pair : range) {
+ if (tag.equals(pair.first)) {
+ rangeNew.add(pair);
+ break;
+ }
+ }
+ }
+ }
+ if (rangeNew.size() > 0) range = rangeNew;
+ }
+ return range.get(0).second;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/KnownBlockRepr.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/KnownBlockRepr.java
new file mode 100644
index 00000000..d3cfd5e0
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/KnownBlockRepr.java
@@ -0,0 +1,1294 @@
+package com.mithrilmania.blocktopograph.block;
+
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
+import com.mithrilmania.blocktopograph.util.NamedBitmapProviderHandle;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by mithrilmania
+ *
+ * ==========================
+ * POCKET EDITION BLOCKS ONLY
+ * ==========================
+ *
+ * uvs are up to date with MCPE 0.14.0
+ *
+ * --- Please attribute @mithrilmania for generating+updating this enum
+ */
+public enum KnownBlockRepr implements NamedBitmapProviderHandle, NamedBitmapProvider {
+ /*
+ * ==============================
+ * Blocks
+ * ==============================
+ */
+
+
+ B_0_0_AIR("minecraft:air", null, 0, 0, null, 0x00000000, false),
+ B_1_0_STONE("minecraft:stone", "stone", 1, 0, "blocks/stone.png", 0xff464646, false),
+ B_1_1_STONE_GRANITE("minecraft:stone", "granite", 1, 1, "blocks/stone_granite.png", 0xff8c7167, false),
+ B_1_2_STONE_GRANITE_SMOOTH("minecraft:stone", "granite_smooth", 1, 2, "blocks/stone_granite_smooth.png", 0xff946251, false),
+ B_1_3_STONE_DIORITE("minecraft:stone", "diorite", 1, 3, "blocks/stone_diorite.png", 0xffc6c6c6, false),
+ B_1_4_STONE_DIORITE_SMOOTH("minecraft:stone", "diorite_smooth", 1, 4, "blocks/stone_diorite_smooth.png", 0xffbebec1, false),
+ B_1_5_STONE_ANDESITE("minecraft:stone", "andesite", 1, 5, "blocks/stone_andesite.png", 0xff797777, false),
+ B_1_6_STONE_ANDESITE_SMOOTH("minecraft:stone", "andesite_smooth", 1, 6, "blocks/stone_andesite_smooth.png", 0xff828382, false),
+ B_2_0_GRASS("minecraft:grass", null, 2, 0, "blocks/grass_side_carried.png", 0xff939393, true),
+ B_3_0_DIRT("minecraft:dirt", null, 3, 0, "blocks/dirt.png", 0xff866043, true),
+ B_4_0_COBBLESTONE("minecraft:cobblestone", null, 4, 0, "blocks/cobblestone.png", 0xff7a7a7a, false),
+ B_5_0_PLANKS_OAK("minecraft:planks", "oak", 5, 0, "blocks/planks_oak.png", 0xff9c7f4e, false),
+ B_5_1_PLANKS_SPRUCE("minecraft:planks", "spruce", 5, 1, "blocks/planks_spruce.png", 0xff5a3d0d, false),
+ B_5_2_PLANKS_BIRCH("minecraft:planks", "birch", 5, 2, "blocks/planks_birch.png", 0xffdabd8d, false),
+ B_5_3_PLANKS_JUNGLE("minecraft:planks", "jungle", 5, 3, "blocks/planks_jungle.png", 0xffBa7d5d, false),
+ B_5_4_PLANKS_ACACIA("minecraft:planks", "acacia", 5, 4, "blocks/planks_acacia.png", 0xff934f39, false),
+ B_5_5_PLANKS_BIG_OAK("minecraft:planks", "big_oak", 5, 5, "blocks/planks_big_oak.png", 0xff3b260f, false),
+ B_6_0_SAPLING_OAK("minecraft:sapling", "oak", 6, 0, "blocks/sapling_oak.png", 0x6b476625, false),
+ B_6_1_SAPLING_SPRUCE("minecraft:sapling", "spruce", 6, 1, "blocks/sapling_spruce.png", 0x53333a21, false),
+ B_6_2_SAPLING_BIRCH("minecraft:sapling", "birch", 6, 2, "blocks/sapling_birch.png", 0x6b769654, false),
+ B_6_3_SAPLING_JUNGLE("minecraft:sapling", "jungle", 6, 3, "blocks/sapling_jungle.png", 0x55305612, false),
+ B_6_4_SAPLING_ACACIA("minecraft:sapling", "acacia", 6, 4, "blocks/sapling_acacia.png", 0xff718919, false),
+ B_6_5_SAPLING_BIG_OAK("minecraft:sapling", "big_oak", 6, 5, "blocks/sapling_roofed_oak.png", 0xff6f522d, false),
+ B_7_0_BEDROCK("minecraft:bedrock", null, 7, 0, "blocks/bedrock.png", 0xff535353, false),
+ B_8_0_FLOWING_WATER("minecraft:flowing_water", null, 8, 0, "blocks/water_flow.png", 0x802e43f4, false),
+ B_9_0_WATER("minecraft:water", null, 9, 0, "blocks/water_still.png", 0x802e43f4, false),
+ B_10_0_FLOWING_LAVA("minecraft:flowing_lava", null, 10, 0, "blocks/lava_flow.png", 0xf0d45a12, false),
+ B_11_0_LAVA("minecraft:lava", null, 11, 0, "blocks/lava_still.png", 0xf0d45a12, false),
+ B_12_0_SAND_DEFAULT("minecraft:sand", "default", 12, 0, "blocks/sand.png", 0xffdbd3a0, false),
+ B_12_1_SAND_RED("minecraft:sand", "red", 12, 1, "blocks/red_sand.png", 0xffa7531f, false),
+ B_13_0_GRAVEL("minecraft:gravel", null, 13, 0, "blocks/gravel.png", 0xff7e7c7a, false),
+ B_14_0_GOLD_ORE("minecraft:gold_ore", null, 14, 0, "blocks/gold_ore.png", 0xff8f8b7c, false),
+ B_15_0_IRON_ORE("minecraft:iron_ore", null, 15, 0, "blocks/iron_ore.png", 0xff87827e, false),
+ B_16_0_COAL_ORE("minecraft:coal_ore", null, 16, 0, "blocks/coal_ore.png", 0xff737373, false),
+ B_17_0_LOG_OAK("minecraft:log", "oak", 17, 0, "blocks/log_oak.png", 0xff9a7d4d, false),
+ B_17_1_LOG_SPRUCE("minecraft:log", "spruce", 17, 1, "blocks/log_spruce.png", 0xff5a3d0d, false),
+ B_17_2_LOG_BIRCH("minecraft:log", "birch", 17, 2, "blocks/log_birch.png", 0xffdabd8d, false),
+ B_17_3_LOG_JUNGLE("minecraft:log", "jungle", 17, 3, "blocks/log_jungle.png", 0xffBa7d5d, false),
+ B_18_0_LEAVES_OAK("minecraft:leaves", "oak", 18, 0, "blocks/leaves_oak.png", 0xff878787, true),
+ B_18_1_LEAVES_SPRUCE("minecraft:leaves", "spruce", 18, 1, "blocks/leaves_spruce.png", 0xff132613, true),
+ B_18_2_LEAVES_BIRCH("minecraft:leaves", "birch", 18, 2, "blocks/leaves_birch.png", 0xff283816, true),
+ B_18_3_LEAVES_JUNGLE("minecraft:leaves", "jungle", 18, 3, "blocks/leaves_jungle.png", 0xff918e86, true),
+ B_19_0_SPONGE_DRY("minecraft:sponge", "dry", 19, 0, "blocks/sponge_dry.png", 0xffb6b639, false),
+ B_19_1_SPONGE_WET("minecraft:sponge", "wet", 19, 1, "blocks/sponge_wet.png", 0xff9b9a33, false),
+ B_20_0_GLASS("minecraft:glass", null, 20, 0, "blocks/glass.png", 0x46daf0f4, false),
+ B_21_0_LAPIS_ORE("minecraft:lapis_ore", null, 21, 0, "blocks/lapis_ore.png", 0xff667086, false),
+ B_22_0_LAPIS_BLOCK("minecraft:lapis_block", null, 22, 0, "blocks/lapis_block.png", 0xff1d47a5, false),
+ B_23_0_DISPENSER("minecraft:dispenser", null, 23, 0, "blocks/dispenser.png", 0xff606060, false),
+ B_24_0_SANDSTONE_DEFAULT("minecraft:sandstone", "default", 24, 0, "blocks/sandstone_default.png", 0xffdad29e, false),
+ B_24_1_SANDSTONE_CHISELED("minecraft:sandstone", "chiseled", 24, 1, "blocks/sandstone_chiseled.png", 0xffdad1a2, false),
+ B_24_2_SANDSTONE_SMOOTH("minecraft:sandstone", "smooth", 24, 2, "blocks/sandstone_smooth.png", 0xffdad1a2, false),
+ B_25_0_NOTEBLOCK("minecraft:noteblock", null, 25, 0, "blocks/noteblock.png", 0xff644332, false),
+ B_26_0_BED("minecraft:bed", null, 26, 0, "blocks/bed.png", 0xff8e1616, false),
+ B_27_0_GOLDEN_RAIL("minecraft:golden_rail", null, 27, 0, "blocks/golden_rail.png", 0xab9a6846, false),
+ B_28_0_DETECTOR_RAIL("minecraft:detector_rail", null, 28, 0, "blocks/detector_rail.png", 0x9b786559, false),
+ B_29_0_STICKY_PISTON("minecraft:sticky_piston", null, 29, 0, "blocks/sticky_piston.png", 0xff8d9263, false),
+ B_30_0_WEB("minecraft:web", null, 30, 0, "blocks/web.png", 0x68dcdcdc, false),
+ B_31_1_TALLGRASS_FERN("minecraft:tallgrass", "fern", 31, 1, "blocks/tallgrass_fern.png", 0xff747474, true),
+ B_31_2_TALLGRASS_GRASS("minecraft:tallgrass", "grass", 31, 2, "blocks/tallgrass_grass.png", 0x4e787878, true),
+ B_32_0_DEADBUSH("minecraft:deadbush", null, 32, 0, "blocks/deadbush.png", 0x517b4f19, false),
+ B_33_0_PISTON("minecraft:piston", null, 33, 0, "blocks/piston.png", 0xff998159, false),
+ B_34_0_PISTONARMCOLLISION("minecraft:pistonArmCollision", null, 34, 0, "blocks/pistonArmCollision.png", 0xff9c7f4e, false),
+ B_35_0_WOOL_WHITE("minecraft:wool", "white", 35, 0, "blocks/wool_colored_white.png", 0xffdddddd, false),
+ B_35_1_WOOL_ORANGE("minecraft:wool", "orange", 35, 1, "blocks/wool_colored_orange.png", 0xffdb7d3e, false),
+ B_35_2_WOOL_MAGENTA("minecraft:wool", "magenta", 35, 2, "blocks/wool_colored_magenta.png", 0xffb350bc, false),
+ B_35_3_WOOL_LIGHT_BLUE("minecraft:wool", "light_blue", 35, 3, "blocks/wool_colored_light_blue.png", 0xff6a8ac9, false),
+ B_35_4_WOOL_YELLOW("minecraft:wool", "yellow", 35, 4, "blocks/wool_colored_yellow.png", 0xffb1a627, false),
+ B_35_5_WOOL_LIME("minecraft:wool", "lime", 35, 5, "blocks/wool_colored_lime.png", 0xff41ae38, false),
+ B_35_6_WOOL_PINK("minecraft:wool", "pink", 35, 6, "blocks/wool_colored_pink.png", 0xffd08499, false),
+ B_35_7_WOOL_GRAY("minecraft:wool", "gray", 35, 7, "blocks/wool_colored_gray.png", 0xff404040, false),
+ B_35_8_WOOL_SILVER("minecraft:wool", "silver", 35, 8, "blocks/wool_colored_silver.png", 0xff9aa1a1, false),
+ B_35_9_WOOL_CYAN("minecraft:wool", "cyan", 35, 9, "blocks/wool_colored_cyan.png", 0xff2e6e89, false),
+ B_35_10_WOOL_PURPLE("minecraft:wool", "purple", 35, 10, "blocks/wool_colored_purple.png", 0xff7e3db5, false),
+ B_35_11_WOOL_BLUE("minecraft:wool", "blue", 35, 11, "blocks/wool_colored_blue.png", 0xff2e388d, false),
+ B_35_12_WOOL_BROWN("minecraft:wool", "brown", 35, 12, "blocks/wool_colored_brown.png", 0xff4f321f, false),
+ B_35_13_WOOL_GREEN("minecraft:wool", "green", 35, 13, "blocks/wool_colored_green.png", 0xff35461b, false),
+ B_35_14_WOOL_RED("minecraft:wool", "red", 35, 14, "blocks/wool_colored_red.png", 0xff963430, false),
+ B_35_15_WOOL_BLACK("minecraft:wool", "black", 35, 15, "blocks/wool_colored_black.png", 0xff191616, false),
+ B_36_0_ELEMENT0("minecraft:element_0", "unknown", 36, 0, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_1_ELEMENT0("minecraft:element_0", "unknown", 36, 1, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_2_ELEMENT0("minecraft:element_0", "unknown", 36, 2, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_3_ELEMENT0("minecraft:element_0", "unknown", 36, 3, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_4_ELEMENT0("minecraft:element_0", "unknown", 36, 4, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_5_ELEMENT0("minecraft:element_0", "unknown", 36, 5, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_6_ELEMENT0("minecraft:element_0", "unknown", 36, 6, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_7_ELEMENT0("minecraft:element_0", "unknown", 36, 7, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_8_ELEMENT0("minecraft:element_0", "unknown", 36, 8, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_9_ELEMENT0("minecraft:element_0", "unknown", 36, 9, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_10_ELEMENT0("minecraft:element_0", "unknown", 36, 10, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_11_ELEMENT0("minecraft:element_0", "unknown", 36, 11, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_12_ELEMENT0("minecraft:element_0", "unknown", 36, 12, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_13_ELEMENT0("minecraft:element_0", "unknown", 36, 13, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_14_ELEMENT0("minecraft:element_0", "unknown", 36, 14, "blocks/coal_ore.png", 0xff191616, false),
+ B_36_15_ELEMENT0("minecraft:element_0", "unknown", 36, 15, "blocks/coal_ore.png", 0xff191616, false),
+ B_37_0_YELLOW_FLOWER("minecraft:yellow_flower", null, 37, 0, "blocks/yellow_flower.png", 0x1e6ca200, false),
+ B_38_0_RED_FLOWER_POPPY("minecraft:red_flower", "poppy", 38, 0, "blocks/flower_poppy.png", 0x1d8a2b0d, false),
+ B_38_1_RED_FLOWER_BLUE_ORCHID("minecraft:red_flower", "blue_orchid", 38, 1, "blocks/flower_blue_orchid.png", 0x1d188fd3, false),
+ B_38_2_RED_FLOWER_ALLIUM("minecraft:red_flower", "allium", 38, 2, "blocks/flower_allium.png", 0x1ddbb7f8, false),
+ B_38_3_RED_FLOWER_HOUSTONIA("minecraft:red_flower", "houstonia", 38, 3, "blocks/flower_houstonia.png", 0x1defef99, false),
+ B_38_4_RED_FLOWER_TULIP_RED("minecraft:red_flower", "tulip_red", 38, 4, "blocks/flower_tulip_red.png", 0x1dbd2604, false),
+ B_38_5_RED_FLOWER_TULIP_ORANGE("minecraft:red_flower", "tulip_orange", 38, 5, "blocks/flower_tulip_orange.png", 0x1dd06713, false),
+ B_38_6_RED_FLOWER_TULIP_WHITE("minecraft:red_flower", "tulip_white", 38, 6, "blocks/flower_tulip_white.png", 0x1df9f9f9, false),
+ B_38_7_RED_FLOWER_TULIP_PINK("minecraft:red_flower", "tulip_pink", 38, 7, "blocks/flower_tulip_pink.png", 0x1dbeb3be, false),
+ B_38_8_RED_FLOWER_OXEYE_DAISY("minecraft:red_flower", "oxeye_daisy", 38, 8, "blocks/flower_oxeye_daisy.png", 0x1ddadada, false),
+ B_39_0_BROWN_MUSHROOM("minecraft:brown_mushroom", null, 39, 0, "blocks/brown_mushroom.png", 0x198a6953, false),
+ B_40_0_RED_MUSHROOM("minecraft:red_mushroom", null, 40, 0, "blocks/red_mushroom.png", 0x21c33538, false),
+ B_41_0_GOLD_BLOCK("minecraft:gold_block", null, 41, 0, "blocks/gold_block.png", 0xfff9ec4e, false),
+ B_42_0_IRON_BLOCK("minecraft:iron_block", null, 42, 0, "blocks/iron_block.png", 0xffdbdbdb, false),
+ B_43_0_DOUBLE_STONE_SLAB_STONE("minecraft:double_stone_slab", "stone", 43, 0, "blocks/double_stone_slab_stone.png", 0xff9f9f9f, false),
+ B_43_1_DOUBLE_STONE_SLAB_SAND("minecraft:double_stone_slab", "sand", 43, 1, "blocks/double_stone_slab_sand.png", 0xffdad29e, false),
+ B_43_2_DOUBLE_STONE_SLAB_WOOD("minecraft:double_stone_slab", "wood", 43, 2, "blocks/double_stone_slab_wood.png", 0xff9c7f4e, false),
+ B_43_3_DOUBLE_STONE_SLAB_COBBLE("minecraft:double_stone_slab", "cobble", 43, 3, "blocks/double_stone_slab_cobble.png", 0xff7a7a7a, false),
+ B_43_4_DOUBLE_STONE_SLAB_BRICK("minecraft:double_stone_slab", "brick", 43, 4, "blocks/double_stone_slab_brick.png", 0xff926356, false),
+ B_43_5_DOUBLE_STONE_SLAB_SMOOTH_STONE_BRICK("minecraft:double_stone_slab", "smooth_stone_brick", 43, 5, "blocks/double_stone_slab_smooth_stone_brick.png", 0xff7d7d7d, false),
+ B_43_6_DOUBLE_STONE_SLAB_QUARTZ("minecraft:double_stone_slab", "quartz", 43, 6, "blocks/double_stone_slab_quartz.png", 0xff2c161a, false),
+ B_43_7_DOUBLE_STONE_SLAB_NETHER_BRICK("minecraft:double_stone_slab", "nether_brick", 43, 7, "blocks/double_stone_slab_nether_brick.png", 0xffece9e2, false),
+ B_43_8_DOUBLE_STONE_SLAB_RED_SANDSTONE("minecraft:double_stone_slab", "red_sandstone", 43, 8, "blocks/double_stone_slab_red_sandstone.png", 0xff9f9f9f, false),
+ B_44_0_STONE_SLAB_STONE("minecraft:stone_slab", "stone", 44, 0, "blocks/stone_slab_side.png", 0xff9f9f9f, false),
+ B_44_1_STONE_SLAB_SAND("minecraft:stone_slab", "sand", 44, 1, "blocks/stone_slab_side.png", 0xffdad29e, false),
+ B_44_2_STONE_SLAB_WOOD("minecraft:stone_slab", "wood", 44, 2, "blocks/stone_slab_side.png", 0xff9c7f4e, false),
+ B_44_3_STONE_SLAB_COBBLE("minecraft:stone_slab", "cobble", 44, 3, "blocks/stone_slab_side.png", 0xff7a7a7a, false),
+ B_44_4_STONE_SLAB_BRICK("minecraft:stone_slab", "brick", 44, 4, "blocks/stone_slab_side.png", 0xff926356, false),
+ B_44_5_STONE_SLAB_SMOOTH_STONE_BRICK("minecraft:stone_slab", "smooth_stone_brick", 44, 5, "blocks/stone_slab_side.png", 0xff7d7d7d, false),
+ B_44_6_STONE_SLAB_QUARTZ("minecraft:stone_slab", "quartz", 44, 6, "blocks/stone_slab_side.png", 0xff2c161a, false),
+ B_44_7_STONE_SLAB_NETHER_BRICK("minecraft:stone_slab", "nether_brick", 44, 7, "blocks/stone_slab_side.png", 0xffece9e2, false),
+ B_45_0_BRICK_BLOCK("minecraft:brick_block", null, 45, 0, "blocks/brick_block.png", 0xff926356, false),
+ B_46_0_TNT("minecraft:tnt", null, 46, 0, "blocks/tnt.png", 0xff82412f, false),
+ B_47_0_BOOKSHELF("minecraft:bookshelf", null, 47, 0, "blocks/bookshelf.png", 0xff6b5839, false),
+ B_48_0_MOSSY_COBBLESTONE("minecraft:mossy_cobblestone", null, 48, 0, "blocks/mossy_cobblestone.png", 0xff677967, false),
+ B_49_0_OBSIDIAN("minecraft:obsidian", null, 49, 0, "blocks/obsidian.png", 0xff14121d, false),
+ B_50_0_TORCH("minecraft:torch", null, 50, 0, "blocks/torch.png", 0x13826a3a, false),
+ B_51_0_FIRE("minecraft:fire", null, 51, 0, "blocks/fire.png", 0x8bd38c35, false),
+ B_52_0_MOB_SPAWNER("minecraft:mob_spawner", null, 52, 0, "blocks/mob_spawner.png", 0x9b1a2731, false),
+ B_53_0_OAK_STAIRS("minecraft:oak_stairs", null, 53, 0, "blocks/oak_stairs.png", 0xff9c7f4e, false),
+ B_54_0_CHEST("minecraft:chest", null, 54, 0, "blocks/chest_front.png", 0xc86f5739, false),
+ B_55_0_REDSTONE_WIRE("minecraft:redstone_wire", null, 55, 0, "blocks/redstone_wire.png", 0x80fa1010, false),
+ B_56_0_DIAMOND_ORE("minecraft:diamond_ore", null, 56, 0, "blocks/diamond_ore.png", 0xff818c8f, false),
+ B_57_0_DIAMOND_BLOCK("minecraft:diamond_block", null, 57, 0, "blocks/diamond_block.png", 0xff61dbd5, false),
+ B_58_0_CRAFTING_TABLE("minecraft:crafting_table", null, 58, 0, "blocks/crafting_table.png", 0xff6b472a, false),
+ B_59_0_WHEAT("minecraft:wheat", null, 59, 0, "blocks/wheat.png", 0x0500b312, false),
+ B_60_0_FARMLAND("minecraft:farmland", null, 60, 0, "blocks/farmland.png", 0xff734b2d, false),
+ B_61_0_FURNACE("minecraft:furnace", null, 61, 0, "blocks/furnace.png", 0xff606060, false),
+ B_62_0_LIT_FURNACE("minecraft:lit_furnace", null, 62, 0, "blocks/lit_furnace.png", 0xff606060, false),
+ B_63_0_STANDING_SIGN("minecraft:standing_sign", null, 63, 0, "blocks/standing_sign.png", 0x566f5739, false),
+ B_64_0_WOODEN_DOOR("minecraft:wooden_door", null, 64, 0, "blocks/wooden_door.png", 0xcf866733, false),
+ B_65_0_LADDER("minecraft:ladder", null, 65, 0, "blocks/ladder.png", 0x8f795f34, false),
+ B_66_0_RAIL("minecraft:rail", null, 66, 0, "blocks/rail.png", 0x8f796c58, false),
+ B_67_0_STONE_STAIRS("minecraft:stone_stairs", null, 67, 0, "blocks/stone_stairs.png", 0xff7a7a7a, false),
+ B_68_0_WALL_SIGN("minecraft:wall_sign", null, 68, 0, "blocks/wall_sign.png", 0x206f5739, false),
+ B_69_0_LEVER("minecraft:lever", null, 69, 0, "blocks/lever.png", 0x136a5940, false),
+ B_70_0_STONE_PRESSURE_PLATE("minecraft:stone_pressure_plate", null, 70, 0, "blocks/stone_pressure_plate.png", 0xff7d7d7d, false),
+ B_71_0_IRON_DOOR("minecraft:iron_door", null, 71, 0, "blocks/iron_door.png", 0xcfbababa, false),
+ B_72_0_WOODEN_PRESSURE_PLATE("minecraft:wooden_pressure_plate", null, 72, 0, "blocks/wooden_pressure_plate.png", 0xff9c7f4e, false),
+ B_73_0_REDSTONE_ORE("minecraft:redstone_ore", null, 73, 0, "blocks/redstone_ore.png", 0xff846b6b, false),
+ B_74_0_LIT_REDSTONE_ORE("minecraft:lit_redstone_ore", null, 74, 0, "blocks/lit_redstone_ore.png", 0xff846b6b, false),
+ B_75_0_UNLIT_REDSTONE_TORCH("minecraft:unlit_redstone_torch", null, 75, 0, "blocks/unlit_redstone_torch.png", 0x465d3e26, false),
+ B_76_0_REDSTONE_TORCH("minecraft:redstone_torch", null, 76, 0, "blocks/redstone_torch.png", 0x46a74b29, false),
+ B_77_0_STONE_BUTTON("minecraft:stone_button", null, 77, 0, "blocks/stone_button.png", 0x28565656, false),
+ B_78_0_SNOW_LAYER("minecraft:snow_layer", null, 78, 0, "blocks/snow_layer.png", 0xffeffbfb, false),
+ B_79_0_ICE("minecraft:ice", null, 79, 0, "blocks/ice.png", 0x9f7dadff, false),
+ B_80_0_SNOW("minecraft:snow", null, 80, 0, "blocks/snow.png", 0xffeffbfb, false),
+ B_81_0_CACTUS("minecraft:cactus", null, 81, 0, "blocks/cactus.png", 0xc30d6318, false),
+ B_82_0_CLAY("minecraft:clay", null, 82, 0, "blocks/clay.png", 0xff9ea4b0, false),
+ B_83_0_REEDS("minecraft:reeds", null, 83, 0, "blocks/reeds.png", 0x8c94c065, false),
+
+ B_84_0_JUKEBOX("minecraft:jukebox", null, 84, 0, "blocks/fence_birch_fence.png", 0x8f463822, false),
+
+ B_85_0_FENCE_FENCE("minecraft:fence", "fence", 85, 0, "blocks/fence_fence.png", 0x8f463822, false),
+ B_85_1_FENCE_SPRUCE_FENCE("minecraft:fence", "spruce_fence", 85, 1, "blocks/fence_spruce_fence.png", 0x8f5a3d0d, false),
+ B_85_2_FENCE_BIRCH_FENCE("minecraft:fence", "birch_fence", 85, 2, "blocks/fence_birch_fence.png", 0x8fdabd8d, false),
+ B_85_3_FENCE_JUNGLE_FENCE("minecraft:fence", "jungle_fence", 85, 3, "blocks/fence_jungle_fence.png", 0x8fBa7d5d, false),
+ B_85_4_FENCE_ACACIA_FENCE("minecraft:fence", "acacia_fence", 85, 4, "blocks/fence_acacia_fence.png", 0x8f934f39, false),
+ B_85_5_FENCE_DARK_OAK_FENCE("minecraft:fence", "dark_oak_fence", 85, 5, "blocks/fence_dark_oak_fence.png", 0x8f2d2213, false),
+ B_86_0_PUMPKIN("minecraft:pumpkin", null, 86, 0, "blocks/pumpkin.png", 0xffc07615, false),
+ B_87_0_NETHERRACK("minecraft:netherrack", null, 87, 0, "blocks/netherrack.png", 0xff6f3634, false),
+ B_88_0_SOUL_SAND("minecraft:soul_sand", null, 88, 0, "blocks/soul_sand.png", 0xff544033, false),
+ B_89_0_GLOWSTONE("minecraft:glowstone", null, 89, 0, "blocks/glowstone.png", 0xff8f7645, false),
+ B_90_0_PORTAL("minecraft:portal", null, 90, 0, "blocks/portal.png", 0xc8410491, false),
+ B_91_0_LIT_PUMPKIN("minecraft:lit_pumpkin", null, 91, 0, "blocks/lit_pumpkin.png", 0xffc07615, false),
+ B_92_0_CAKE("minecraft:cake", null, 92, 0, "blocks/cake.png", 0xc3e4cdce, false),
+ B_93_0_UNPOWERED_REPEATER("minecraft:unpowered_repeater", null, 93, 0, "blocks/unpowered_repeater.png", 0xff979393, false),
+ B_94_0_POWERED_REPEATER("minecraft:powered_repeater", null, 94, 0, "blocks/powered_repeater.png", 0xffa09393, false),
+ B_95_0_INVISIBLEBEDROCK("minecraft:invisibleBedrock", null, 95, 0, "blocks/invisibleBedrock.png", 0x3c282828, false),
+ B_96_0_TRAPDOOR("minecraft:trapdoor", null, 96, 0, "blocks/trapdoor.png", 0xdb7e5d2d, false),
+ B_97_0_MONSTER_EGG_STONE("minecraft:monster_egg", "stone", 97, 0, "blocks/monster_egg_stone.png", 0xff7d7d7d, false),
+ B_97_1_MONSTER_EGG_COBBLE("minecraft:monster_egg", "cobble", 97, 1, "blocks/monster_egg_cobble.png", 0xff7a7a7a, false),
+ B_97_2_MONSTER_EGG_BRICK("minecraft:monster_egg", "brick", 97, 2, "blocks/monster_egg_brick.png", 0xff7a7a7a, false),
+ B_97_3_MONSTER_EGG_MOSSYBRICK("minecraft:monster_egg", "mossybrick", 97, 3, "blocks/monster_egg_mossybrick.png", 0xff7b6651, false),
+ B_97_4_MONSTER_EGG_CRACKEDBRICK("minecraft:monster_egg", "crackedbrick", 97, 4, "blocks/monster_egg_crackedbrick.png", 0xff7b6651, false),
+ B_97_5_MONSTER_EGG_CHISELEDBRICK("minecraft:monster_egg", "chiseledbrick", 97, 5, "blocks/monster_egg_chiseledbrick.png", 0xff7b6651, false),
+ B_98_0_STONEBRICK_DEFAULT("minecraft:stonebrick", "default", 98, 0, "blocks/stonebrick_default.png", 0xff7a7a7a, false),
+ B_98_1_STONEBRICK_MOSSY("minecraft:stonebrick", "mossy", 98, 1, "blocks/stonebrick_mossy.png", 0xff72776a, false),
+ B_98_2_STONEBRICK_CRACKED("minecraft:stonebrick", "cracked", 98, 2, "blocks/stonebrick_cracked.png", 0xff767676, false),
+ B_98_3_STONEBRICK_CHISELED("minecraft:stonebrick", "chiseled", 98, 3, "blocks/stonebrick_chiseled.png", 0xff767676, false),
+ B_98_4_STONEBRICK_SMOOTH("minecraft:stonebrick", "smooth", 98, 4, "blocks/stonebrick_smooth.png", 0xff767676, false),
+ B_99_0_BROWN_MUSHROOM_BLOCK("minecraft:brown_mushroom_block", null, 99, 0, "blocks/brown_mushroom_block.png", 0xff8d6a53, false),
+ B_100_0_RED_MUSHROOM_BLOCK("minecraft:red_mushroom_block", null, 100, 0, "blocks/red_mushroom_block.png", 0xffb62524, false),
+ B_101_0_IRON_BARS("minecraft:iron_bars", null, 101, 0, "blocks/iron_bars.png", 0x736d6c6a, false),
+ B_102_0_GLASS_PANE("minecraft:glass_pane", null, 102, 0, "blocks/glass_pane.png", 0x1fd3eff4, false),
+ B_103_0_MELON_BLOCK("minecraft:melon_block", null, 103, 0, "blocks/melon_block.png", 0xff979924, false),
+ B_104_0_PUMPKIN_STEM("minecraft:pumpkin_stem", null, 104, 0, "blocks/pumpkin_stem.png", 0x1e87b759, false),
+ B_105_0_MELON_STEM("minecraft:melon_stem", null, 105, 0, "blocks/melon_stem.png", 0x1e87b759, false),
+ B_106_0_VINE("minecraft:vine", null, 106, 0, "blocks/vine.png", 0x8a6f6f6f, false),
+ B_107_0_FENCE_GATE("minecraft:fence_gate", null, 107, 0, "blocks/fence_gate.png", 0x7b463822, false),
+ B_108_0_BRICK_STAIRS("minecraft:brick_stairs", null, 108, 0, "blocks/brick_stairs.png", 0xff926356, false),
+ B_109_0_STONE_BRICK_STAIRS("minecraft:stone_brick_stairs", null, 109, 0, "blocks/stone_brick_stairs.png", 0xff7a7a7a, false),
+ B_110_0_MYCELIUM("minecraft:mycelium", null, 110, 0, "blocks/mycelium.png", 0xff6f6369, false),
+ B_111_0_WATERLILY("minecraft:waterlily", null, 111, 0, "blocks/waterlily.png", 0x93335a21, false),
+ B_112_0_NETHER_BRICK("minecraft:nether_brick", null, 112, 0, "blocks/nether_brick.png", 0xff2c161a, false),
+ B_113_0_NETHER_BRICK_FENCE("minecraft:nether_brick_fence", null, 113, 0, "blocks/nether_brick_fence.png", 0xff2c161a, false),
+ B_114_0_NETHER_BRICK_STAIRS("minecraft:nether_brick_stairs", null, 114, 0, "blocks/nether_brick_stairs.png", 0xff2c161a, false),
+ B_115_0_NETHER_WART("minecraft:nether_wart", null, 115, 0, "blocks/nether_wart.png", 0x2a6a0e1e, false),
+ B_116_0_ENCHANTING_TABLE("minecraft:enchanting_table", null, 116, 0, "blocks/enchanting_table.png", 0xff67403b, false),
+ B_117_0_BREWING_STAND("minecraft:brewing_stand", null, 117, 0, "blocks/brewing_stand.png", 0x767c6751, false),
+ B_118_0_CAULDRON("minecraft:cauldron", null, 118, 0, "blocks/cauldron.png", 0xff373737, false),
+ B_119_0_END_PORTAL("minecraft:end_portal", null, 119, 0, "blocks/endframe_top.png", 0xff101010, false),
+ B_120_0_END_PORTAL_FRAME("minecraft:end_portal_frame", null, 120, 0, "blocks/endframe_side.png", 0xff597560, false),
+ B_121_0_END_STONE("minecraft:end_stone", null, 121, 0, "blocks/end_stone.png", 0xffdddfa5, false),
+ B_122_0_DRAGON_EGG("minecraft:dragon_egg", null, 122, 0, "blocks/dragon_egg.png", 0xff0c090f, false),
+ B_123_0_REDSTONE_LAMP("minecraft:redstone_lamp", null, 123, 0, "blocks/redstone_lamp.png", 0xff462b1a, false),
+ B_124_0_LIT_REDSTONE_LAMP("minecraft:lit_redstone_lamp", null, 124, 0, "blocks/lit_redstone_lamp.png", 0xff775937, false),
+ B_125_0_DROPPER("minecraft:dropper", null, 125, 0, "blocks/dropper.png", 0xff9c7f4e, false),
+ B_126_0_ACTIVATOR_RAIL("minecraft:activator_rail", null, 126, 0, "blocks/activator_rail.png", 0xff9c7f4e, false),
+ B_127_0_COCOA("minecraft:cocoa", null, 127, 0, "blocks/cocoa.png", 0x2e8a8c40, false),
+ B_128_0_SANDSTONE_STAIRS("minecraft:sandstone_stairs", null, 128, 0, "blocks/sandstone_stairs.png", 0xffdad29e, false),
+ B_129_0_EMERALD_ORE("minecraft:emerald_ore", null, 129, 0, "blocks/emerald_ore.png", 0xff6d8074, false),
+ B_130_0_ENDER_CHEST("minecraft:ender_chest", null, 130, 0, "blocks/ender_chest_front.png", 0xc82c3e40, false),
+ B_131_0_TRIPWIRE_HOOK("minecraft:tripwire_hook", null, 131, 0, "blocks/tripwire_hook.png", 0x2d8a8171, false),
+ B_132_0_TRIPWIRE("minecraft:tripWire", null, 132, 0, "blocks/tripWire.png", 0x2d818181, false),
+ B_133_0_EMERALD_BLOCK("minecraft:emerald_block", null, 133, 0, "blocks/emerald_block.png", 0xff51d975, false),
+ B_134_0_SPRUCE_STAIRS("minecraft:spruce_stairs", null, 134, 0, "blocks/spruce_stairs.png", 0xff5a3d0d, false),
+ B_135_0_BIRCH_STAIRS("minecraft:birch_stairs", null, 135, 0, "blocks/birch_stairs.png", 0xffdabd8d, false),
+ B_136_0_JUNGLE_STAIRS("minecraft:jungle_stairs", null, 136, 0, "blocks/jungle_stairs.png", 0xffBa7d5d, false),
+ B_138_0_BEACON("minecraft:beacon", null, 138, 0, "blocks/beacon.png", 0xff74ddd7, false),
+ B_139_0_COBBLESTONE_WALL_NORMAL("minecraft:cobblestone_wall", "normal", 139, 0, "blocks/cobblestone_wall_normal.png", 0xff7a7a7a, false),
+ B_139_1_COBBLESTONE_WALL_MOSSY("minecraft:cobblestone_wall", "mossy", 139, 1, "blocks/cobblestone_wall_mossy.png", 0xff506a50, false),
+ B_140_0_FLOWER_POT("minecraft:flower_pot", null, 140, 0, "blocks/flower_pot.png", 0x31764133, false),
+ B_141_0_CARROTS("minecraft:carrots", null, 141, 0, "blocks/carrots.png", 0x0901ab10, false),
+ B_142_0_POTATOES("minecraft:potatoes", null, 142, 0, "blocks/potatoes.png", 0x0901ab10, false),
+ B_143_0_WOODEN_BUTTON("minecraft:wooden_button", null, 143, 0, "blocks/wooden_button.png", 0x2878613e, false),
+ B_144_0_SKULL("minecraft:skull", null, 144, 0, "blocks/skull.png", 0x8c8c8c8c, false),
+ B_145_0_ANVIL_INTACT("minecraft:anvil", "intact", 145, 0, "blocks/anvil_intact.png", 0x9f403c3c, false),
+ B_145_4_ANVIL_SLIGHTLY_DAMAGED("minecraft:anvil", "slightly_damaged", 145, 4, "blocks/anvil_slightly_damaged.png", 0x9f403c3c, false),
+ B_145_8_ANVIL_VERY_DAMAGED("minecraft:anvil", "very_damaged", 145, 8, "blocks/anvil_very_damaged.png", 0x9f403c3c, false),
+ B_146_0_TRAPPED_CHEST("minecraft:trapped_chest", null, 146, 0, "blocks/chest_front.png", 0xfe6f5739, false),
+ B_147_0_LIGHT_WEIGHTED_PRESSURE_PLATE("minecraft:light_weighted_pressure_plate", null, 147, 0, "blocks/light_weighted_pressure_plate.png", 0xc8f9ec4e, false),
+ B_148_0_HEAVY_WEIGHTED_PRESSURE_PLATE("minecraft:heavy_weighted_pressure_plate", null, 148, 0, "blocks/heavy_weighted_pressure_plate.png", 0xc8dbdbdb, false),
+ B_149_0_UNPOWERED_COMPARATOR("minecraft:unpowered_comparator", null, 149, 0, "blocks/unpowered_comparator.png", 0xff9c9695, false),
+ B_150_0_POWERED_COMPARATOR("minecraft:powered_comparator", null, 150, 0, "blocks/powered_comparator.png", 0xffa59594, false),
+ B_151_0_DAYLIGHT_DETECTOR("minecraft:daylight_detector", null, 151, 0, "blocks/daylight_detector.png", 0xff82745e, false),
+ B_152_0_REDSTONE_BLOCK("minecraft:redstone_block", null, 152, 0, "blocks/redstone_block.png", 0xffab1b09, false),
+ B_153_0_QUARTZ_ORE("minecraft:quartz_ore", null, 153, 0, "blocks/quartz_ore.png", 0xffd9d1c8, false),
+ B_154_0_HOPPER("minecraft:hopper", null, 154, 0, "blocks/hopper.png", 0xff3e3e3e, false),
+ B_155_0_QUARTZ_BLOCK_DEFAULT("minecraft:quartz_block", "default", 155, 0, "blocks/quartz_block_default.png", 0xffece9e2, false),
+ B_155_1_QUARTZ_BLOCK_CHISELED("minecraft:quartz_block", "chiseled", 155, 1, "blocks/quartz_block_chiseled.png", 0xffe7e4db, false),
+ B_155_2_QUARTZ_BLOCK_LINES("minecraft:quartz_block", "lines", 155, 2, "blocks/quartz_block_lines.png", 0xffe8e5dd, false),
+ B_155_3_QUARTZ_BLOCK_DEFAULT("minecraft:quartz_block", "default", 155, 3, "blocks/quartz_block_default.png", 0xffe7e3db, false),
+ B_156_0_QUARTZ_STAIRS("minecraft:quartz_stairs", null, 156, 0, "blocks/quartz_stairs.png", 0xffece9e2, false),
+ B_157_0_DOUBLE_WOODEN_SLAB_OAK("minecraft:double_wooden_slab", "oak", 157, 0, "blocks/planks_oak.png", 0xb4907449, false),
+ B_157_1_DOUBLE_WOODEN_SLAB_SPRUCE("minecraft:double_wooden_slab", "spruce", 157, 1, "blocks/planks_spruce.png", 0xff5a3d0d, false),
+ B_157_2_DOUBLE_WOODEN_SLAB_BIRCH("minecraft:double_wooden_slab", "birch", 157, 2, "blocks/planks_birch.png", 0xb4dabd8d, false),
+ B_157_3_DOUBLE_WOODEN_SLAB_JUNGLE("minecraft:double_wooden_slab", "jungle", 157, 3, "blocks/planks_jungle.png", 0xb4Ba7d5d, false),
+ B_157_4_DOUBLE_WOODEN_SLAB_ACACIA("minecraft:double_wooden_slab", "acacia", 157, 4, "blocks/planks_acacia.png", 0xb4934f39, false),
+ B_157_5_DOUBLE_WOODEN_SLAB_BIG_OAK("minecraft:double_wooden_slab", "big_oak", 157, 5, "blocks/planks_big_oak.png", 0xb4907449, false),
+ B_158_0_WOODEN_SLAB_OAK("minecraft:wooden_slab", "oak", 158, 0, "blocks/wooden_slab_oak.png", 0xff907449, false),
+ B_158_1_WOODEN_SLAB_SPRUCE("minecraft:wooden_slab", "spruce", 158, 1, "blocks/wooden_slab_spruce.png", 0xff5a3d0d, false),
+ B_158_2_WOODEN_SLAB_BIRCH("minecraft:wooden_slab", "birch", 158, 2, "blocks/wooden_slab_birch.png", 0xffdabd8d, false),
+ B_158_3_WOODEN_SLAB_JUNGLE("minecraft:wooden_slab", "jungle", 158, 3, "blocks/wooden_slab_jungle.png", 0xffBa7d5d, false),
+ B_158_4_WOODEN_SLAB_ACACIA("minecraft:wooden_slab", "acacia", 158, 4, "blocks/wooden_slab_acacia.png", 0xff934f39, false),
+ B_158_5_WOODEN_SLAB_BIG_OAK("minecraft:wooden_slab", "big_oak", 158, 5, "blocks/wooden_slab_big_oak.png", 0xff907449, false),
+ B_159_0_STAINED_HARDENED_CLAY_WHITE("minecraft:stained_hardened_clay", "white", 159, 0, "blocks/hardened_clay_stained_white.png", 0xff836f64, false),
+ B_159_1_STAINED_HARDENED_CLAY_ORANGE("minecraft:stained_hardened_clay", "orange", 159, 1, "blocks/hardened_clay_stained_orange.png", 0xff9d5021, false),
+ B_159_2_STAINED_HARDENED_CLAY_MAGENTA("minecraft:stained_hardened_clay", "magenta", 159, 2, "blocks/hardened_clay_stained_magenta.png", 0xff915369, false),
+ B_159_3_STAINED_HARDENED_CLAY_LIGHT_BLUE("minecraft:stained_hardened_clay", "light_blue", 159, 3, "blocks/hardened_clay_stained_light_blue.png", 0xff706b87, false),
+ B_159_4_STAINED_HARDENED_CLAY_YELLOW("minecraft:stained_hardened_clay", "yellow", 159, 4, "blocks/hardened_clay_stained_yellow.png", 0xffb5801f, false),
+ B_159_5_STAINED_HARDENED_CLAY_LIME("minecraft:stained_hardened_clay", "lime", 159, 5, "blocks/hardened_clay_stained_lime.png", 0xff617030, false),
+ B_159_6_STAINED_HARDENED_CLAY_PINK("minecraft:stained_hardened_clay", "pink", 159, 6, "blocks/hardened_clay_stained_pink.png", 0xff9c4848, false),
+ B_159_7_STAINED_HARDENED_CLAY_GRAY("minecraft:stained_hardened_clay", "gray", 159, 7, "blocks/hardened_clay_stained_gray.png", 0xff392721, false),
+ B_159_8_STAINED_HARDENED_CLAY_SILVER("minecraft:stained_hardened_clay", "silver", 159, 8, "blocks/hardened_clay_stained_silver.png", 0xff81655b, false),
+ B_159_9_STAINED_HARDENED_CLAY_CYAN("minecraft:stained_hardened_clay", "cyan", 159, 9, "blocks/hardened_clay_stained_cyan.png", 0xff565959, false),
+ B_159_10_STAINED_HARDENED_CLAY_PURPLE("minecraft:stained_hardened_clay", "purple", 159, 10, "blocks/hardened_clay_stained_purple.png", 0xff744555, false),
+ B_159_11_STAINED_HARDENED_CLAY_BLUE("minecraft:stained_hardened_clay", "blue", 159, 11, "blocks/hardened_clay_stained_blue.png", 0xff463857, false),
+ B_159_12_STAINED_HARDENED_CLAY_BROWN("minecraft:stained_hardened_clay", "brown", 159, 12, "blocks/hardened_clay_stained_brown.png", 0xff492e1f, false),
+ B_159_13_STAINED_HARDENED_CLAY_GREEN("minecraft:stained_hardened_clay", "green", 159, 13, "blocks/hardened_clay_stained_green.png", 0xff484f26, false),
+ B_159_14_STAINED_HARDENED_CLAY_RED("minecraft:stained_hardened_clay", "red", 159, 14, "blocks/hardened_clay_stained_red.png", 0xffff382b, false),
+ B_159_15_STAINED_HARDENED_CLAY_BLACK("minecraft:stained_hardened_clay", "black", 159, 15, "blocks/hardened_clay_stained_black.png", 0xff21120d, false),
+ B_160_0_STAINED_GLASS_PANE_WHITE("minecraft:stained_glass_pane", "white", 160, 0, "blocks/glass.png", 0x32141414, false),
+ B_160_1_STAINED_GLASS_PANE_ORANGE("minecraft:stained_glass_pane", "orange", 160, 1, "blocks/glass.png", 0x209d5021, false),
+ B_160_2_STAINED_GLASS_PANE_MAGENTA("minecraft:stained_glass_pane", "magenta", 160, 2, "blocks/glass.png", 0x20915369, false),
+ B_160_3_STAINED_GLASS_PANE_LIGHT_BLUE("minecraft:stained_glass_pane", "light_blue", 160, 3, "blocks/glass.png", 0x20706b87, false),
+ B_160_4_STAINED_GLASS_PANE_YELLOW("minecraft:stained_glass_pane", "yellow", 160, 4, "blocks/glass.png", 0x20b5801f, false),
+ B_160_5_STAINED_GLASS_PANE_LIME("minecraft:stained_glass_pane", "lime", 160, 5, "blocks/glass.png", 0x20617030, false),
+ B_160_6_STAINED_GLASS_PANE_PINK("minecraft:stained_glass_pane", "pink", 160, 6, "blocks/glass.png", 0x209c4848, false),
+ B_160_7_STAINED_GLASS_PANE_GRAY("minecraft:stained_glass_pane", "gray", 160, 7, "blocks/glass.png", 0x20392721, false),
+ B_160_8_STAINED_GLASS_PANE_SILVER("minecraft:stained_glass_pane", "silver", 160, 8, "blocks/glass.png", 0x2081655b, false),
+ B_160_9_STAINED_GLASS_PANE_CYAN("minecraft:stained_glass_pane", "cyan", 160, 9, "blocks/glass.png", 0x20565959, false),
+ B_160_10_STAINED_GLASS_PANE_PURPLE("minecraft:stained_glass_pane", "purple", 160, 10, "blocks/glass.png", 0x20744555, false),
+ B_160_11_STAINED_GLASS_PANE_BLUE("minecraft:stained_glass_pane", "blue", 160, 11, "blocks/glass.png", 0x20463857, false),
+ B_160_12_STAINED_GLASS_PANE_BROWN("minecraft:stained_glass_pane", "brown", 160, 12, "blocks/glass.png", 0x20492e1f, false),
+ B_160_13_STAINED_GLASS_PANE_GREEN("minecraft:stained_glass_pane", "green", 160, 13, "blocks/glass.png", 0x20484f26, false),
+ B_160_14_STAINED_GLASS_PANE_RED("minecraft:stained_glass_pane", "red", 160, 14, "blocks/glass.png", 0x20ff382b, false),
+ B_160_15_STAINED_GLASS_PANE_BLACK("minecraft:stained_glass_pane", "black", 160, 15, "blocks/glass.png", 0x2021120d, false),
+ B_161_0_LEAVES2_ACACIA("minecraft:leaves2", "acacia", 161, 0, "blocks/leaves2_acacia.png", 0xff2e780c, true),
+ B_161_1_LEAVES2_BIG_OAK("minecraft:leaves2", "big_oak", 161, 1, "blocks/leaves2_big_oak.png", 0xff878787, true),
+ B_162_0_LOG2_ACACIA("minecraft:log2", "acacia", 162, 0, "blocks/log2_acacia.png", 0xff934f39, false),
+ B_162_1_LOG2_BIG_OAK("minecraft:log2", "big_oak", 162, 1, "blocks/log2_big_oak.png", 0xff2d2213, false),
+ B_163_0_ACACIA_STAIRS("minecraft:acacia_stairs", null, 163, 0, "blocks/acacia_stairs.png", 0xff934f39, false),
+ B_164_0_DARK_OAK_STAIRS("minecraft:dark_oak_stairs", null, 164, 0, "blocks/dark_oak_stairs.png", 0xff2d2213, false),
+ B_165_0_SLIME("minecraft:slime", null, 165, 0, "blocks/slime.png", 0xc880b672, false),
+ B_167_0_IRON_TRAPDOOR("minecraft:iron_trapdoor", null, 167, 0, "blocks/iron_trapdoor.png", 0xb4cccccc, false),
+ B_168_0_PRISMARINE_ROUGH("minecraft:prismarine", "rough", 168, 0, "blocks/prismarine_rough.png", 0xff79Ad7e, false),
+ B_168_1_PRISMARINE_DARK("minecraft:prismarine", "dark", 168, 1, "blocks/prismarine_dark.png", 0xFF34634e, false),
+ B_168_2_PRISMARINE_BRICKS("minecraft:prismarine", "bricks", 168, 2, "blocks/prismarine_bricks.png", 0xff59Ad7e, false),
+ B_169_0_SEALANTERN("minecraft:seaLantern", null, 169, 0, "blocks/seaLantern.png", 0xffe0eae4, false),
+ B_170_0_HAY_BLOCK("minecraft:hay_block", null, 170, 0, "blocks/hay_block.png", 0xffa3870e, false),
+ B_171_0_CARPET_WHITE("minecraft:carpet", "white", 171, 0, "blocks/carpet_white.png", 0xffdddddd, false),
+ B_171_1_CARPET_ORANGE("minecraft:carpet", "orange", 171, 1, "blocks/carpet_orange.png", 0xffdb7d3e, false),
+ B_171_2_CARPET_MAGENTA("minecraft:carpet", "magenta", 171, 2, "blocks/carpet_magenta.png", 0xffb350bc, false),
+ B_171_3_CARPET_LIGHT_BLUE("minecraft:carpet", "light_blue", 171, 3, "blocks/carpet_light_blue.png", 0xff6a8ac9, false),
+ B_171_4_CARPET_YELLOW("minecraft:carpet", "yellow", 171, 4, "blocks/carpet_yellow.png", 0xffb1a627, false),
+ B_171_5_CARPET_LIME("minecraft:carpet", "lime", 171, 5, "blocks/carpet_lime.png", 0xff41ae38, false),
+ B_171_6_CARPET_PINK("minecraft:carpet", "pink", 171, 6, "blocks/carpet_pink.png", 0xffd08499, false),
+ B_171_7_CARPET_GRAY("minecraft:carpet", "gray", 171, 7, "blocks/carpet_gray.png", 0xff404040, false),
+ B_171_8_CARPET_SILVER("minecraft:carpet", "silver", 171, 8, "blocks/carpet_silver.png", 0xff9aa1a1, false),
+ B_171_9_CARPET_CYAN("minecraft:carpet", "cyan", 171, 9, "blocks/carpet_cyan.png", 0xff2e6e89, false),
+ B_171_10_CARPET_PURPLE("minecraft:carpet", "purple", 171, 10, "blocks/carpet_purple.png", 0xff7e3db5, false),
+ B_171_11_CARPET_BLUE("minecraft:carpet", "blue", 171, 11, "blocks/carpet_blue.png", 0xff2e388d, false),
+ B_171_12_CARPET_BROWN("minecraft:carpet", "brown", 171, 12, "blocks/carpet_brown.png", 0xff4f321f, false),
+ B_171_13_CARPET_GREEN("minecraft:carpet", "green", 171, 13, "blocks/carpet_green.png", 0xff35461b, false),
+ B_171_14_CARPET_RED("minecraft:carpet", "red", 171, 14, "blocks/carpet_red.png", 0xff963430, false),
+ B_171_15_CARPET_BLACK("minecraft:carpet", "black", 171, 15, "blocks/carpet_black.png", 0xff191616, false),
+ B_172_0_HARDENED_CLAY("minecraft:hardened_clay", null, 172, 0, "blocks/hardened_clay.png", 0xff5d3828, false),
+ B_173_0_COAL_BLOCK("minecraft:coal_block", null, 173, 0, "blocks/coal_block.png", 0xff111111, false),
+ B_174_0_PACKED_ICE("minecraft:packed_ice", null, 174, 0, "blocks/packed_ice.png", 0xff97b3e4, false),
+ B_175_0_DOUBLE_PLANT_SUNFLOWER("minecraft:double_plant", "sunflower", 175, 0, "blocks/double_plant_sunflower.png", 0xb4d28219, false),
+ B_175_1_DOUBLE_PLANT_SYRINGA("minecraft:double_plant", "syringa", 175, 1, "blocks/double_plant_syringa.png", 0xb4dec0e2, false),
+ B_175_2_DOUBLE_PLANT_GRASS("minecraft:double_plant", "grass", 175, 2, "blocks/double_plant_grass.png", 0xb4334e2c, false),
+ B_175_3_DOUBLE_PLANT_FERN("minecraft:double_plant", "fern", 175, 3, "blocks/double_plant_fern.png", 0xb43d5d34, false),
+ B_175_4_DOUBLE_PLANT_ROSE("minecraft:double_plant", "rose", 175, 4, "blocks/double_plant_rose.png", 0xb4d10609, false),
+ B_175_5_DOUBLE_PLANT_PAEONIA("minecraft:double_plant", "paeonia", 175, 5, "blocks/double_plant_paeonia.png", 0xb4d6c1df, false),
+
+ B_176_0_BANNER("minecraft:banner", null, 176, 0, "blocks/double_plant_paeonia.png", 0xff9aa1a1, false),
+ B_176_8_BANNER("minecraft:banner", null, 176, 8, "blocks/double_plant_paeonia.png", 0xff9aa1a1, false),
+ B_176_12_BANNER("minecraft:banner", null, 176, 12, "blocks/double_plant_paeonia.png", 0xff9aa1a1, false),
+
+ B_178_0_DAYLIGHT_DETECTOR_INVERTED("minecraft:daylight_detector_inverted", null, 178, 0, "blocks/daylight_detector_inverted.png", 0xffd8c9b5, false),
+ B_179_0_RED_SANDSTONE_DEFAULT("minecraft:red_sandstone", "default", 179, 0, "blocks/red_sandstone_default.png", 0xffaa561e, false),
+ B_179_1_RED_SANDSTONE_CHISELED("minecraft:red_sandstone", "chiseled", 179, 1, "blocks/red_sandstone_chiseled.png", 0xffa8551e, false),
+ B_179_2_RED_SANDSTONE_SMOOTH("minecraft:red_sandstone", "smooth", 179, 2, "blocks/red_sandstone_smooth.png", 0xffcc5e16, false),
+ B_180_0_RED_SANDSTONE_STAIRS("minecraft:red_sandstone_stairs", null, 180, 0, "blocks/red_sandstone_stairs.png", 0xffaa561e, false),
+ B_181_0_DOUBLE_STONE_SLAB2_RED_SANDSTONE("minecraft:double_stone_slab2", "red_sandstone", 181, 0, "blocks/double_stone_slab2_red_sandstone.png", 0xffaa561e, false),
+ B_181_1_DOUBLE_STONE_SLAB2_PURPUR("minecraft:double_stone_slab2", "purpur", 181, 1, "blocks/double_stone_slab2_purpur.png", 0xffa072a0, false),
+ B_182_0_STONE_SLAB2_RED_SANDSTONE("minecraft:stone_slab2", "red_sandstone", 182, 0, "blocks/stone_slab2_red_sandstone.png", 0xffaa561e, false),
+ B_182_1_STONE_SLAB2_PURPUR("minecraft:stone_slab2", "purpur", 182, 1, "blocks/stone_slab2_purpur.png", 0xffa072a0, false),
+ B_183_0_SPRUCE_FENCE_GATE("minecraft:spruce_fence_gate", null, 183, 0, "blocks/spruce_fence_gate.png", 0x8f5a3d0d, false),
+ B_184_0_BIRCH_FENCE_GATE("minecraft:birch_fence_gate", null, 184, 0, "blocks/birch_fence_gate.png", 0x8fdabd8d, false),
+ B_185_0_JUNGLE_FENCE_GATE("minecraft:jungle_fence_gate", null, 185, 0, "blocks/jungle_fence_gate.png", 0x8fBa7d5d, false),
+ B_186_0_DARK_OAK_FENCE_GATE("minecraft:dark_oak_fence_gate", null, 186, 0, "blocks/dark_oak_fence_gate.png", 0x8f2d2213, false),
+ B_187_0_ACACIA_FENCE_GATE("minecraft:acacia_fence_gate", null, 187, 0, "blocks/acacia_fence_gate.png", 0x8f934f39, false),
+
+ B_188_0_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 0, "blocks/command_block.png", 0x00000000, false),
+ B_188_1_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 1, "blocks/command_block.png", 0x00000000, false),
+ B_188_2_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 2, "blocks/command_block.png", 0x00000000, false),
+ B_188_3_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 3, "blocks/command_block.png", 0x00000000, false),
+ B_188_4_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 4, "blocks/command_block.png", 0x00000000, false),
+ B_188_5_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 5, "blocks/command_block.png", 0x00000000, false),
+ B_188_6_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 6, "blocks/command_block.png", 0x00000000, false),
+ B_188_7_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 7, "blocks/command_block.png", 0x00000000, false),
+ B_188_8_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 8, "blocks/command_block.png", 0x00000000, false),
+ B_188_9_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 9, "blocks/command_block.png", 0x00000000, false),
+ B_188_10_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 10, "blocks/command_block.png", 0x00000000, false),
+ B_188_11_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 11, "blocks/command_block.png", 0x00000000, false),
+ B_188_12_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 12, "blocks/command_block.png", 0x00000000, false),
+ B_188_13_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 13, "blocks/command_block.png", 0x00000000, false),
+ B_188_14_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 14, "blocks/command_block.png", 0x00000000, false),
+ B_188_15_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", null, 188, 15, "blocks/command_block.png", 0x00000000, false),
+
+ B_189_0_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 0, "blocks/command_block.png", 0x00000000, false),
+ B_189_1_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 1, "blocks/command_block.png", 0x00000000, false),
+ B_189_2_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 2, "blocks/command_block.png", 0x00000000, false),
+ B_189_3_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 3, "blocks/command_block.png", 0x00000000, false),
+ B_189_4_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 4, "blocks/command_block.png", 0x00000000, false),
+ B_189_5_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 5, "blocks/command_block.png", 0x00000000, false),
+ B_189_6_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 6, "blocks/command_block.png", 0x00000000, false),
+ B_189_7_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 7, "blocks/command_block.png", 0x00000000, false),
+ B_189_8_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 8, "blocks/command_block.png", 0x00000000, false),
+ B_189_9_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 9, "blocks/command_block.png", 0x00000000, false),
+ B_189_10_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 10, "blocks/command_block.png", 0x00000000, false),
+ B_189_11_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 11, "blocks/command_block.png", 0x00000000, false),
+ B_189_12_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 12, "blocks/command_block.png", 0x00000000, false),
+ B_189_13_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 13, "blocks/command_block.png", 0x00000000, false),
+ B_189_14_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 14, "blocks/command_block.png", 0x00000000, false),
+ B_189_15_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", null, 189, 15, "blocks/command_block.png", 0x00000000, false),
+
+ B_190_0_HARD_GLASS_PANE("minecraft:hard_glass_pane", null, 190, 0, "blocks/glass_pane_top.png", 0x00000000, false),
+
+ B_191_0_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 0, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_1_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 1, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_2_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 2, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_3_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 3, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_4_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 4, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_5_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 5, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_6_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 6, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_7_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 7, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_8_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 8, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_9_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 9, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_10_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 10, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_11_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 11, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_12_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 12, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_13_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 13, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_14_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 14, "blocks/glass_pane_top.png", 0x00000000, false),
+ B_191_15_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", null, 191, 15, "blocks/glass_pane_top.png", 0x00000000, false),
+
+ B_192_0_CHEMICAL_HEAT("minecraft:chemical_heat", null, 192, 0, "blocks/fire_0.png", 0x00000000, false),
+
+ B_193_0_SPRUCE_DOOR("minecraft:spruce_door", null, 193, 0, "blocks/spruce_door.png", 0xff5a3d0d, false),
+ B_194_0_BIRCH_DOOR("minecraft:birch_door", null, 194, 0, "blocks/birch_door.png", 0xffdabd8d, false),
+ B_195_0_JUNGLE_DOOR("minecraft:jungle_door", null, 195, 0, "blocks/jungle_door.png", 0xffBa7d5d, false),
+ B_196_0_ACACIA_DOOR("minecraft:acacia_door", null, 196, 0, "blocks/acacia_door.png", 0xff934f39, false),
+ B_197_0_DARK_OAK_DOOR("minecraft:dark_oak_door", null, 197, 0, "blocks/dark_oak_door.png", 0xff2d2213, false),
+ B_198_0_GRASS_PATH("minecraft:grass_path", null, 198, 0, "blocks/grass_path.png", 0x46a0a0a0, false),
+ B_199_0_FRAME("minecraft:frame", null, 199, 0, "blocks/frame.png", 0xa04f3e4f, false),
+ B_200_0_CHORUS_FLOWER("minecraft:chorus_flower", null, 200, 0, "blocks/chorus_flower.png", 0xa0c3b6c8, false),
+ B_201_0_PURPUR_BLOCK_DEFAULT("minecraft:purpur_block", "default", 201, 0, "blocks/purpur_block_default.png", 0xc095c0ff, false),
+ B_201_1_PURPUR_BLOCK_CHISELED("minecraft:purpur_block", "chiseled", 201, 1, "blocks/purpur_block_chiseled.png", 0xc095c0ff, false),
+ B_201_2_PURPUR_BLOCK_LINES("minecraft:purpur_block", "lines", 201, 2, "blocks/purpur_block_lines.png", 0xc095c0ff, false),
+ B_201_3_PURPUR_BLOCK_DEFAULT("minecraft:purpur_block", "default", 201, 3, "blocks/purpur_block_default.png", 0xc095c0ff, false),
+ B_203_0_PURPUR_STAIRS("minecraft:purpur_stairs", null, 203, 0, "blocks/purpur_stairs.png", 0xc095c0ff, false),
+ B_205_0_SHULKERBOX("minecraft:shulker_box", null, 205, 0, "blocks/observer.png", 0xffffffff, false),
+ B_206_0_END_BRICKS("minecraft:end_bricks", null, 206, 0, "blocks/end_bricks.png", 0xffe7f2af, false),
+ B_208_0_END_ROD("minecraft:end_rod", null, 208, 0, "blocks/end_rod.png", 0xff6e6e6e, true),
+ B_209_0_END_GATEWAY("minecraft:end_gateway", null, 209, 0, "blocks/end_gateway.png", 0xff171c27, false),
+ B_210_0_ALLOW("minecraft:210", null, 210, 0, "blocks/allow.png", 0xff634aba, false),
+ B_211_0_DENY("minecraft:211", null, 211, 0, "blocks/deny.png", 0xff6ca28a, false),
+ B_212_0_BORDER_BLOCK("minecraft:212", null, 212, 0, "blocks/border_block.png", 0xff76a7fc, false),
+ B_213_0_MAGMA_BLOCK("minecraft:magma", "default", 213, 0, "blocks/quartz_block_default.png", 0xffc45a12, false),
+ B_214_0_NETHERWART_BLOCK("minecraft:nether_wart_block", "default", 214, 0, "blocks/quartz_block_default.png", 0xffbf2030, false),
+ B_215_0_RED_NETHER_BRICK("minecraft:red_nether_brick", "default", 215, 0, "blocks/quartz_block_default.png", 0xff7f1020, false),
+ B_216_0_BONE("minecraft:bone_block", "default", 216, 0, "blocks/quartz_block_default.png", 0xffefe5d2, false),
+
+ B_218_0_SHULKERBOX_WHITE("minecraft:shulker_box", "white", 218, 0, "blocks/observer.png", 0xffffffff, false),
+ B_218_1_SHULKERBOX_ORANGE("minecraft:shulker_box", "orange", 218, 1, "blocks/observer.png", 0xffffd030, false),
+ B_218_2_SHULKERBOX_MAGENTA("minecraft:shulker_box", "magenta", 218, 2, "blocks/observer.png", 0xffef007f, false),
+ B_218_3_SHULKERBOX_LIGHT_BLUE("minecraft:shulker_box", "light_blue", 218, 3, "blocks/observer.png", 0xff5588ff, false),
+ B_218_4_SHULKERBOX_YELLOW("minecraft:shulker_box", "yellow", 218, 4, "blocks/observer.png", 0xffffff40, false),
+ B_218_5_SHULKERBOX_LIME("minecraft:shulker_box", "lime", 218, 5, "blocks/observer.png", 0xff0db60e, false),
+ B_218_6_SHULKERBOX_PINK("minecraft:shulker_box", "pink", 218, 6, "blocks/observer.png", 0xffff6076, false),
+ B_218_7_SHULKERBOX_GRAY("minecraft:shulker_box", "gray", 218, 7, "blocks/observer.png", 0xff565656, false),
+ B_218_8_SHULKERBOX_SILVER("minecraft:shulker_box", "silver", 218, 8, "blocks/observer.png", 0xffa6a6a6, false),
+ B_218_9_SHULKERBOX_CYAN("minecraft:shulker_box", "cyan", 218, 9, "blocks/observer.png", 0xff0d5656, false),
+ B_218_10_SHULKERBOX_PURPLE("minecraft:shulker_box", "purple", 218, 10, "blocks/observer.png", 0xff560d56, false),
+ B_218_11_SHULKERBOX_BLUE("minecraft:shulker_box", "blue", 218, 11, "blocks/observer.png", 0xff0d0e56, false),
+ B_218_12_SHULKERBOX_BROWN("minecraft:shulker_box", "brown", 218, 12, "blocks/observer.png", 0xff804530, false),
+ B_218_13_SHULKERBOX_GREEN("minecraft:shulker_box", "green", 218, 13, "blocks/observer.png", 0xff0d560e, false),
+ B_218_14_SHULKERBOX_RED("minecraft:shulker_box", "red", 218, 14, "blocks/observer.png", 0xffff2020, false),
+ B_218_15_SHULKERBOX_BLACK("minecraft:shulker_box", "black", 218, 15, "blocks/observer.png", 0xff000000, false),
+
+ B_219_2_GLAZED_TERRACOTTA_PURPLE("minecraft:purple_glazed_terracotta", "purple", 219, 2, "blocks/observer.png", 0xff762d76, false),
+ B_219_3_GLAZED_TERRACOTTA_PURPLE("minecraft:purple_glazed_terracotta", "purple", 219, 3, "blocks/observer.png", 0xff762d76, false),
+ B_219_4_GLAZED_TERRACOTTA_PURPLE("minecraft:purple_glazed_terracotta", "purple", 219, 4, "blocks/observer.png", 0xff762d76, false),
+ B_219_5_GLAZED_TERRACOTTA_PURPLE("minecraft:purple_glazed_terracotta", "purple", 219, 5, "blocks/observer.png", 0xff762d76, false),
+ B_220_2_GLAZED_TERRACOTTA_WHITE("minecraft:white_glazed_terracotta", "white", 220, 2, "blocks/observer.png", 0xffffffff, false),
+ B_220_3_GLAZED_TERRACOTTA_WHITE("minecraft:white_glazed_terracotta", "white", 220, 3, "blocks/observer.png", 0xffffffff, false),
+ B_220_4_GLAZED_TERRACOTTA_WHITE("minecraft:white_glazed_terracotta", "white", 220, 4, "blocks/observer.png", 0xffffffff, false),
+ B_220_5_GLAZED_TERRACOTTA_WHITE("minecraft:white_glazed_terracotta", "white", 220, 5, "blocks/observer.png", 0xffffffff, false),
+ B_221_2_GLAZED_TERRACOTTA_ORANGE("minecraft:orange_glazed_terracotta", "orange", 221, 2, "blocks/observer.png", 0xffff8030, false),
+ B_221_3_GLAZED_TERRACOTTA_ORANGE("minecraft:orange_glazed_terracotta", "orange", 221, 3, "blocks/observer.png", 0xffff8030, false),
+ B_221_4_GLAZED_TERRACOTTA_ORANGE("minecraft:orange_glazed_terracotta", "orange", 221, 4, "blocks/observer.png", 0xffff8030, false),
+ B_221_5_GLAZED_TERRACOTTA_ORANGE("minecraft:orange_glazed_terracotta", "orange", 221, 5, "blocks/observer.png", 0xffff8030, false),
+ B_222_2_GLAZED_TERRACOTTA_LIGHT_MAGENTA("minecraft:magenta_glazed_terracotta", "magenta", 222, 2, "blocks/observer.png", 0xffff108f, false),
+ B_222_3_GLAZED_TERRACOTTA_LIGHT_MAGENTA("minecraft:magenta_glazed_terracotta", "magenta", 222, 3, "blocks/observer.png", 0xffff108f, false),
+ B_222_4_GLAZED_TERRACOTTA_LIGHT_MAGENTA("minecraft:magenta_glazed_terracotta", "magenta", 222, 4, "blocks/observer.png", 0xffff108f, false),
+ B_222_5_GLAZED_TERRACOTTA_LIGHT_MAGENTA("minecraft:magenta_glazed_terracotta", "magenta", 222, 5, "blocks/observer.png", 0xffff108f, false),
+ B_223_2_GLAZED_TERRACOTTA_LIGHT_BLUE("minecraft:light_blue_glazed_terracotta", "light_blue", 223, 2, "blocks/observer.png", 0xff75a8ff, false),
+ B_223_3_GLAZED_TERRACOTTA_LIGHT_BLUE("minecraft:light_blue_glazed_terracotta", "light_blue", 223, 3, "blocks/observer.png", 0xff75a8ff, false),
+ B_223_4_GLAZED_TERRACOTTA_LIGHT_BLUE("minecraft:light_blue_glazed_terracotta", "light_blue", 223, 4, "blocks/observer.png", 0xff75a8ff, false),
+ B_223_5_GLAZED_TERRACOTTA_LIGHT_BLUE("minecraft:light_blue_glazed_terracotta", "light_blue", 223, 5, "blocks/observer.png", 0xff75a8ff, false),
+ B_224_2_GLAZED_TERRACOTTA_YELLOW("minecraft:yellow_glazed_terracotta", "yellow", 224, 2, "blocks/observer.png", 0xffffff60, false),
+ B_224_3_GLAZED_TERRACOTTA_YELLOW("minecraft:yellow_glazed_terracotta", "yellow", 224, 3, "blocks/observer.png", 0xffffff60, false),
+ B_224_4_GLAZED_TERRACOTTA_YELLOW("minecraft:yellow_glazed_terracotta", "yellow", 224, 4, "blocks/observer.png", 0xffffff60, false),
+ B_224_5_GLAZED_TERRACOTTA_YELLOW("minecraft:yellow_glazed_terracotta", "yellow", 224, 5, "blocks/observer.png", 0xffffff60, false),
+ B_225_2_GLAZED_TERRACOTTA_LIME("minecraft:lime_glazed_terracotta", "lime", 225, 2, "blocks/observer.png", 0xff2dd62e, false),
+ B_225_3_GLAZED_TERRACOTTA_LIME("minecraft:lime_glazed_terracotta", "lime", 225, 3, "blocks/observer.png", 0xff2dd62e, false),
+ B_225_4_GLAZED_TERRACOTTA_LIME("minecraft:lime_glazed_terracotta", "lime", 225, 4, "blocks/observer.png", 0xff2dd62e, false),
+ B_225_5_GLAZED_TERRACOTTA_LIME("minecraft:lime_glazed_terracotta", "lime", 225, 5, "blocks/observer.png", 0xff2dd62e, false),
+ B_226_2_GLAZED_TERRACOTTA_PINK("minecraft:pink_glazed_terracotta", "pink", 226, 2, "blocks/observer.png", 0xffff8096, false),
+ B_226_3_GLAZED_TERRACOTTA_PINK("minecraft:pink_glazed_terracotta", "pink", 226, 3, "blocks/observer.png", 0xffff8096, false),
+ B_226_4_GLAZED_TERRACOTTA_PINK("minecraft:pink_glazed_terracotta", "pink", 226, 4, "blocks/observer.png", 0xffff8096, false),
+ B_226_5_GLAZED_TERRACOTTA_PINK("minecraft:pink_glazed_terracotta", "pink", 226, 5, "blocks/observer.png", 0xffff8096, false),
+ B_227_2_GLAZED_TERRACOTTA_GRAY("minecraft:gray_glazed_terracotta", "gray", 227, 2, "blocks/observer.png", 0xff767676, false),
+ B_227_3_GLAZED_TERRACOTTA_GRAY("minecraft:gray_glazed_terracotta", "gray", 227, 3, "blocks/observer.png", 0xff767676, false),
+ B_227_4_GLAZED_TERRACOTTA_GRAY("minecraft:gray_glazed_terracotta", "gray", 227, 4, "blocks/observer.png", 0xff767676, false),
+ B_227_5_GLAZED_TERRACOTTA_GRAY("minecraft:gray_glazed_terracotta", "gray", 227, 5, "blocks/observer.png", 0xff767676, false),
+ B_228_2_GLAZED_TERRACOTTA_LIGHT_GRAY("minecraft:silver_glazed_terracotta", "silver", 228, 2, "blocks/observer.png", 0xffc6c6c6, false),
+ B_228_3_GLAZED_TERRACOTTA_LIGHT_GRAY("minecraft:silver_glazed_terracotta", "silver", 228, 3, "blocks/observer.png", 0xffc6c6c6, false),
+ B_228_4_GLAZED_TERRACOTTA_LIGHT_GRAY("minecraft:silver_glazed_terracotta", "silver", 228, 4, "blocks/observer.png", 0xffc6c6c6, false),
+ B_228_5_GLAZED_TERRACOTTA_LIGHT_GRAY("minecraft:silver_glazed_terracotta", "silver", 228, 5, "blocks/observer.png", 0xffc6c6c6, false),
+ B_229_2_GLAZED_TERRACOTTA_CYAN("minecraft:cyan_glazed_terracotta", "cyan", 229, 2, "blocks/observer.png", 0xff2d7676, false),
+ B_229_3_GLAZED_TERRACOTTA_CYAN("minecraft:cyan_glazed_terracotta", "cyan", 229, 3, "blocks/observer.png", 0xff2d7676, false),
+ B_229_4_GLAZED_TERRACOTTA_CYAN("minecraft:cyan_glazed_terracotta", "cyan", 229, 4, "blocks/observer.png", 0xff2d7676, false),
+ B_229_5_GLAZED_TERRACOTTA_CYAN("minecraft:cyan_glazed_terracotta", "cyan", 229, 5, "blocks/observer.png", 0xff2d7676, false),
+ B_230_0_CHALKBOARD("minecraft:230", null, 230, 0, "blocks/chalkboard.png", 0xff3d6e86, false),
+ B_231_2_GLAZED_TERRACOTTA_BLUE("minecraft:blue_glazed_terracotta", "blue", 231, 2, "blocks/observer.png", 0xff2d2e76, false),
+ B_231_3_GLAZED_TERRACOTTA_BLUE("minecraft:blue_glazed_terracotta", "blue", 231, 3, "blocks/observer.png", 0xff2d2e76, false),
+ B_231_4_GLAZED_TERRACOTTA_BLUE("minecraft:blue_glazed_terracotta", "blue", 231, 4, "blocks/observer.png", 0xff2d2e76, false),
+ B_231_5_GLAZED_TERRACOTTA_BLUE("minecraft:blue_glazed_terracotta", "blue", 231, 5, "blocks/observer.png", 0xff2d2e76, false),
+ B_232_2_GLAZED_TERRACOTTA_BROWN("minecraft:brown_glazed_terracotta", "brown", 232, 2, "blocks/observer.png", 0xffa06550, false),
+ B_232_3_GLAZED_TERRACOTTA_BROWN("minecraft:brown_glazed_terracotta", "brown", 232, 3, "blocks/observer.png", 0xffa06550, false),
+ B_232_4_GLAZED_TERRACOTTA_BROWN("minecraft:brown_glazed_terracotta", "brown", 232, 4, "blocks/observer.png", 0xffa06550, false),
+ B_232_5_GLAZED_TERRACOTTA_BROWN("minecraft:brown_glazed_terracotta", "brown", 232, 5, "blocks/observer.png", 0xffa06550, false),
+ B_233_2_GLAZED_TERRACOTTA_GREEN("minecraft:green_glazed_terracotta", "green", 233, 2, "blocks/observer.png", 0xff2d762e, false),
+ B_233_3_GLAZED_TERRACOTTA_GREEN("minecraft:green_glazed_terracotta", "green", 233, 3, "blocks/observer.png", 0xff2d762e, false),
+ B_233_4_GLAZED_TERRACOTTA_GREEN("minecraft:green_glazed_terracotta", "green", 233, 4, "blocks/observer.png", 0xff2d762e, false),
+ B_233_5_GLAZED_TERRACOTTA_GREEN("minecraft:green_glazed_terracotta", "green", 233, 5, "blocks/observer.png", 0xff2d762e, false),
+ B_234_2_GLAZED_TERRACOTTA_RED("minecraft:red_glazed_terracotta", "red", 234, 2, "blocks/observer.png", 0xffff3030, false),
+ B_234_3_GLAZED_TERRACOTTA_RED("minecraft:red_glazed_terracotta", "red", 234, 3, "blocks/observer.png", 0xffff3030, false),
+ B_234_4_GLAZED_TERRACOTTA_RED("minecraft:red_glazed_terracotta", "red", 234, 4, "blocks/observer.png", 0xffff3030, false),
+ B_234_5_GLAZED_TERRACOTTA_RED("minecraft:red_glazed_terracotta", "red", 234, 5, "blocks/observer.png", 0xffff3030, false),
+ B_235_2_GLAZED_TERRACOTTA_BLACK("minecraft:black_glazed_terracotta", "black", 235, 2, "blocks/observer.png", 0xff050505, false),
+ B_235_3_GLAZED_TERRACOTTA_BLACK("minecraft:black_glazed_terracotta", "black", 235, 3, "blocks/observer.png", 0xff050505, false),
+ B_235_4_GLAZED_TERRACOTTA_BLACK("minecraft:black_glazed_terracotta", "black", 235, 4, "blocks/observer.png", 0xff050505, false),
+ B_235_5_GLAZED_TERRACOTTA_BLACK("minecraft:black_glazed_terracotta", "black", 235, 5, "blocks/observer.png", 0xff050505, false),
+
+ B_236_0_CONCRETE_WHITE("minecraft:concrete", "orange", 236, 0, "blocks/observer.png", 0xffffffff, false),
+ B_236_1_CONCRETE_ORANGE("minecraft:concrete", "orange", 236, 1, "blocks/observer.png", 0xffffd030, false),
+ B_236_2_CONCRETE_MAGENTA("minecraft:concrete", "magenta", 236, 2, "blocks/observer.png", 0xffef007f, false),
+ B_236_3_CONCRETE_LIGHT_BLUE("minecraft:concrete", "light_blue", 236, 3, "blocks/observer.png", 0xff5588ff, false),
+ B_236_4_CONCRETE_YELLOW("minecraft:concrete", "yellow", 236, 4, "blocks/observer.png", 0xffffff40, false),
+ B_236_5_CONCRETE_LIME("minecraft:concrete", "lime", 236, 5, "blocks/observer.png", 0xff0db60e, false),
+ B_236_6_CONCRETE_PINK("minecraft:concrete", "pink", 236, 6, "blocks/observer.png", 0xffff6076, false),
+ B_236_7_CONCRETE_GRAY("minecraft:concrete", "gray", 236, 7, "blocks/observer.png", 0xff565656, false),
+ B_236_8_CONCRETE_SILVER("minecraft:concrete", "silver", 236, 8, "blocks/observer.png", 0xffa6a6a6, false),
+ B_236_9_CONCRETE_CYAN("minecraft:concrete", "cyan", 236, 9, "blocks/observer.png", 0xff0d5656, false),
+ B_236_10_CONCRETE_PURPLE("minecraft:concrete", "purple", 236, 10, "blocks/observer.png", 0xff560d56, false),
+ B_236_11_CONCRETE_BLUE("minecraft:concrete", "blue", 236, 11, "blocks/observer.png", 0xff0d0e56, false),
+ B_236_12_CONCRETE_BROWN("minecraft:concrete", "brown", 236, 12, "blocks/observer.png", 0xff804530, false),
+ B_236_13_CONCRETE_GREEN("minecraft:concrete", "green", 236, 13, "blocks/observer.png", 0xff0d560e, false),
+ B_236_14_CONCRETE_RED("minecraft:concrete", "red", 236, 14, "blocks/observer.png", 0xffff2020, false),
+ B_236_15_CONCRETE_BLACK("minecraft:concrete", "black", 236, 15, "blocks/observer.png", 0xff000000, false),
+
+ B_237_0_CONCRETE_POWDER_WHITE("minecraft:concretePowder", "white", 237, 0, "blocks/observer.png", 0xffffffff, false),
+ B_237_1_CONCRETE_POWDER_ORANGE("minecraft:concretePowder", "orange", 237, 1, "blocks/observer.png", 0xffffd030, false),
+ B_237_2_CONCRETE_POWDER_MAGENTA("minecraft:concretePowder", "magenta", 237, 2, "blocks/observer.png", 0xffef007f, false),
+ B_237_3_CONCRETE_POWDER_LIGHT_BLUE("minecraft:concretePowder", "light_blue", 237, 3, "blocks/observer.png", 0xff5588ff, false),
+ B_237_4_CONCRETE_POWDER_YELLOW("minecraft:concretePowder", "yellow", 237, 4, "blocks/observer.png", 0xffffff40, false),
+ B_237_5_CONCRETE_POWDER_LIME("minecraft:concretePowder", "lime", 237, 5, "blocks/observer.png", 0xff0db60e, false),
+ B_237_6_CONCRETE_POWDER_PINK("minecraft:concretePowder", "pink", 237, 6, "blocks/observer.png", 0xffff6076, false),
+ B_237_7_CONCRETE_POWDER_GRAY("minecraft:concretePowder", "gray", 237, 7, "blocks/observer.png", 0xff565656, false),
+ B_237_8_CONCRETE_POWDER_SILVER("minecraft:concretePowder", "silver", 237, 8, "blocks/observer.png", 0xffa6a6a6, false),
+ B_237_9_CONCRETE_POWDER_CYAN("minecraft:concretePowder", "cyan", 237, 9, "blocks/observer.png", 0xff0d5656, false),
+ B_237_10_CONCRETE_POWDER_PURPLE("minecraft:concretePowder", "purple", 237, 10, "blocks/observer.png", 0xff560d56, false),
+ B_237_11_CONCRETE_POWDER_BLUE("minecraft:concretePowder", "blue", 237, 11, "blocks/observer.png", 0xff0d0e56, false),
+ B_237_12_CONCRETE_POWDER_BROWN("minecraft:concretePowder", "brown", 237, 12, "blocks/observer.png", 0xff804530, false),
+ B_237_13_CONCRETE_POWDER_GREEN("minecraft:concretePowder", "green", 237, 13, "blocks/observer.png", 0xff0d560e, false),
+ B_237_14_CONCRETE_POWDER_RED("minecraft:concretePowder", "brown", 237, 14, "blocks/observer.png", 0xffff2020, false),
+ B_237_15_CONCRETE_POWDER_BLACK("minecraft:concretePowder", "black", 237, 15, "blocks/observer.png", 0xff000000, false),
+
+ B_238_0_CHEMISTRY_TABLE("minecraft:chemistry_table", "orange", 238, 0, "blocks/observer.png", 0xffffffff, false),
+ B_238_1_CHEMISTRY_TABLE("minecraft:chemistry_table", "orange", 238, 1, "blocks/observer.png", 0xffffd030, false),
+ B_238_2_CHEMISTRY_TABLE("minecraft:chemistry_table", "magenta", 238, 2, "blocks/observer.png", 0xffef007f, false),
+ B_238_3_CHEMISTRY_TABLE("minecraft:chemistry_table", "light_blue", 238, 3, "blocks/observer.png", 0xff5588ff, false),
+ B_238_4_CHEMISTRY_TABLE("minecraft:chemistry_table", "yellow", 238, 4, "blocks/observer.png", 0xffffff40, false),
+ B_238_5_CHEMISTRY_TABLE("minecraft:chemistry_table", "lime", 238, 5, "blocks/observer.png", 0xff0db60e, false),
+ B_238_6_CHEMISTRY_TABLE("minecraft:chemistry_table", "pink", 238, 6, "blocks/observer.png", 0xffff6076, false),
+ B_238_7_CHEMISTRY_TABLE("minecraft:chemistry_table", "gray", 238, 7, "blocks/observer.png", 0xff565656, false),
+ B_238_8_CHEMISTRY_TABLE("minecraft:chemistry_table", "silver", 238, 8, "blocks/observer.png", 0xffa6a6a6, false),
+ B_238_9_CHEMISTRY_TABLE("minecraft:chemistry_table", "cyan", 238, 9, "blocks/observer.png", 0xff0d5656, false),
+ B_238_10_CHEMISTRY_TABLE("minecraft:chemistry_table", "purple", 238, 10, "blocks/observer.png", 0xff560d56, false),
+ B_238_11_CHEMISTRY_TABLE("minecraft:chemistry_table", "blue", 238, 11, "blocks/observer.png", 0xff0d0e56, false),
+ B_238_12_CHEMISTRY_TABLE("minecraft:chemistry_table", "brown", 238, 12, "blocks/observer.png", 0xff804530, false),
+ B_238_13_CHEMISTRY_TABLE("minecraft:chemistry_table", "green", 238, 13, "blocks/observer.png", 0xff0d560e, false),
+ B_238_14_CHEMISTRY_TABLE("minecraft:chemistry_table", "brown", 238, 14, "blocks/observer.png", 0xffff2020, false),
+ B_238_15_CHEMISTRY_TABLE("minecraft:chemistry_table", "black", 238, 15, "blocks/observer.png", 0xff000000, false),
+
+ B_239_0_UNDERWATER_TORCH("minecraft:underwater_torch", "orange", 239, 0, "blocks/observer.png", 0xffffffff, false),
+ B_239_1_UNDERWATER_TORCH("minecraft:underwater_torch", "orange", 239, 1, "blocks/observer.png", 0xffffd030, false),
+ B_239_2_UNDERWATER_TORCH("minecraft:underwater_torch", "magenta", 239, 2, "blocks/observer.png", 0xffef007f, false),
+ B_239_3_UNDERWATER_TORCH("minecraft:underwater_torch", "light_blue", 239, 3, "blocks/observer.png", 0xff5588ff, false),
+ B_239_4_UNDERWATER_TORCH("minecraft:underwater_torch", "yellow", 239, 4, "blocks/observer.png", 0xffffff40, false),
+ B_239_5_UNDERWATER_TORCH("minecraft:underwater_torch", "lime", 239, 5, "blocks/observer.png", 0xff0db60e, false),
+ B_239_6_UNDERWATER_TORCH("minecraft:underwater_torch", "pink", 239, 6, "blocks/observer.png", 0xffff6076, false),
+ B_239_7_UNDERWATER_TORCH("minecraft:underwater_torch", "gray", 239, 7, "blocks/observer.png", 0xff565656, false),
+
+ B_240_0_CHORUS_PLANT("minecraft:chorus_plant", null, 240, 0, "blocks/chorus_plant.png", 0xaa3d6e86, false),
+ B_241_0_STAINED_GLASS_WHITE("minecraft:stained_glass", "white", 241, 0, "blocks/stained_glass_white.png", 0x50836f64, false),
+ B_241_1_STAINED_GLASS_ORANGE("minecraft:stained_glass", "orange", 241, 1, "blocks/stained_glass_orange.png", 0x509d5021, false),
+ B_241_2_STAINED_GLASS_MAGENTA("minecraft:stained_glass", "magenta", 241, 2, "blocks/stained_glass_magenta.png", 0x50915369, false),
+ B_241_3_STAINED_GLASS_LIGHT_BLUE("minecraft:stained_glass", "light_blue", 241, 3, "blocks/stained_glass_light_blue.png", 0x50706b87, false),
+ B_241_4_STAINED_GLASS_YELLOW("minecraft:stained_glass", "yellow", 241, 4, "blocks/stained_glass_yellow.png", 0x50b5801f, false),
+ B_241_5_STAINED_GLASS_LIME("minecraft:stained_glass", "lime", 241, 5, "blocks/stained_glass_lime.png", 0x50617030, false),
+ B_241_6_STAINED_GLASS_PINK("minecraft:stained_glass", "pink", 241, 6, "blocks/stained_glass_pink.png", 0x509c4848, false),
+ B_241_7_STAINED_GLASS_GRAY("minecraft:stained_glass", "gray", 241, 7, "blocks/stained_glass_gray.png", 0x50392721, false),
+ B_241_8_STAINED_GLASS_SILVER("minecraft:stained_glass", "silver", 241, 8, "blocks/stained_glass_silver.png", 0x5081655b, false),
+ B_241_9_STAINED_GLASS_CYAN("minecraft:stained_glass", "cyan", 241, 9, "blocks/stained_glass_cyan.png", 0x50565959, false),
+ B_241_10_STAINED_GLASS_PURPLE("minecraft:stained_glass", "purple", 241, 10, "blocks/stained_glass_purple.png", 0x50744555, false),
+ B_241_11_STAINED_GLASS_BLUE("minecraft:stained_glass", "blue", 241, 11, "blocks/stained_glass_blue.png", 0x50463857, false),
+ B_241_12_STAINED_GLASS_BROWN("minecraft:stained_glass", "brown", 241, 12, "blocks/stained_glass_brown.png", 0x50492e1f, false),
+ B_241_13_STAINED_GLASS_GREEN("minecraft:stained_glass", "green", 241, 13, "blocks/stained_glass_green.png", 0x50484f26, false),
+ B_241_14_STAINED_GLASS_RED("minecraft:stained_glass", "red", 241, 14, "blocks/stained_glass_red.png", 0x50ff382b, false),
+ B_241_15_STAINED_GLASS_BLACK("minecraft:stained_glass", "black", 241, 15, "blocks/stained_glass_black.png", 0x5021120d, false),
+ B_242_0_CAMERA("minecraft:242", null, 242, 0, "blocks/camera.png", 0xff3d6e86, false),
+ B_243_0_PODZOL("minecraft:podzol", null, 243, 0, "blocks/podzol.png", 0xff533a1b, true),
+ B_244_0_BEETROOT("minecraft:beetroot", null, 244, 0, "blocks/beetroot.png", 0x0901ab10, false),
+ B_245_0_STONECUTTER("minecraft:stonecutter", null, 245, 0, "blocks/stonecutter.png", 0xff515151, false),
+ B_246_0_GLOWINGOBSIDIAN("minecraft:glowingobsidian", null, 246, 0, "blocks/glowingobsidian.png", 0xff17060a, false),
+ B_247_0_NETHERREACTOR_DEFAULT("minecraft:netherreactor", "default", 247, 0, "blocks/netherreactor_default.png", 0xffd2d200, false),
+ B_247_1_NETHERREACTOR_ACTIVE("minecraft:netherreactor", "active", 247, 1, "blocks/netherreactor_active.png", 0xff3d6e86, false),
+ B_247_2_NETHERREACTOR_COOLED("minecraft:netherreactor", "cooled", 247, 2, "blocks/netherreactor_cooled.png", 0xff3d6e86, false),
+ B_248_0_INFO_UPDATE("minecraft:info_update", null, 248, 0, "blocks/info_update.png", 0xff2f3218, false),
+ B_249_0_INFO_UPDATE2("minecraft:info_update2", null, 249, 0, "blocks/info_update2.png", 0xff2f3218, false),
+ B_250_0_MOVINGBLOCK("minecraft:movingBlock", null, 250, 0, "blocks/movingBlock.png", 0, false),
+
+ B_251_0_OBSERVER("minecraft:observer", null, 251, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_1_OBSERVER("minecraft:observer", null, 251, 1, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_2_OBSERVER("minecraft:observer", null, 251, 2, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_3_OBSERVER("minecraft:observer", null, 251, 3, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_4_OBSERVER("minecraft:observer", null, 251, 4, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_5_OBSERVER("minecraft:observer", null, 251, 5, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_6_OBSERVER("minecraft:observer", null, 251, 6, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_7_OBSERVER("minecraft:observer", null, 251, 7, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_8_OBSERVER("minecraft:observer", null, 251, 8, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_9_OBSERVER("minecraft:observer", null, 251, 9, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_10_OBSERVER("minecraft:observer", null, 251, 10, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_11_OBSERVER("minecraft:observer", null, 251, 11, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_12_OBSERVER("minecraft:observer", null, 251, 12, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_13_OBSERVER("minecraft:observer", null, 251, 13, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_14_OBSERVER("minecraft:observer", null, 251, 14, "blocks/observer.png", 0xff3d6e86, false),
+ B_251_15_OBSERVER("minecraft:observer", null, 251, 15, "blocks/observer.png", 0xff3d6e86, false),
+
+ B_252_0_STRUCTURE_BLOCK("minecraft:structure_block", null, 252, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_252_1_STRUCTURE_BLOCK("minecraft:structure_block", null, 252, 1, "blocks/observer.png", 0xff3d6e86, false),
+ B_252_2_STRUCTURE_BLOCK("minecraft:structure_block", null, 252, 2, "blocks/observer.png", 0xff3d6e86, false),
+ B_252_3_STRUCTURE_BLOCK("minecraft:structure_block", null, 252, 3, "blocks/observer.png", 0xff3d6e86, false),
+ B_252_4_STRUCTURE_BLOCK("minecraft:structure_block", null, 252, 4, "blocks/observer.png", 0xff3d6e86, false),
+ B_252_5_STRUCTURE_BLOCK("minecraft:structure_block", null, 252, 5, "blocks/observer.png", 0xff3d6e86, false),
+ B_252_6_STRUCTURE_BLOCK("minecraft:structure_block", null, 252, 6, "blocks/observer.png", 0xff3d6e86, false),
+ B_252_7_STRUCTURE_BLOCK("minecraft:structure_block", null, 252, 7, "blocks/observer.png", 0xff3d6e86, false),
+
+ B_253_0_HARD_GLASS("minecraft:hard_glass", null, 253, 0, "blocks/observer.png", 0xff3d6e86, false),
+
+ B_254_0_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "white", 254, 0, "blocks/stained_glass_white.png", 0x50836f64, false),
+ B_254_1_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "orange", 254, 1, "blocks/stained_glass_orange.png", 0x509d5021, false),
+ B_254_2_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "magenta", 254, 2, "blocks/stained_glass_magenta.png", 0x50915369, false),
+ B_254_3_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "light_blue", 254, 3, "blocks/stained_glass_light_blue.png", 0x50706b87, false),
+ B_254_4_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "yellow", 254, 4, "blocks/stained_glass_yellow.png", 0x50b5801f, false),
+ B_254_5_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "lime", 254, 5, "blocks/stained_glass_lime.png", 0x50617030, false),
+ B_254_6_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "pink", 254, 6, "blocks/stained_glass_pink.png", 0x509c4848, false),
+ B_254_7_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "gray", 254, 7, "blocks/stained_glass_gray.png", 0x50392721, false),
+ B_254_8_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "silver", 254, 8, "blocks/stained_glass_silver.png", 0x5081655b, false),
+ B_254_9_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "cyan", 254, 9, "blocks/stained_glass_cyan.png", 0x50565959, false),
+ B_254_10_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "purple", 254, 10, "blocks/stained_glass_purple.png", 0x50744555, false),
+ B_254_11_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "blue", 254, 11, "blocks/stained_glass_blue.png", 0x50463857, false),
+ B_254_12_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "brown", 254, 12, "blocks/stained_glass_brown.png", 0x50492e1f, false),
+ B_254_13_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "green", 254, 13, "blocks/stained_glass_green.png", 0x50484f26, false),
+ B_254_14_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "red", 254, 14, "blocks/stained_glass_red.png", 0x50ff382b, false),
+ B_254_15_HARD_STAINED_GLASS("minecraft:hard_stained_glass", "black", 254, 15, "blocks/stained_glass_black.png", 0x5021120d, false),
+
+ B_255_0_RESERVED6("minecraft:reserved6", null, 255, 0, "blocks/reserved6.png", 0xff19171a, false),
+
+ B_2153_0_256("minecraft:256", "", 2153, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_2154_0_prismarine_stairs("minecraft:prismarine_stairs", "", 2154, 0, "blocks/observer.png", 0xA9498d6e, false),
+ B_2155_1_prismarine_stairs("minecraft:prismarine_stairs", "", 2155, 1, "blocks/observer.png", 0xA9498d6e, false),
+ B_2156_2_prismarine_stairs("minecraft:prismarine_stairs", "", 2156, 2, "blocks/observer.png", 0xA9498d6e, false),
+ B_2157_3_prismarine_stairs("minecraft:prismarine_stairs", "", 2157, 3, "blocks/observer.png", 0xA9498d6e, false),
+ B_2158_4_prismarine_stairs("minecraft:prismarine_stairs", "", 2158, 4, "blocks/observer.png", 0xA9498d6e, false),
+ B_2159_5_prismarine_stairs("minecraft:prismarine_stairs", "", 2159, 5, "blocks/observer.png", 0xA9498d6e, false),
+ B_2160_6_prismarine_stairs("minecraft:prismarine_stairs", "", 2160, 6, "blocks/observer.png", 0xA9498d6e, false),
+ B_2161_7_prismarine_stairs("minecraft:prismarine_stairs", "", 2161, 7, "blocks/observer.png", 0xA9498d6e, false),
+ B_2162_0_dark_prismarine_stairs("minecraft:dark_prismarine_stairs", "", 2162, 0, "blocks/observer.png", 0xff04635e, false),
+ B_2163_1_dark_prismarine_stairs("minecraft:dark_prismarine_stairs", "", 2163, 1, "blocks/observer.png", 0xff04635e, false),
+ B_2164_2_dark_prismarine_stairs("minecraft:dark_prismarine_stairs", "", 2164, 2, "blocks/observer.png", 0xff04635e, false),
+ B_2165_3_dark_prismarine_stairs("minecraft:dark_prismarine_stairs", "", 2165, 3, "blocks/observer.png", 0xff04635e, false),
+ B_2166_4_dark_prismarine_stairs("minecraft:dark_prismarine_stairs", "", 2166, 4, "blocks/observer.png", 0xff04635e, false),
+ B_2167_5_dark_prismarine_stairs("minecraft:dark_prismarine_stairs", "", 2167, 5, "blocks/observer.png", 0xff04635e, false),
+ B_2168_6_dark_prismarine_stairs("minecraft:dark_prismarine_stairs", "", 2168, 6, "blocks/observer.png", 0xff04635e, false),
+ B_2169_7_dark_prismarine_stairs("minecraft:dark_prismarine_stairs", "", 2169, 7, "blocks/observer.png", 0xff04635e, false),
+ B_2170_0_prismarine_bricks_stairs("minecraft:prismarine_bricks_stairs", "", 2170, 0, "blocks/observer.png", 0xff097d6e, false),
+ B_2171_1_prismarine_bricks_stairs("minecraft:prismarine_bricks_stairs", "", 2171, 1, "blocks/observer.png", 0xff097d6e, false),
+ B_2172_2_prismarine_bricks_stairs("minecraft:prismarine_bricks_stairs", "", 2172, 2, "blocks/observer.png", 0xff097d6e, false),
+ B_2173_3_prismarine_bricks_stairs("minecraft:prismarine_bricks_stairs", "", 2173, 3, "blocks/observer.png", 0xff097d6e, false),
+ B_2174_4_prismarine_bricks_stairs("minecraft:prismarine_bricks_stairs", "", 2174, 4, "blocks/observer.png", 0xff097d6e, false),
+ B_2175_5_prismarine_bricks_stairs("minecraft:prismarine_bricks_stairs", "", 2175, 5, "blocks/observer.png", 0xff097d6e, false),
+ B_2176_6_prismarine_bricks_stairs("minecraft:prismarine_bricks_stairs", "", 2176, 6, "blocks/observer.png", 0xff097d6e, false),
+ B_2177_7_prismarine_bricks_stairs("minecraft:prismarine_bricks_stairs", "", 2177, 7, "blocks/observer.png", 0xff097d6e, false),
+ B_2178_0_stripped_spruce_log("minecraft:stripped_spruce_log", "", 2178, 0, "blocks/observer.png", 0xff5a3d0d, false),
+ B_2179_1_stripped_spruce_log("minecraft:stripped_spruce_log", "", 2179, 1, "blocks/observer.png", 0xff5a3d0d, false),
+ B_2180_2_stripped_spruce_log("minecraft:stripped_spruce_log", "", 2180, 2, "blocks/observer.png", 0xff5a3d0d, false),
+ B_2181_3_stripped_spruce_log("minecraft:stripped_spruce_log", "", 2181, 3, "blocks/observer.png", 0xff5a3d0d, false),
+ B_2182_0_stripped_birch_log("minecraft:stripped_birch_log", "", 2182, 0, "blocks/observer.png", 0xffdabd8d, false),
+ B_2183_1_stripped_birch_log("minecraft:stripped_birch_log", "", 2183, 1, "blocks/observer.png", 0xffdabd8d, false),
+ B_2184_2_stripped_birch_log("minecraft:stripped_birch_log", "", 2184, 2, "blocks/observer.png", 0xffdabd8d, false),
+ B_2185_3_stripped_birch_log("minecraft:stripped_birch_log", "", 2185, 3, "blocks/observer.png", 0xffdabd8d, false),
+ B_2186_0_stripped_jungle_log("minecraft:stripped_jungle_log", "", 2186, 0, "blocks/observer.png", 0xffBa7d5d, false),
+ B_2187_1_stripped_jungle_log("minecraft:stripped_jungle_log", "", 2187, 1, "blocks/observer.png", 0xffBa7d5d, false),
+ B_2188_2_stripped_jungle_log("minecraft:stripped_jungle_log", "", 2188, 2, "blocks/observer.png", 0xffBa7d5d, false),
+ B_2189_3_stripped_jungle_log("minecraft:stripped_jungle_log", "", 2189, 3, "blocks/observer.png", 0xffBa7d5d, false),
+ B_2190_0_stripped_acacia_log("minecraft:stripped_acacia_log", "", 2190, 0, "blocks/observer.png", 0xff934f39, false),
+ B_2191_1_stripped_acacia_log("minecraft:stripped_acacia_log", "", 2191, 1, "blocks/observer.png", 0xff934f39, false),
+ B_2192_2_stripped_acacia_log("minecraft:stripped_acacia_log", "", 2192, 2, "blocks/observer.png", 0xff934f39, false),
+ B_2193_3_stripped_acacia_log("minecraft:stripped_acacia_log", "", 2193, 3, "blocks/observer.png", 0xff934f39, false),
+ B_2194_0_stripped_dark_oak_log("minecraft:stripped_dark_oak_log", "", 2194, 0, "blocks/observer.png", 0xff2d2213, false),
+ B_2195_1_stripped_dark_oak_log("minecraft:stripped_dark_oak_log", "", 2195, 1, "blocks/observer.png", 0xff2d2213, false),
+ B_2196_2_stripped_dark_oak_log("minecraft:stripped_dark_oak_log", "", 2196, 2, "blocks/observer.png", 0xff2d2213, false),
+ B_2197_3_stripped_dark_oak_log("minecraft:stripped_dark_oak_log", "", 2197, 3, "blocks/observer.png", 0xff2d2213, false),
+ B_2198_0_stripped_oak_log("minecraft:stripped_oak_log", "", 2198, 0, "blocks/observer.png", 0xff9a7d4d, false),
+ B_2199_1_stripped_oak_log("minecraft:stripped_oak_log", "", 2199, 1, "blocks/observer.png", 0xff9a7d4d, false),
+ B_2200_2_stripped_oak_log("minecraft:stripped_oak_log", "", 2200, 2, "blocks/observer.png", 0xff9a7d4d, false),
+ B_2201_3_stripped_oak_log("minecraft:stripped_oak_log", "", 2201, 3, "blocks/observer.png", 0xff9a7d4d, false),
+ B_2202_0_blue_ice("minecraft:blue_ice", "", 2202, 0, "blocks/observer.png", 0xff7dbeF6, false),
+ /**/
+ B_4091_0_seagrass("minecraft:seagrass", "", 4091, 0, "blocks/observer.png", 0x4e787878, false),
+ B_4092_1_seagrass("minecraft:seagrass", "", 4092, 1, "blocks/observer.png", 0x4e787878, false),
+ B_4093_2_seagrass("minecraft:seagrass", "", 4093, 2, "blocks/observer.png", 0x4e787878, false),
+ B_4094_3_seagrass("minecraft:seagrass", "", 4094, 3, "blocks/observer.png", 0x4e787878, false),
+ B_4095_0_coral("minecraft:coral", "", 4095, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_4096_1_coral("minecraft:coral", "", 4096, 1, "blocks/observer.png", 0xff3d6e86, false),
+ B_4097_2_coral("minecraft:coral", "", 4097, 2, "blocks/observer.png", 0xff3d6e86, false),
+ B_4098_3_coral("minecraft:coral", "", 4098, 3, "blocks/observer.png", 0xff3d6e86, false),
+ B_4099_4_coral("minecraft:coral", "", 4099, 4, "blocks/observer.png", 0xff3d6e86, false),
+ B_4100_5_coral("minecraft:coral", "", 4100, 5, "blocks/observer.png", 0xff3d6e86, false),
+ B_4101_6_coral("minecraft:coral", "", 4101, 6, "blocks/observer.png", 0xff3d6e86, false),
+ B_4102_7_coral("minecraft:coral", "", 4102, 7, "blocks/observer.png", 0xff3d6e86, false),
+ B_4103_8_coral("minecraft:coral", "", 4103, 8, "blocks/observer.png", 0xff3d6e86, false),
+ B_4104_9_coral("minecraft:coral", "", 4104, 9, "blocks/observer.png", 0xff3d6e86, false),
+ B_4105_10_coral("minecraft:coral", "", 4105, 10, "blocks/observer.png", 0xff3d6e86, false),
+ B_4106_11_coral("minecraft:coral", "", 4106, 11, "blocks/observer.png", 0xff3d6e86, false),
+ B_4107_12_coral("minecraft:coral", "", 4107, 12, "blocks/observer.png", 0xff3d6e86, false),
+ B_4108_13_coral("minecraft:coral", "", 4108, 13, "blocks/observer.png", 0xff3d6e86, false),
+ B_4109_14_coral("minecraft:coral", "", 4109, 14, "blocks/observer.png", 0xff3d6e86, false),
+ B_4110_15_coral("minecraft:coral", "", 4110, 15, "blocks/observer.png", 0xff3d6e86, false),
+ B_4111_0_coral_block("minecraft:coral_block", "", 4111, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_4112_1_coral_block("minecraft:coral_block", "", 4112, 1, "blocks/observer.png", 0xff3d6e86, false),
+ B_4113_2_coral_block("minecraft:coral_block", "", 4113, 2, "blocks/observer.png", 0xff3d6e86, false),
+ B_4114_3_coral_block("minecraft:coral_block", "", 4114, 3, "blocks/observer.png", 0xff3d6e86, false),
+ B_4115_4_coral_block("minecraft:coral_block", "", 4115, 4, "blocks/observer.png", 0xff3d6e86, false),
+ B_4116_5_coral_block("minecraft:coral_block", "", 4116, 5, "blocks/observer.png", 0xff3d6e86, false),
+ B_4117_6_coral_block("minecraft:coral_block", "", 4117, 6, "blocks/observer.png", 0xff3d6e86, false),
+ B_4118_7_coral_block("minecraft:coral_block", "", 4118, 7, "blocks/observer.png", 0xff3d6e86, false),
+ B_4119_8_coral_block("minecraft:coral_block", "", 4119, 8, "blocks/observer.png", 0xff3d6e86, false),
+ B_4120_9_coral_block("minecraft:coral_block", "", 4120, 9, "blocks/observer.png", 0xff3d6e86, false),
+ B_4121_10_coral_block("minecraft:coral_block", "", 4121, 10, "blocks/observer.png", 0xff3d6e86, false),
+ B_4122_11_coral_block("minecraft:coral_block", "", 4122, 11, "blocks/observer.png", 0xff3d6e86, false),
+ B_4123_12_coral_block("minecraft:coral_block", "", 4123, 12, "blocks/observer.png", 0xff3d6e86, false),
+ B_4124_13_coral_block("minecraft:coral_block", "", 4124, 13, "blocks/observer.png", 0xff3d6e86, false),
+ B_4125_14_coral_block("minecraft:coral_block", "", 4125, 14, "blocks/observer.png", 0xff3d6e86, false),
+ B_4126_15_coral_block("minecraft:coral_block", "", 4126, 15, "blocks/observer.png", 0xff3d6e86, false),
+ B_4127_0_coral_fan("minecraft:coral_fan", "", 4127, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_4128_1_coral_fan("minecraft:coral_fan", "", 4128, 1, "blocks/observer.png", 0xff3d6e86, false),
+ B_4129_2_coral_fan("minecraft:coral_fan", "", 4129, 2, "blocks/observer.png", 0xff3d6e86, false),
+ B_4130_3_coral_fan("minecraft:coral_fan", "", 4130, 3, "blocks/observer.png", 0xff3d6e86, false),
+ B_4131_4_coral_fan("minecraft:coral_fan", "", 4131, 4, "blocks/observer.png", 0xff3d6e86, false),
+ B_4132_5_coral_fan("minecraft:coral_fan", "", 4132, 5, "blocks/observer.png", 0xff3d6e86, false),
+ B_4133_6_coral_fan("minecraft:coral_fan", "", 4133, 6, "blocks/observer.png", 0xff3d6e86, false),
+ B_4134_7_coral_fan("minecraft:coral_fan", "", 4134, 7, "blocks/observer.png", 0xff3d6e86, false),
+ B_4135_8_coral_fan("minecraft:coral_fan", "", 4135, 8, "blocks/observer.png", 0xff3d6e86, false),
+ B_4136_9_coral_fan("minecraft:coral_fan", "", 4136, 9, "blocks/observer.png", 0xff3d6e86, false),
+ B_4137_10_coral_fan("minecraft:coral_fan", "", 4137, 10, "blocks/observer.png", 0xff3d6e86, false),
+ B_4138_11_coral_fan("minecraft:coral_fan", "", 4138, 11, "blocks/observer.png", 0xff3d6e86, false),
+ B_4139_12_coral_fan("minecraft:coral_fan", "", 4139, 12, "blocks/observer.png", 0xff3d6e86, false),
+ B_4140_13_coral_fan("minecraft:coral_fan", "", 4140, 13, "blocks/observer.png", 0xff3d6e86, false),
+ B_4141_14_coral_fan("minecraft:coral_fan", "", 4141, 14, "blocks/observer.png", 0xff3d6e86, false),
+ B_4142_15_coral_fan("minecraft:coral_fan", "", 4142, 15, "blocks/observer.png", 0xff3d6e86, false),
+ B_4143_0_coral_fan_dead("minecraft:coral_fan_dead", "", 4143, 0, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4144_1_coral_fan_dead("minecraft:coral_fan_dead", "", 4144, 1, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4145_2_coral_fan_dead("minecraft:coral_fan_dead", "", 4145, 2, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4146_3_coral_fan_dead("minecraft:coral_fan_dead", "", 4146, 3, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4147_4_coral_fan_dead("minecraft:coral_fan_dead", "", 4147, 4, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4148_5_coral_fan_dead("minecraft:coral_fan_dead", "", 4148, 5, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4149_6_coral_fan_dead("minecraft:coral_fan_dead", "", 4149, 6, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4150_7_coral_fan_dead("minecraft:coral_fan_dead", "", 4150, 7, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4151_8_coral_fan_dead("minecraft:coral_fan_dead", "", 4151, 8, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4152_9_coral_fan_dead("minecraft:coral_fan_dead", "", 4152, 9, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4153_10_coral_fan_dead("minecraft:coral_fan_dead", "", 4153, 10, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4154_11_coral_fan_dead("minecraft:coral_fan_dead", "", 4154, 11, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4155_12_coral_fan_dead("minecraft:coral_fan_dead", "", 4155, 12, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4156_13_coral_fan_dead("minecraft:coral_fan_dead", "", 4156, 13, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4157_14_coral_fan_dead("minecraft:coral_fan_dead", "", 4157, 14, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4158_15_coral_fan_dead("minecraft:coral_fan_dead", "", 4158, 15, "blocks/observer.png", 0xFFC8C8C8, false),
+ B_4159_0_coral_fan_hang("minecraft:coral_fan_hang", "", 4159, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_4160_1_coral_fan_hang("minecraft:coral_fan_hang", "", 4160, 1, "blocks/observer.png", 0xff3d6e86, false),
+ B_4161_2_coral_fan_hang("minecraft:coral_fan_hang", "", 4161, 2, "blocks/observer.png", 0xff3d6e86, false),
+ B_4162_3_coral_fan_hang("minecraft:coral_fan_hang", "", 4162, 3, "blocks/observer.png", 0xff3d6e86, false),
+ B_4163_4_coral_fan_hang("minecraft:coral_fan_hang", "", 4163, 4, "blocks/observer.png", 0xff3d6e86, false),
+ B_4164_5_coral_fan_hang("minecraft:coral_fan_hang", "", 4164, 5, "blocks/observer.png", 0xff3d6e86, false),
+ B_4165_6_coral_fan_hang("minecraft:coral_fan_hang", "", 4165, 6, "blocks/observer.png", 0xff3d6e86, false),
+ B_4166_7_coral_fan_hang("minecraft:coral_fan_hang", "", 4166, 7, "blocks/observer.png", 0xff3d6e86, false),
+ B_4167_8_coral_fan_hang("minecraft:coral_fan_hang", "", 4167, 8, "blocks/observer.png", 0xff3d6e86, false),
+ B_4168_9_coral_fan_hang("minecraft:coral_fan_hang", "", 4168, 9, "blocks/observer.png", 0xff3d6e86, false),
+ B_4169_10_coral_fan_hang("minecraft:coral_fan_hang", "", 4169, 10, "blocks/observer.png", 0xff3d6e86, false),
+ B_4170_11_coral_fan_hang("minecraft:coral_fan_hang", "", 4170, 11, "blocks/observer.png", 0xff3d6e86, false),
+ B_4171_12_coral_fan_hang("minecraft:coral_fan_hang", "", 4171, 12, "blocks/observer.png", 0xff3d6e86, false),
+ B_4172_13_coral_fan_hang("minecraft:coral_fan_hang", "", 4172, 13, "blocks/observer.png", 0xff3d6e86, false),
+ B_4173_14_coral_fan_hang("minecraft:coral_fan_hang", "", 4173, 14, "blocks/observer.png", 0xff3d6e86, false),
+ B_4174_15_coral_fan_hang("minecraft:coral_fan_hang", "", 4174, 15, "blocks/observer.png", 0xff3d6e86, false),
+ B_4175_0_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4175, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_4176_1_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4176, 1, "blocks/observer.png", 0xff3d6e86, false),
+ B_4177_2_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4177, 2, "blocks/observer.png", 0xff3d6e86, false),
+ B_4178_3_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4178, 3, "blocks/observer.png", 0xff3d6e86, false),
+ B_4179_4_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4179, 4, "blocks/observer.png", 0xff3d6e86, false),
+ B_4180_5_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4180, 5, "blocks/observer.png", 0xff3d6e86, false),
+ B_4181_6_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4181, 6, "blocks/observer.png", 0xff3d6e86, false),
+ B_4182_7_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4182, 7, "blocks/observer.png", 0xff3d6e86, false),
+ B_4183_8_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4183, 8, "blocks/observer.png", 0xff3d6e86, false),
+ B_4184_9_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4184, 9, "blocks/observer.png", 0xff3d6e86, false),
+ B_4185_10_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4185, 10, "blocks/observer.png", 0xff3d6e86, false),
+ B_4186_11_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4186, 11, "blocks/observer.png", 0xff3d6e86, false),
+ B_4187_12_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4187, 12, "blocks/observer.png", 0xff3d6e86, false),
+ B_4188_13_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4188, 13, "blocks/observer.png", 0xff3d6e86, false),
+ B_4189_14_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4189, 14, "blocks/observer.png", 0xff3d6e86, false),
+ B_4190_15_coral_fan_hang2("minecraft:coral_fan_hang2", "", 4190, 15, "blocks/observer.png", 0xff3d6e86, false),
+ B_4191_0_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4191, 0, "blocks/observer.png", 0xff3d6e86, false),
+ B_4192_1_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4192, 1, "blocks/observer.png", 0xff3d6e86, false),
+ B_4193_2_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4193, 2, "blocks/observer.png", 0xff3d6e86, false),
+ B_4194_3_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4194, 3, "blocks/observer.png", 0xff3d6e86, false),
+ B_4195_4_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4195, 4, "blocks/observer.png", 0xff3d6e86, false),
+ B_4196_5_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4196, 5, "blocks/observer.png", 0xff3d6e86, false),
+ B_4197_6_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4197, 6, "blocks/observer.png", 0xff3d6e86, false),
+ B_4198_7_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4198, 7, "blocks/observer.png", 0xff3d6e86, false),
+ B_4199_8_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4199, 8, "blocks/observer.png", 0xff3d6e86, false),
+ B_4200_9_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4200, 9, "blocks/observer.png", 0xff3d6e86, false),
+ B_4201_10_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4201, 10, "blocks/observer.png", 0xff3d6e86, false),
+ B_4202_11_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4202, 11, "blocks/observer.png", 0xff3d6e86, false),
+ B_4203_12_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4203, 12, "blocks/observer.png", 0xff3d6e86, false),
+ B_4204_13_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4204, 13, "blocks/observer.png", 0xff3d6e86, false),
+ B_4205_14_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4205, 14, "blocks/observer.png", 0xff3d6e86, false),
+ B_4206_15_coral_fan_hang3("minecraft:coral_fan_hang3", "", 4206, 15, "blocks/observer.png", 0xff3d6e86, false),
+ B_4207_0_kelp("minecraft:kelp", "", 4207, 0, "blocks/observer.png", 0xff04833e, false),
+ B_4208_1_kelp("minecraft:kelp", "", 4208, 1, "blocks/observer.png", 0xff04833e, false),
+ B_4209_2_kelp("minecraft:kelp", "", 4209, 2, "blocks/observer.png", 0xff04833e, false),
+ B_4210_3_kelp("minecraft:kelp", "", 4210, 3, "blocks/observer.png", 0xff04833e, false),
+ B_4211_4_kelp("minecraft:kelp", "", 4211, 4, "blocks/observer.png", 0xff04833e, false),
+ B_4212_5_kelp("minecraft:kelp", "", 4212, 5, "blocks/observer.png", 0xff04833e, false),
+ B_4213_6_kelp("minecraft:kelp", "", 4213, 6, "blocks/observer.png", 0xff04833e, false),
+ B_4214_7_kelp("minecraft:kelp", "", 4214, 7, "blocks/observer.png", 0xff04833e, false),
+ B_4215_8_kelp("minecraft:kelp", "", 4215, 8, "blocks/observer.png", 0xff04833e, false),
+ B_4216_9_kelp("minecraft:kelp", "", 4216, 9, "blocks/observer.png", 0xff04833e, false),
+ B_4217_10_kelp("minecraft:kelp", "", 4217, 10, "blocks/observer.png", 0xff04833e, false),
+ B_4218_11_kelp("minecraft:kelp", "", 4218, 11, "blocks/observer.png", 0xff04833e, false),
+ B_4219_12_kelp("minecraft:kelp", "", 4219, 12, "blocks/observer.png", 0xff04833e, false),
+ B_4220_13_kelp("minecraft:kelp", "", 4220, 13, "blocks/observer.png", 0xff04833e, false),
+ B_4221_14_kelp("minecraft:kelp", "", 4221, 14, "blocks/observer.png", 0xff04833e, false),
+ B_4222_15_kelp("minecraft:kelp", "", 4222, 15, "blocks/observer.png", 0xff04833e, false),
+ B_4223_0_dried_kelp_block("minecraft:dried_kelp_block", "", 4223, 0, "blocks/observer.png", 0xff044b4b, false),
+ B_4224_0_acacia_button("minecraft:acacia_button", "", 4224, 0, "blocks/observer.png", 0x5f934f39, false),
+ B_4225_1_acacia_button("minecraft:acacia_button", "", 4225, 1, "blocks/observer.png", 0x5f934f39, false),
+ B_4226_2_acacia_button("minecraft:acacia_button", "", 4226, 2, "blocks/observer.png", 0x5f934f39, false),
+ B_4227_3_acacia_button("minecraft:acacia_button", "", 4227, 3, "blocks/observer.png", 0x5f934f39, false),
+ B_4228_4_acacia_button("minecraft:acacia_button", "", 4228, 4, "blocks/observer.png", 0x5f934f39, false),
+ B_4229_5_acacia_button("minecraft:acacia_button", "", 4229, 5, "blocks/observer.png", 0x5f934f39, false),
+ B_4230_6_acacia_button("minecraft:acacia_button", "", 4230, 6, "blocks/observer.png", 0x5f934f39, false),
+ B_4231_7_acacia_button("minecraft:acacia_button", "", 4231, 7, "blocks/observer.png", 0x5f934f39, false),
+ B_4232_8_acacia_button("minecraft:acacia_button", "", 4232, 8, "blocks/observer.png", 0x5f934f39, false),
+ B_4233_9_acacia_button("minecraft:acacia_button", "", 4233, 9, "blocks/observer.png", 0x5f934f39, false),
+ B_4234_10_acacia_button("minecraft:acacia_button", "", 4234, 10, "blocks/observer.png", 0x5f934f39, false),
+ B_4235_11_acacia_button("minecraft:acacia_button", "", 4235, 11, "blocks/observer.png", 0x5f934f39, false),
+ B_4236_12_acacia_button("minecraft:acacia_button", "", 4236, 12, "blocks/observer.png", 0x5f934f39, false),
+ B_4237_13_acacia_button("minecraft:acacia_button", "", 4237, 13, "blocks/observer.png", 0x5f934f39, false),
+ B_4238_14_acacia_button("minecraft:acacia_button", "", 4238, 14, "blocks/observer.png", 0x5f934f39, false),
+ B_4239_15_acacia_button("minecraft:acacia_button", "", 4239, 15, "blocks/observer.png", 0x5f934f39, false),
+ B_4240_0_birch_button("minecraft:birch_button", "", 4240, 0, "blocks/observer.png", 0xffdabd8d, false),
+ B_4241_1_birch_button("minecraft:birch_button", "", 4241, 1, "blocks/observer.png", 0xffdabd8d, false),
+ B_4242_2_birch_button("minecraft:birch_button", "", 4242, 2, "blocks/observer.png", 0xffdabd8d, false),
+ B_4243_3_birch_button("minecraft:birch_button", "", 4243, 3, "blocks/observer.png", 0xffdabd8d, false),
+ B_4244_4_birch_button("minecraft:birch_button", "", 4244, 4, "blocks/observer.png", 0xffdabd8d, false),
+ B_4245_5_birch_button("minecraft:birch_button", "", 4245, 5, "blocks/observer.png", 0xffdabd8d, false),
+ B_4246_6_birch_button("minecraft:birch_button", "", 4246, 6, "blocks/observer.png", 0xffdabd8d, false),
+ B_4247_7_birch_button("minecraft:birch_button", "", 4247, 7, "blocks/observer.png", 0xffdabd8d, false),
+ B_4248_8_birch_button("minecraft:birch_button", "", 4248, 8, "blocks/observer.png", 0xffdabd8d, false),
+ B_4249_9_birch_button("minecraft:birch_button", "", 4249, 9, "blocks/observer.png", 0xffdabd8d, false),
+ B_4250_10_birch_button("minecraft:birch_button", "", 4250, 10, "blocks/observer.png", 0xffdabd8d, false),
+ B_4251_11_birch_button("minecraft:birch_button", "", 4251, 11, "blocks/observer.png", 0xffdabd8d, false),
+ B_4252_12_birch_button("minecraft:birch_button", "", 4252, 12, "blocks/observer.png", 0xffdabd8d, false),
+ B_4253_13_birch_button("minecraft:birch_button", "", 4253, 13, "blocks/observer.png", 0xffdabd8d, false),
+ B_4254_14_birch_button("minecraft:birch_button", "", 4254, 14, "blocks/observer.png", 0xffdabd8d, false),
+ B_4255_15_birch_button("minecraft:birch_button", "", 4255, 15, "blocks/observer.png", 0xffdabd8d, false),
+ B_4256_0_dark_oak_button("minecraft:dark_oak_button", "", 4256, 0, "blocks/observer.png", 0xff2d2213, false),
+ B_4257_1_dark_oak_button("minecraft:dark_oak_button", "", 4257, 1, "blocks/observer.png", 0xff2d2213, false),
+ B_4258_2_dark_oak_button("minecraft:dark_oak_button", "", 4258, 2, "blocks/observer.png", 0xff2d2213, false),
+ B_4259_3_dark_oak_button("minecraft:dark_oak_button", "", 4259, 3, "blocks/observer.png", 0xff2d2213, false),
+ B_4260_4_dark_oak_button("minecraft:dark_oak_button", "", 4260, 4, "blocks/observer.png", 0xff2d2213, false),
+ B_4261_5_dark_oak_button("minecraft:dark_oak_button", "", 4261, 5, "blocks/observer.png", 0xff2d2213, false),
+ B_4262_6_dark_oak_button("minecraft:dark_oak_button", "", 4262, 6, "blocks/observer.png", 0xff2d2213, false),
+ B_4263_7_dark_oak_button("minecraft:dark_oak_button", "", 4263, 7, "blocks/observer.png", 0xff2d2213, false),
+ B_4264_8_dark_oak_button("minecraft:dark_oak_button", "", 4264, 8, "blocks/observer.png", 0xff2d2213, false),
+ B_4265_9_dark_oak_button("minecraft:dark_oak_button", "", 4265, 9, "blocks/observer.png", 0xff2d2213, false),
+ B_4266_10_dark_oak_button("minecraft:dark_oak_button", "", 4266, 10, "blocks/observer.png", 0xff2d2213, false),
+ B_4267_11_dark_oak_button("minecraft:dark_oak_button", "", 4267, 11, "blocks/observer.png", 0xff2d2213, false),
+ B_4268_12_dark_oak_button("minecraft:dark_oak_button", "", 4268, 12, "blocks/observer.png", 0xff2d2213, false),
+ B_4269_13_dark_oak_button("minecraft:dark_oak_button", "", 4269, 13, "blocks/observer.png", 0xff2d2213, false),
+ B_4270_14_dark_oak_button("minecraft:dark_oak_button", "", 4270, 14, "blocks/observer.png", 0xff2d2213, false),
+ B_4271_15_dark_oak_button("minecraft:dark_oak_button", "", 4271, 15, "blocks/observer.png", 0xff2d2213, false),
+ B_4272_0_jungle_button("minecraft:jungle_button", "", 4272, 0, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4273_1_jungle_button("minecraft:jungle_button", "", 4273, 1, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4274_2_jungle_button("minecraft:jungle_button", "", 4274, 2, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4275_3_jungle_button("minecraft:jungle_button", "", 4275, 3, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4276_4_jungle_button("minecraft:jungle_button", "", 4276, 4, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4277_5_jungle_button("minecraft:jungle_button", "", 4277, 5, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4278_6_jungle_button("minecraft:jungle_button", "", 4278, 6, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4279_7_jungle_button("minecraft:jungle_button", "", 4279, 7, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4280_8_jungle_button("minecraft:jungle_button", "", 4280, 8, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4281_9_jungle_button("minecraft:jungle_button", "", 4281, 9, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4282_10_jungle_button("minecraft:jungle_button", "", 4282, 10, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4283_11_jungle_button("minecraft:jungle_button", "", 4283, 11, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4284_12_jungle_button("minecraft:jungle_button", "", 4284, 12, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4285_13_jungle_button("minecraft:jungle_button", "", 4285, 13, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4286_14_jungle_button("minecraft:jungle_button", "", 4286, 14, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4287_15_jungle_button("minecraft:jungle_button", "", 4287, 15, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4288_0_spruce_button("minecraft:spruce_button", "", 4288, 0, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4289_1_spruce_button("minecraft:spruce_button", "", 4289, 1, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4290_2_spruce_button("minecraft:spruce_button", "", 4290, 2, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4291_3_spruce_button("minecraft:spruce_button", "", 4291, 3, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4292_4_spruce_button("minecraft:spruce_button", "", 4292, 4, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4293_5_spruce_button("minecraft:spruce_button", "", 4293, 5, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4294_6_spruce_button("minecraft:spruce_button", "", 4294, 6, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4295_7_spruce_button("minecraft:spruce_button", "", 4295, 7, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4296_8_spruce_button("minecraft:spruce_button", "", 4296, 8, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4297_9_spruce_button("minecraft:spruce_button", "", 4297, 9, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4298_10_spruce_button("minecraft:spruce_button", "", 4298, 10, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4299_11_spruce_button("minecraft:spruce_button", "", 4299, 11, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4300_12_spruce_button("minecraft:spruce_button", "", 4300, 12, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4301_13_spruce_button("minecraft:spruce_button", "", 4301, 13, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4302_14_spruce_button("minecraft:spruce_button", "", 4302, 14, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4303_15_spruce_button("minecraft:spruce_button", "", 4303, 15, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4304_0_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4304, 0, "blocks/observer.png", 0xff934f39, false),
+ B_4305_1_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4305, 1, "blocks/observer.png", 0xff934f39, false),
+ B_4306_2_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4306, 2, "blocks/observer.png", 0xff934f39, false),
+ B_4307_3_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4307, 3, "blocks/observer.png", 0xff934f39, false),
+ B_4308_4_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4308, 4, "blocks/observer.png", 0xff934f39, false),
+ B_4309_5_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4309, 5, "blocks/observer.png", 0xff934f39, false),
+ B_4310_6_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4310, 6, "blocks/observer.png", 0xff934f39, false),
+ B_4311_7_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4311, 7, "blocks/observer.png", 0xff934f39, false),
+ B_4312_8_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4312, 8, "blocks/observer.png", 0xff934f39, false),
+ B_4313_9_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4313, 9, "blocks/observer.png", 0xff934f39, false),
+ B_4314_10_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4314, 10, "blocks/observer.png", 0xff934f39, false),
+ B_4315_11_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4315, 11, "blocks/observer.png", 0xff934f39, false),
+ B_4316_12_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4316, 12, "blocks/observer.png", 0xff934f39, false),
+ B_4317_13_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4317, 13, "blocks/observer.png", 0xff934f39, false),
+ B_4318_14_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4318, 14, "blocks/observer.png", 0xff934f39, false),
+ B_4319_15_acacia_trapdoor("minecraft:acacia_trapdoor", "", 4319, 15, "blocks/observer.png", 0xff934f39, false),
+ B_4320_0_birch_trapdoor("minecraft:birch_trapdoor", "", 4320, 0, "blocks/observer.png", 0xffdabd8d, false),
+ B_4321_1_birch_trapdoor("minecraft:birch_trapdoor", "", 4321, 1, "blocks/observer.png", 0xffdabd8d, false),
+ B_4322_2_birch_trapdoor("minecraft:birch_trapdoor", "", 4322, 2, "blocks/observer.png", 0xffdabd8d, false),
+ B_4323_3_birch_trapdoor("minecraft:birch_trapdoor", "", 4323, 3, "blocks/observer.png", 0xffdabd8d, false),
+ B_4324_4_birch_trapdoor("minecraft:birch_trapdoor", "", 4324, 4, "blocks/observer.png", 0xffdabd8d, false),
+ B_4325_5_birch_trapdoor("minecraft:birch_trapdoor", "", 4325, 5, "blocks/observer.png", 0xffdabd8d, false),
+ B_4326_6_birch_trapdoor("minecraft:birch_trapdoor", "", 4326, 6, "blocks/observer.png", 0xffdabd8d, false),
+ B_4327_7_birch_trapdoor("minecraft:birch_trapdoor", "", 4327, 7, "blocks/observer.png", 0xffdabd8d, false),
+ B_4328_8_birch_trapdoor("minecraft:birch_trapdoor", "", 4328, 8, "blocks/observer.png", 0xffdabd8d, false),
+ B_4329_9_birch_trapdoor("minecraft:birch_trapdoor", "", 4329, 9, "blocks/observer.png", 0xffdabd8d, false),
+ B_4330_10_birch_trapdoor("minecraft:birch_trapdoor", "", 4330, 10, "blocks/observer.png", 0xffdabd8d, false),
+ B_4331_11_birch_trapdoor("minecraft:birch_trapdoor", "", 4331, 11, "blocks/observer.png", 0xffdabd8d, false),
+ B_4332_12_birch_trapdoor("minecraft:birch_trapdoor", "", 4332, 12, "blocks/observer.png", 0xffdabd8d, false),
+ B_4333_13_birch_trapdoor("minecraft:birch_trapdoor", "", 4333, 13, "blocks/observer.png", 0xffdabd8d, false),
+ B_4334_14_birch_trapdoor("minecraft:birch_trapdoor", "", 4334, 14, "blocks/observer.png", 0xffdabd8d, false),
+ B_4335_15_birch_trapdoor("minecraft:birch_trapdoor", "", 4335, 15, "blocks/observer.png", 0xffdabd8d, false),
+ B_4336_0_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4336, 0, "blocks/observer.png", 0xff2d2213, false),
+ B_4337_1_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4337, 1, "blocks/observer.png", 0xff2d2213, false),
+ B_4338_2_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4338, 2, "blocks/observer.png", 0xff2d2213, false),
+ B_4339_3_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4339, 3, "blocks/observer.png", 0xff2d2213, false),
+ B_4340_4_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4340, 4, "blocks/observer.png", 0xff2d2213, false),
+ B_4341_5_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4341, 5, "blocks/observer.png", 0xff2d2213, false),
+ B_4342_6_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4342, 6, "blocks/observer.png", 0xff2d2213, false),
+ B_4343_7_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4343, 7, "blocks/observer.png", 0xff2d2213, false),
+ B_4344_8_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4344, 8, "blocks/observer.png", 0xff2d2213, false),
+ B_4345_9_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4345, 9, "blocks/observer.png", 0xff2d2213, false),
+ B_4346_10_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4346, 10, "blocks/observer.png", 0xff2d2213, false),
+ B_4347_11_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4347, 11, "blocks/observer.png", 0xff2d2213, false),
+ B_4348_12_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4348, 12, "blocks/observer.png", 0xff2d2213, false),
+ B_4349_13_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4349, 13, "blocks/observer.png", 0xff2d2213, false),
+ B_4350_14_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4350, 14, "blocks/observer.png", 0xff2d2213, false),
+ B_4351_15_dark_oak_trapdoor("minecraft:dark_oak_trapdoor", "", 4351, 15, "blocks/observer.png", 0xff2d2213, false),
+ B_4352_0_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4352, 0, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4353_1_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4353, 1, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4354_2_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4354, 2, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4355_3_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4355, 3, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4356_4_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4356, 4, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4357_5_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4357, 5, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4358_6_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4358, 6, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4359_7_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4359, 7, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4360_8_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4360, 8, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4361_9_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4361, 9, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4362_10_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4362, 10, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4363_11_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4363, 11, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4364_12_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4364, 12, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4365_13_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4365, 13, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4366_14_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4366, 14, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4367_15_jungle_trapdoor("minecraft:jungle_trapdoor", "", 4367, 15, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4368_0_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4368, 0, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4369_1_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4369, 1, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4370_2_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4370, 2, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4371_3_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4371, 3, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4372_4_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4372, 4, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4373_5_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4373, 5, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4374_6_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4374, 6, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4375_7_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4375, 7, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4376_8_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4376, 8, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4377_9_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4377, 9, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4378_10_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4378, 10, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4379_11_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4379, 11, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4380_12_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4380, 12, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4381_13_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4381, 13, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4382_14_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4382, 14, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4383_15_spruce_trapdoor("minecraft:spruce_trapdoor", "", 4383, 15, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4384_0_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4384, 0, "blocks/observer.png", 0xff934f39, false),
+ B_4385_1_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4385, 1, "blocks/observer.png", 0xff934f39, false),
+ B_4386_2_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4386, 2, "blocks/observer.png", 0xff934f39, false),
+ B_4387_3_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4387, 3, "blocks/observer.png", 0xff934f39, false),
+ B_4388_4_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4388, 4, "blocks/observer.png", 0xff934f39, false),
+ B_4389_5_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4389, 5, "blocks/observer.png", 0xff934f39, false),
+ B_4390_6_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4390, 6, "blocks/observer.png", 0xff934f39, false),
+ B_4391_7_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4391, 7, "blocks/observer.png", 0xff934f39, false),
+ B_4392_8_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4392, 8, "blocks/observer.png", 0xff934f39, false),
+ B_4393_9_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4393, 9, "blocks/observer.png", 0xff934f39, false),
+ B_4394_10_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4394, 10, "blocks/observer.png", 0xff934f39, false),
+ B_4395_11_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4395, 11, "blocks/observer.png", 0xff934f39, false),
+ B_4396_12_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4396, 12, "blocks/observer.png", 0xff934f39, false),
+ B_4397_13_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4397, 13, "blocks/observer.png", 0xff934f39, false),
+ B_4398_14_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4398, 14, "blocks/observer.png", 0xff934f39, false),
+ B_4399_15_acacia_pressure_plate("minecraft:acacia_pressure_plate", "", 4399, 15, "blocks/observer.png", 0xff934f39, false),
+ B_4400_0_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4400, 0, "blocks/observer.png", 0xffdabd8d, false),
+ B_4401_1_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4401, 1, "blocks/observer.png", 0xffdabd8d, false),
+ B_4402_2_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4402, 2, "blocks/observer.png", 0xffdabd8d, false),
+ B_4403_3_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4403, 3, "blocks/observer.png", 0xffdabd8d, false),
+ B_4404_4_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4404, 4, "blocks/observer.png", 0xffdabd8d, false),
+ B_4405_5_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4405, 5, "blocks/observer.png", 0xffdabd8d, false),
+ B_4406_6_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4406, 6, "blocks/observer.png", 0xffdabd8d, false),
+ B_4407_7_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4407, 7, "blocks/observer.png", 0xffdabd8d, false),
+ B_4408_8_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4408, 8, "blocks/observer.png", 0xffdabd8d, false),
+ B_4409_9_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4409, 9, "blocks/observer.png", 0xffdabd8d, false),
+ B_4410_10_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4410, 10, "blocks/observer.png", 0xffdabd8d, false),
+ B_4411_11_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4411, 11, "blocks/observer.png", 0xffdabd8d, false),
+ B_4412_12_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4412, 12, "blocks/observer.png", 0xffdabd8d, false),
+ B_4413_13_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4413, 13, "blocks/observer.png", 0xffdabd8d, false),
+ B_4414_14_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4414, 14, "blocks/observer.png", 0xffdabd8d, false),
+ B_4415_15_birch_pressure_plate("minecraft:birch_pressure_plate", "", 4415, 15, "blocks/observer.png", 0xffdabd8d, false),
+ B_4416_0_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4416, 0, "blocks/observer.png", 0xff2d2213, false),
+ B_4417_1_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4417, 1, "blocks/observer.png", 0xff2d2213, false),
+ B_4418_2_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4418, 2, "blocks/observer.png", 0xff2d2213, false),
+ B_4419_3_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4419, 3, "blocks/observer.png", 0xff2d2213, false),
+ B_4420_4_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4420, 4, "blocks/observer.png", 0xff2d2213, false),
+ B_4421_5_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4421, 5, "blocks/observer.png", 0xff2d2213, false),
+ B_4422_6_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4422, 6, "blocks/observer.png", 0xff2d2213, false),
+ B_4423_7_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4423, 7, "blocks/observer.png", 0xff2d2213, false),
+ B_4424_8_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4424, 8, "blocks/observer.png", 0xff2d2213, false),
+ B_4425_9_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4425, 9, "blocks/observer.png", 0xff2d2213, false),
+ B_4426_10_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4426, 10, "blocks/observer.png", 0xff2d2213, false),
+ B_4427_11_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4427, 11, "blocks/observer.png", 0xff2d2213, false),
+ B_4428_12_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4428, 12, "blocks/observer.png", 0xff2d2213, false),
+ B_4429_13_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4429, 13, "blocks/observer.png", 0xff2d2213, false),
+ B_4430_14_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4430, 14, "blocks/observer.png", 0xff2d2213, false),
+ B_4431_15_dark_oak_pressure_plate("minecraft:dark_oak_pressure_plate", "", 4431, 15, "blocks/observer.png", 0xff2d2213, false),
+ B_4432_0_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4432, 0, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4433_1_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4433, 1, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4434_2_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4434, 2, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4435_3_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4435, 3, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4436_4_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4436, 4, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4437_5_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4437, 5, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4438_6_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4438, 6, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4439_7_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4439, 7, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4440_8_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4440, 8, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4441_9_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4441, 9, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4442_10_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4442, 10, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4443_11_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4443, 11, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4444_12_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4444, 12, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4445_13_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4445, 13, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4446_14_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4446, 14, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4447_15_jungle_pressure_plate("minecraft:jungle_pressure_plate", "", 4447, 15, "blocks/observer.png", 0xffBa7d5d, false),
+ B_4448_0_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4448, 0, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4449_1_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4449, 1, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4450_2_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4450, 2, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4451_3_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4451, 3, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4452_4_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4452, 4, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4453_5_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4453, 5, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4454_6_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4454, 6, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4455_7_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4455, 7, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4456_8_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4456, 8, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4457_9_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4457, 9, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4458_10_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4458, 10, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4459_11_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4459, 11, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4460_12_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4460, 12, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4461_13_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4461, 13, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4462_14_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4462, 14, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4463_15_spruce_pressure_plate("minecraft:spruce_pressure_plate", "", 4463, 15, "blocks/observer.png", 0xff5a3d0d, false),
+ B_4464_0_carved_pumpkin("minecraft:carved_pumpkin", "", 4464, 0, "blocks/observer.png", 0xffc07615, false),
+ B_4465_1_carved_pumpkin("minecraft:carved_pumpkin", "", 4465, 1, "blocks/observer.png", 0xffc07615, false),
+ B_4466_2_carved_pumpkin("minecraft:carved_pumpkin", "", 4466, 2, "blocks/observer.png", 0xffc07615, false),
+ B_4467_3_carved_pumpkin("minecraft:carved_pumpkin", "", 4467, 3, "blocks/observer.png", 0xffc07615, false),
+ B_4468_0_sea_pickle("minecraft:sea_pickle", "", 4468, 0, "blocks/observer.png", 0xff10C38e, false),
+ B_4469_1_sea_pickle("minecraft:sea_pickle", "", 4469, 1, "blocks/observer.png", 0xff10C38e, false),
+ B_4470_2_sea_pickle("minecraft:sea_pickle", "", 4470, 2, "blocks/observer.png", 0xff10C38e, false),
+ B_4471_3_sea_pickle("minecraft:sea_pickle", "", 4471, 3, "blocks/observer.png", 0xff10C38e, false),
+ B_4472_4_sea_pickle("minecraft:sea_pickle", "", 4472, 4, "blocks/observer.png", 0xff10C38e, false),
+ B_4473_5_sea_pickle("minecraft:sea_pickle", "", 4473, 5, "blocks/observer.png", 0xff10C38e, false),
+ B_4474_6_sea_pickle("minecraft:sea_pickle", "", 4474, 6, "blocks/observer.png", 0xff10C38e, false),
+ B_4475_7_sea_pickle("minecraft:sea_pickle", "", 4475, 7, "blocks/observer.png", 0xff10C38e, false);
+
+ private static final Map byDataName = new HashMap<>();
+ private static final SparseArray blockMap;
+ private static final Map nameService;
+ private static final Map resolver;
+
+ static {
+ blockMap = new SparseArray<>();
+ nameService = new HashMap<>(256);
+ resolver = new HashMap<>(256);
+ KnownBlockRepr[] subMap;
+ KnownBlockRepr[] subMap2;
+ for (KnownBlockRepr b : KnownBlockRepr.values()) {
+ subMap = blockMap.get(b.id);
+ if (subMap == null) {
+ subMap = new KnownBlockRepr[16];
+ blockMap.put(b.id, subMap);
+ }
+ subMap[b.subId] = b;
+ if (b.subId == 0) byDataName.put(b.identifier, b);
+ byDataName.put(b.identifier + "@" + b.subName, b);
+ nameService.put(b.identifier, b.id);
+ subMap2 = resolver.get(b.identifier);
+ if (subMap2 == null) {
+ subMap2 = new KnownBlockRepr[16];
+ resolver.put(b.identifier, subMap2);
+ }
+ subMap2[b.subId] = b;
+ }
+ }
+
+ public final int id, subId;
+ public final String identifier, subName;
+ public final String texPath;
+ public final int color;
+ public final boolean hasBiomeShading;
+ public Bitmap bitmap;
+
+ KnownBlockRepr(String identifier, String subName, int id, int subId, String texPath, int color, boolean hasBiomeShading) {
+ this.id = id;
+ this.subId = subId;
+ this.identifier = identifier;
+ this.subName = subName;
+ this.texPath = texPath;
+ this.color = color;
+ this.hasBiomeShading = hasBiomeShading;
+ }
+
+ public static KnownBlockRepr getByDataName(String dataName) {
+ return byDataName.get(dataName);
+ }
+
+ public static void loadBitmaps(AssetManager assetManager) throws IOException {
+ if (Math.random() < 1) return;
+ for (KnownBlockRepr b : KnownBlockRepr.values()) {
+ if (b.bitmap == null && b.texPath != null) {
+ try {
+ b.bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(assetManager.open(b.texPath)), 32, 32, false);
+ } catch (FileNotFoundException e) {
+ //TODO file-paths were generated from block names; some do not actually exist...
+ //Log.w("File not found! "+b.texPath);
+ } catch (Exception e) {
+ Log.d(KnownBlockRepr.class, e);
+ }
+ }
+ }
+ }
+
+ @NonNull
+ public static KnownBlockRepr getBestBlock(int id, int meta) {
+ KnownBlockRepr ret = getBlock(id, meta);
+ if (ret != null) return ret;
+ if (id >= 0) {
+ KnownBlockRepr[] subMap = blockMap.get(id);
+ if (subMap != null) {
+ ret = subMap[meta];
+ if (ret == null) {
+ for (int i = 0; i < 16; i++)
+ if (subMap[i] != null) return subMap[i];
+ }
+ }
+ }
+ return (ret == null) ? KnownBlockRepr.B_0_0_AIR : ret;
+ }
+
+ @Nullable
+ public static KnownBlockRepr getBlock(int id, int meta) {
+ if (id < 0) return null;
+ KnownBlockRepr[] subMap = blockMap.get(id);
+ if (subMap == null) return null;
+ else return subMap[meta];
+ }
+
+ public static KnownBlockRepr getBlock(int runtimeId) {
+ int id = runtimeId >>> 8;
+ int data = runtimeId & 0xf;
+ return getBlock(id, data);
+ }
+
+ public static int resolve(@NonNull String identifier) {
+ Integer i = nameService.get(identifier);
+ if (i == null) return 0;
+ return i;
+ }
+
+ @Nullable
+ public static KnownBlockRepr getBlockNew(@NonNull String identifier, int val) {
+ KnownBlockRepr[] subMap = resolver.get(identifier);
+ if (subMap == null) return null;
+ if (val >= 0 && val <= 15) return subMap[val];
+ return null;
+ }
+
+ @NonNull
+ public static KnownBlockRepr guessBlockNew(@NonNull String identifier) {
+ KnownBlockRepr[] subMap = resolver.get(identifier);
+ if (subMap == null) return B_0_0_AIR;
+ for (int i = 0; i <= 15; i++)
+ if (subMap[i] != null) return subMap[i];
+ return B_0_0_AIR;
+ }
+
+
+ public int getRuntimeId() {
+ return (id << 8) | subId;
+ }
+
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+
+ public int getVal() {
+ return subId;
+ }
+
+ @Override
+ public Bitmap getBitmap() {
+ return this.bitmap;
+ }
+
+ @NonNull
+ @Override
+ public NamedBitmapProvider getNamedBitmapProvider() {
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public String getBitmapDisplayName() {
+ return "ww123ww";
+ }
+
+ @NonNull
+ @Override
+ public String getBitmapDataName() {
+ return identifier + "@" + subName;
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/ListingBlock.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/ListingBlock.java
new file mode 100644
index 00000000..c35fed9c
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/ListingBlock.java
@@ -0,0 +1,559 @@
+package com.mithrilmania.blocktopograph.block;
+
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+
+public enum ListingBlock implements Serializable {
+ B_0_AIR("minecraft:air", 0, "Air", -1, 0, -1, 0, 0),
+ B_1_STONE("minecraft:stone", 1, "Stone", 0, 0, 98, 98, 98),
+ B_2_GRASS("minecraft:grass", 2, "Grass Block", 120, 0, 84, 86, 52),
+ B_3_DIRT("minecraft:dirt", 3, "Dirt", 240, 0, 105, 75, 52),
+ B_4_COBBLESTONE("minecraft:cobblestone", 4, "Cobblestone", 360, 0, 100, 99, 100),
+ B_5_PLANKS("minecraft:planks", 5, "Wood Planks", 480, 0, 126, 102, 61),
+ B_6_SAPLING("minecraft:sapling", 6, "Sapling", 600, 0, 75, 110, 41),
+ B_7_BEDROCK("minecraft:bedrock", 7, "Bedrock", 720, 0, 66, 66, 66),
+ B_8_FLOWING_WATER("minecraft:flowing_water", 8, "Water", 840, 0, 33, 62, 120),
+ B_9_WATER("minecraft:water", 9, "Stationary Water", 960, 0, 33, 62, 120),
+ B_10_FLOWING_LAVA("minecraft:flowing_lava", 10, "Lava", 1080, 0, 177, 84, 23),
+ B_11_LAVA("minecraft:lava", 11, "Stationary Lava", 1200, 0, 177, 84, 23),
+ B_12_SAND("minecraft:sand", 12, "Sand", 1320, 0, 171, 162, 127),
+ B_13_GRAVEL("minecraft:gravel", 13, "Gravel", 1440, 0, 103, 99, 99),
+ B_14_GOLD_ORE("minecraft:gold_ore", 14, "Gold Ore", 1560, 0, 112, 109, 98),
+ B_15_IRON_ORE("minecraft:iron_ore", 15, "Iron Ore", 1680, 0, 106, 102, 99),
+ B_16_COAL_ORE("minecraft:coal_ore", 16, "Coal Ore", 1800, 0, 91, 91, 91),
+ B_17_LOG("minecraft:log", 17, "Log", 1920, 0, 97, 76, 45),
+ B_18_LEAVES("minecraft:leaves", 18, "Leaves", 2040, 0, 29, 74, 9),
+ B_19_SPONGE("minecraft:sponge", 19, "Sponge", 2160, 0, 153, 150, 58),
+ B_20_GLASS("minecraft:glass", 20, "Glass", 2280, 0, 139, 169, 173),
+ B_21_LAPIS_ORE("minecraft:lapis_ore", 21, "Lapis Lazuli Ore", 0, 120, 78, 87, 104),
+ B_22_LAPIS_BLOCK("minecraft:lapis_block", 22, "Lapis Lazuli Block", 120, 120, 23, 53, 110),
+ B_23_DISPENSER("minecraft:dispenser", 23, "Dispenser", 240, 120, 91, 90, 90),
+ B_24_SANDSTONE("minecraft:sandstone", 24, "Sandstone", 360, 120, 171, 162, 126),
+ B_25_NOTEBLOCK("minecraft:noteblock", 25, "Note Block", 480, 120, 68, 45, 31),
+ B_26_BED("minecraft:bed", 26, "Bed", 600, 120, 142, 73, 65),
+ B_27_GOLDEN_RAIL("minecraft:golden_rail", 27, "Powered Rail", 720, 120, 134, 105, 70),
+ B_28_DETECTOR_RAIL("minecraft:detector_rail", 28, "Detector Rail", 840, 120, 119, 100, 85),
+ B_29_STICKY_PISTON("minecraft:sticky_piston", 29, "Sticky Piston", 960, 120, 90, 95, 76),
+ B_30_WEB("minecraft:web", 30, "Cobweb", 1080, 120, 158, 162, 163),
+ B_31_TALLGRASS("minecraft:tallgrass", 31, "Tall Grass", 1200, 120, 71, 109, 61),
+ B_32_DEADBUSH("minecraft:deadbush", 32, "Dead Bush", 1320, 120, 104, 77, 40),
+ B_33_PISTON("minecraft:piston", 33, "Piston", 1440, 120, 99, 89, 74),
+ B_34_PISTONARMCOLLISION("minecraft:pistonarmcollision", 34, "Piston Head", 1560, 120, 115, 98, 71),
+ B_35_WOOL("minecraft:wool", 35, "Wool", 1680, 120, 183, 185, 185),
+ //B_36_ELEMENT_0("minecraft:element_0", 36, "Unknown Element ", 1800, 120, 70, 62, 72),
+ B_37_YELLOW_FLOWER("minecraft:yellow_flower", 37, "Dandelion", 1920, 120, 151, 177, 45),
+ B_38_RED_FLOWER("minecraft:red_flower", 38, "Flower", 2040, 120, 122, 64, 37),
+ B_39_BROWN_MUSHROOM("minecraft:brown_mushroom", 39, "Brown Mushroom", 2160, 120, 151, 114, 90),
+ B_40_RED_MUSHROOM("minecraft:red_mushroom", 40, "Red Mushroom", 2280, 120, 212, 72, 67),
+ B_41_GOLD_BLOCK("minecraft:gold_block", 41, "Block of Gold", 0, 240, 192, 162, 48),
+ B_42_IRON_BLOCK("minecraft:iron_block", 42, "Block of Iron", 120, 240, 172, 171, 171),
+ B_43_DOUBLE_STONE_SLAB("minecraft:double_stone_slab", 43, "Double Stone Slab", 240, 240, 128, 128, 128),
+ B_44_STONE_SLAB("minecraft:stone_slab", 44, "Stone Slab", 360, 240, 135, 135, 136),
+ B_45_BRICK_BLOCK("minecraft:brick_block", 45, "Brick Block", 480, 240, 118, 76, 65),
+ B_46_TNT("minecraft:tnt", 46, "TNT", 600, 240, 132, 61, 56),
+ B_47_BOOKSHELF("minecraft:bookshelf", 47, "Bookshelf", 720, 240, 105, 85, 52),
+ B_48_MOSSY_COBBLESTONE("minecraft:mossy_cobblestone", 48, "Mossy Cobblestone", 840, 240, 86, 93, 74),
+ B_49_OBSIDIAN("minecraft:obsidian", 49, "Obsidian", 960, 240, 11, 8, 19),
+ B_50_TORCH("minecraft:torch", 50, "Torch", 1080, 240, 147, 121, 65),
+ B_51_FIRE("minecraft:fire", 51, "Fire", 1200, 240, 206, 126, 39),
+ B_52_MOB_SPAWNER("minecraft:mob_spawner", 52, "Spawner", 1320, 240, 28, 36, 48),
+ B_53_OAK_STAIRS("minecraft:oak_stairs", 53, "Oak Stairs", 1440, 240, 131, 105, 64),
+ B_54_CHEST("minecraft:chest", 54, "Chest", 1560, 240, 93, 69, 31),
+ B_55_REDSTONE_WIRE("minecraft:redstone_wire", 55, "Redstone Wire", 1680, 240, 48, 0, 0),
+ B_56_DIAMOND_ORE("minecraft:diamond_ore", 56, "Diamond Ore", 1800, 240, 98, 111, 110),
+ B_57_DIAMOND_BLOCK("minecraft:diamond_block", 57, "Block of Diamond", 1920, 240, 75, 185, 178),
+ B_58_CRAFTING_TABLE("minecraft:crafting_table", 58, "Crafting Table", 2040, 240, 96, 71, 44),
+ B_59_WHEAT("minecraft:wheat", 59, "Wheat Crops", 2160, 240, 169, 153, 74),
+ B_60_FARMLAND("minecraft:farmland", 60, "Farmland", 2280, 240, 108, 77, 53),
+ B_61_FURNACE("minecraft:furnace", 61, "Furnace", 0, 360, 82, 82, 82),
+ B_62_LIT_FURNACE("minecraft:lit_furnace", 62, "Burning Lit Furnace", 120, 360, 91, 88, 82),
+ B_63_STANDING_SIGN("minecraft:standing_sign", 63, "Oak Standing Sign", 240, 360, 107, 88, 53),
+ B_64_OAK_DOOR("minecraft:oak_door", 64, "Oak Door", 360, 360, 107, 84, 50),
+ B_65_LADDER("minecraft:ladder", 65, "Ladder", 480, 360, 98, 76, 43),
+ B_66_RAIL("minecraft:rail", 66, "Rail", 600, 360, 127, 115, 95),
+ B_67_STONE_STAIRS("minecraft:stone_stairs", 67, "Cobblestone Stairs", 720, 360, 103, 102, 104),
+ B_68_WALL_SIGN("minecraft:wall_sign", 68, "Oak Wall Sign", 840, 360, 115, 94, 56),
+ B_69_LEVER("minecraft:lever", 69, "Lever", 960, 360, 98, 96, 94),
+ B_70_STONE_PRESSURE_PLATE("minecraft:stone_pressure_plate", 70, "Stone Pressure Plate", 1080, 360, 117, 117, 117),
+ B_71_IRON_DOOR("minecraft:iron_door", 71, "Iron Door", 1200, 360, 153, 153, 154),
+ B_72_WOODEN_PRESSURE_PLATE("minecraft:wooden_pressure_plate", 72, "Oak Pressure Plate", 1320, 360, 148, 119, 71),
+ B_73_REDSTONE_ORE("minecraft:redstone_ore", 73, "Redstone Ore", 1440, 360, 104, 84, 84),
+ B_74_LIT_REDSTONE_ORE("minecraft:lit_redstone_ore", 74, "Glowing Redstone Ore", 1560, 360, 104, 84, 84),
+ B_75_UNLIT_REDSTONE_TORCH("minecraft:unlit_redstone_torch", 75, "Unlit Redstone Torch", 1680, 360, 98, 64, 40),
+ B_76_REDSTONE_TORCH("minecraft:redstone_torch", 76, "Redstone Torch", 1800, 360, 172, 64, 35),
+ B_77_STONE_BUTTON("minecraft:stone_button", 77, "Stone Button", 1920, 360, 102, 102, 102),
+ B_78_SNOW_LAYER("minecraft:snow_layer", 78, "Top Snow", 2040, 360, 226, 231, 231),
+ B_79_ICE("minecraft:ice", 79, "Ice", 2160, 360, 114, 144, 199),
+ B_80_SNOW("minecraft:snow", 80, "Snow", 2280, 360, 195, 199, 199),
+ B_81_CACTUS("minecraft:cactus", 81, "Cactus", 0, 480, 67, 100, 33),
+ B_82_CLAY("minecraft:clay", 82, "Clay", 120, 480, 126, 130, 140),
+ B_83_REEDS("minecraft:reeds", 83, "Sugar Cane", 240, 480, 71, 143, 40),
+ B_84_JUKEBOX("minecraft:jukebox", 84, "Jukebox", 360, 480, 70, 47, 33),
+ B_85_FENCE("minecraft:fence", 85, "Oak Fence", 480, 480, 125, 100, 60),
+ B_86_PUMPKIN("minecraft:pumpkin", 86, "Pumpkin", 600, 480, 153, 90, 18),
+ B_87_NETHERRACK("minecraft:netherrack", 87, "Netherrack", 720, 480, 76, 29, 29),
+ B_88_SOUL_SAND("minecraft:soul_sand", 88, "Soul Sand", 840, 480, 63, 48, 39),
+ B_89_GLOWSTONE("minecraft:glowstone", 89, "Glowstone", 960, 480, 134, 102, 66),
+ B_90_PORTAL("minecraft:portal", 90, "Portal", 1080, 480, 112, 15, 228),
+ B_91_LIT_PUMPKIN("minecraft:lit_pumpkin", 91, "Jack o'Lantern", 1200, 480, 158, 100, 26),
+ B_92_CAKE("minecraft:cake", 92, "Cake", 1320, 480, 184, 152, 137),
+ B_93_UNPOWERED_REPEATER("minecraft:unpowered_repeater", 93, "Redstone Repeater", 1440, 480, 128, 122, 119),
+ B_94_POWERED_REPEATER("minecraft:powered_repeater", 94, "Active Redstone Repeater", 1560, 480, 145, 121, 116),
+ B_95_INVISIBLEBEDROCK("minecraft:invisiblebedrock", 95, "Invisible Bedrock", -1, 0, -1, 0, 0),
+ B_96_WOODEN_TRAPDOOR("minecraft:wooden_trapdoor", 96, "Oak Trapdoor", 1680, 480, 96, 77, 43),
+ B_97_MONSTER_EGG("minecraft:monster_egg", 97, "Monster Egg", 1800, 480, 98, 98, 98),
+ B_98_STONEBRICK("minecraft:stonebrick", 98, "Stone Bricks", 1920, 480, 96, 95, 96),
+ B_99_BROWN_MUSHROOM_BLOCK("minecraft:brown_mushroom_block", 99, "Brown Mushroom Block", 2040, 480, 118, 88, 64),
+ B_100_RED_MUSHROOM_BLOCK("minecraft:red_mushroom_block", 100, "Red Mushroom Block", 2160, 480, 158, 36, 35),
+ B_101_IRON_BARS("minecraft:iron_bars", 101, "Iron Bars", 2280, 480, 102, 103, 101),
+ B_102_GLASS_PANE("minecraft:glass_pane", 102, "Glass Pane", 0, 600, 150, 178, 181),
+ B_103_MELON_BLOCK("minecraft:melon_block", 103, "Melon", 120, 600, 88, 114, 23),
+ B_104_PUMPKIN_STEM("minecraft:pumpkin_stem", 104, "Pumpkin Stem", 240, 600, 106, 94, 12),
+ B_105_MELON_STEM("minecraft:melon_stem", 105, "Melon Stem", 360, 600, 106, 94, 12),
+ B_106_VINE("minecraft:vine", 106, "Vines", 480, 600, 32, 82, 10),
+ B_107_FENCE_GATE("minecraft:fence_gate", 107, "Oak Fence Gate", 600, 600, 128, 103, 61),
+ B_108_BRICK_STAIRS("minecraft:brick_stairs", 108, "Brick Stairs", 720, 600, 122, 79, 68),
+ B_109_STONE_BRICK_STAIRS("minecraft:stone_brick_stairs", 109, "Stone Brick Stairs", 840, 600, 99, 98, 100),
+ B_110_MYCELIUM("minecraft:mycelium", 110, "Mycelium", 960, 600, 88, 71, 64),
+ B_111_WATERLILY("minecraft:waterlily", 111, "Lily Pad", 1080, 600, 16, 65, 24),
+ B_112_NETHER_BRICK_BLOCK("minecraft:nether_brick_block", 112, "Nether Brick Block", 1200, 600, 34, 17, 20),
+ B_113_NETHER_BRICK_FENCE("minecraft:nether_brick_fence", 113, "Nether Brick Fence", 1320, 600, 34, 17, 20),
+ B_114_NETHER_BRICK_STAIRS("minecraft:nether_brick_stairs", 114, "Nether Brick Stairs", 1440, 600, 35, 17, 21),
+ B_115_NETHER_WART("minecraft:nether_wart", 115, "Nether Wart", 1560, 600, 114, 17, 17),
+ B_116_ENCHANTING_TABLE("minecraft:enchanting_table", 116, "Enchantment Table", 1680, 600, 88, 76, 69),
+ B_117_BREWING_STAND("minecraft:brewing_stand", 117, "Brewing Stand", 1800, 600, 93, 82, 70),
+ B_118_CAULDRON("minecraft:cauldron", 118, "Cauldron", 1920, 600, 56, 55, 56),
+ B_119_END_PORTAL("minecraft:end_portal", 119, "End Portal", 2040, 600, 7, 14, 24),
+ B_120_END_PORTAL_FRAME("minecraft:end_portal_frame", 120, "End Portal Frame", 2160, 600, 100, 116, 89),
+ B_121_END_STONE("minecraft:end_stone", 121, "End Stone", 2280, 600, 172, 174, 124),
+ B_122_DRAGON_EGG("minecraft:dragon_egg", 122, "Dragon Egg", 0, 720, 10, 7, 12),
+ B_123_REDSTONE_LAMP("minecraft:redstone_lamp", 123, "Redstone Lamp ", 120, 720, 73, 42, 23),
+ B_124_LIT_REDSTONE_LAMP("minecraft:lit_redstone_lamp", 124, "Redstone Lamp ", 240, 720, 110, 78, 46),
+ B_125_DROPPER("minecraft:dropper", 125, "Dropper", 360, 720, 91, 90, 90),
+ B_126_ACTIVATOR_RAIL("minecraft:activator_rail", 126, "Activator Rail", 480, 720, 111, 83, 70),
+ B_127_COCOA("minecraft:cocoa", 127, "Cocoa", 600, 720, 116, 69, 31),
+ B_128_SANDSTONE_STAIRS("minecraft:sandstone_stairs", 128, "Sandstone Stairs", 720, 720, 177, 168, 132),
+ B_129_EMERALD_ORE("minecraft:emerald_ore", 129, "Emerald Ore", 840, 720, 92, 107, 97),
+ B_130_ENDER_CHEST("minecraft:ender_chest", 130, "Ender Chest", 960, 720, 26, 38, 38),
+ B_131_TRIPWIRE_HOOK("minecraft:tripwire_hook", 131, "Tripwire Hook", 1080, 720, 124, 107, 81),
+ B_132_TRIPWIRE("minecraft:tripwire", 132, "Tripwire", 1200, 720, 142, 142, 142),
+ B_133_EMERALD_BLOCK("minecraft:emerald_block", 133, "Block of Emerald", 1320, 720, 32, 159, 68),
+ B_134_SPRUCE_STAIRS("minecraft:spruce_stairs", 134, "Spruce Stairs", 1440, 720, 93, 68, 39),
+ B_135_BIRCH_STAIRS("minecraft:birch_stairs", 135, "Birch Stairs", 1560, 720, 155, 142, 99),
+ B_136_JUNGLE_STAIRS("minecraft:jungle_stairs", 136, "Jungle Stairs", 1680, 720, 129, 93, 65),
+ B_137_IMPULSE_COMMAND_BLOCK("minecraft:impulse_command_block", 137, "Impulse Command Block", 1800, 720, 140, 105, 83),
+ B_138_BEACON("minecraft:beacon", 138, "Beacon", 1920, 720, 103, 151, 152),
+ B_139_COBBLESTONE_WALL("minecraft:cobblestone_wall", 139, "Cobblestone Wall", 2040, 720, 99, 99, 100),
+ B_140_FLOWER_POT("minecraft:flower_pot", 140, "Flower Pot", 2160, 720, 94, 52, 41),
+ B_141_CARROTS("minecraft:carrots", 141, "Carrots", 2280, 720, 78, 123, 37),
+ B_142_POTATOES("minecraft:potatoes", 142, "Potatoes", 0, 840, 96, 161, 49),
+ B_143_WOODEN_BUTTON("minecraft:wooden_button", 143, "Oak Button", 120, 840, 134, 108, 65),
+ B_144_SKULL("minecraft:skull", 144, "Mob head", 240, 840, 61, 42, 28),
+ B_145_ANVIL("minecraft:anvil", 145, "Anvil", 360, 840, 57, 57, 57),
+ B_146_TRAPPED_CHEST("minecraft:trapped_chest", 146, "Trapped Chest", 480, 840, 93, 69, 31),
+ B_147_LIGHT_WEIGHTED_PRESSURE_PLATE("minecraft:light_weighted_pressure_plate", 147, "Weighted Pressure Plate ", 600, 840, 230, 197, 61),
+ B_148_HEAVY_WEIGHTED_PRESSURE_PLATE("minecraft:heavy_weighted_pressure_plate", 148, "Weighted Pressure Plate ", 720, 840, 208, 208, 208),
+ B_149_UNPOWERED_COMPARATOR("minecraft:unpowered_comparator", 149, "Redstone Comparator ", 840, 840, 132, 123, 119),
+ B_150_POWERED_COMPARATOR("minecraft:powered_comparator", 150, "Redstone Comparator ", 960, 840, 149, 122, 116),
+ B_151_DAYLIGHT_DETECTOR("minecraft:daylight_detector", 151, "Daylight Sensor", 1080, 840, 87, 76, 58),
+ B_152_REDSTONE_BLOCK("minecraft:redstone_block", 152, "Block of Redstone", 1200, 840, 138, 19, 4),
+ B_153_QUARTZ_ORE("minecraft:quartz_ore", 153, "Nether Quartz Ore", 1320, 840, 91, 50, 48),
+ B_154_HOPPER("minecraft:hopper", 154, "Hopper", 1440, 840, 60, 59, 60),
+ B_155_QUARTZ_BLOCK("minecraft:quartz_block", 155, "Block of Quartz", 1560, 840, 184, 180, 174),
+ B_156_QUARTZ_STAIRS("minecraft:quartz_stairs", 156, "Quartz Stairs", 1680, 840, 191, 186, 182),
+ B_157_DOUBLE_WOODEN_SLAB("minecraft:double_wooden_slab", 157, "Wooden Double Slab", 1800, 840, 126, 102, 61),
+ B_158_WOODEN_SLAB("minecraft:wooden_slab", 158, "Wooden Slab", 1920, 840, 133, 107, 64),
+ B_159_STAINED_HARDENED_CLAY("minecraft:stained_hardened_clay", 159, "Terracotta", 2040, 840, 164, 139, 126),
+ B_160_STAINED_GLASS_PANE("minecraft:stained_glass_pane", 160, "Stained Glass Pane", 2160, 840, 202, 202, 202),
+ B_161_LEAVES2("minecraft:leaves2", 161, "Acacia Leaves", 2280, 840, 29, 74, 9),
+ B_162_LOG2("minecraft:log2", 162, "Acacia Log", 0, 960, 94, 73, 59),
+ B_163_ACACIA_STAIRS("minecraft:acacia_stairs", 163, "Acacia Stairs", 120, 960, 136, 73, 41),
+ B_164_DARK_OAK_STAIRS("minecraft:dark_oak_stairs", 164, "Dark Oak Stairs", 240, 960, 54, 34, 16),
+ B_165_SLIME("minecraft:slime", 165, "Slime Block", 360, 960, 88, 152, 73),
+ B_166_GLOW_STICK("minecraft:glow_stick", 166, "Glow Stick", 480, 960, 175, 176, 178),
+ B_167_IRON_TRAPDOOR("minecraft:iron_trapdoor", 167, "Iron Trapdoor", 600, 960, 162, 161, 161),
+ B_168_PRISMARINE("minecraft:prismarine", 168, "Prismarine", 720, 960, 78, 128, 116),
+ B_169_SEALANTERN("minecraft:sealantern", 169, "Sea Lantern", 840, 960, 133, 155, 148),
+ B_170_HAY_BLOCK("minecraft:hay_block", 170, "Hay Bale", 960, 960, 130, 107, 22),
+ B_171_CARPET("minecraft:carpet", 171, "Carpet", 1080, 960, 218, 220, 221),
+ B_172_HARDENED_CLAY("minecraft:hardened_clay", 172, "Terracotta", 1200, 960, 120, 74, 54),
+ B_173_COAL_BLOCK("minecraft:coal_block", 173, "Block of Coal", 1320, 960, 12, 12, 12),
+ B_174_PACKED_ICE("minecraft:packed_ice", 174, "Packed Ice", 1440, 960, 112, 142, 198),
+ B_175_DOUBLE_PLANT("minecraft:double_plant", 175, "Sunflower", 1560, 960, 118, 154, 37),
+ B_176_STANDING_BANNER("minecraft:standing_banner", 176, "Standing Banner", 1680, 960, 140, 140, 138),
+ B_177_WALL_BANNER("minecraft:wall_banner", 177, "Wall Banner", 1800, 960, 142, 141, 140),
+ B_178_DAYLIGHT_DETECTOR_INVERTED("minecraft:daylight_detector_inverted", 178, "Inverted Daylight Detector", 1920, 960, 75, 73, 67),
+ B_179_RED_SANDSTONE("minecraft:red_sandstone", 179, "Red Sandstone", 2040, 960, 145, 77, 23),
+ B_180_RED_SANDSTONE_STAIRS("minecraft:red_sandstone_stairs", 180, "Red Sandstone Stairs", 2160, 960, 149, 80, 24),
+ B_181_DOUBLE_STONE_SLAB2("minecraft:double_stone_slab2", 181, "Double Red Sandstone Slab", 2280, 960, 145, 77, 23),
+ B_182_STONE_SLAB2("minecraft:stone_slab2", 182, "Red Sandstone Slab", 0, 1080, 153, 82, 25),
+ B_183_SPRUCE_FENCE_GATE("minecraft:spruce_fence_gate", 183, "Spruce Fence Gate", 120, 1080, 90, 67, 38),
+ B_184_BIRCH_FENCE_GATE("minecraft:birch_fence_gate", 184, "Birch Fence Gate", 240, 1080, 153, 139, 96),
+ B_185_JUNGLE_FENCE_GATE("minecraft:jungle_fence_gate", 185, "Jungle Fence Gate", 360, 1080, 127, 91, 63),
+ B_186_DARK_OAK_FENCE_GATE("minecraft:dark_oak_fence_gate", 186, "Dark Oak Fence Gate", 480, 1080, 52, 33, 15),
+ B_187_ACACIA_FENCE_GATE("minecraft:acacia_fence_gate", 187, "Acacia Fence Gate", 600, 1080, 134, 72, 40),
+ B_188_REPEATING_COMMAND_BLOCK("minecraft:repeating_command_block", 188, "Repeating Command Block", 720, 1080, 100, 86, 135),
+ B_189_CHAIN_COMMAND_BLOCK("minecraft:chain_command_block", 189, "Chain Command Block", 840, 1080, 102, 127, 116),
+ B_190_HARD_GLASS_PANE("minecraft:hard_glass_pane", 190, "Hardened Glass Pane", 960, 1080, 166, 195, 187),
+ B_191_HARD_STAINED_GLASS_PANE("minecraft:hard_stained_glass_pane", 191, "Hardened Stained Glass Pane", 1080, 1080, 198, 198, 198),
+ B_192_CHEMICAL_HEAT("minecraft:chemical_heat", 192, "Heat Block", 1200, 1080, 61, 45, 42),
+ B_193_SPRUCE_DOOR("minecraft:spruce_door", 193, "Spruce Door", 1320, 1080, 83, 63, 38),
+ B_194_BIRCH_DOOR("minecraft:birch_door", 194, "Birch Door", 1440, 1080, 163, 153, 119),
+ B_195_JUNGLE_DOOR("minecraft:jungle_door", 195, "Jungle Door", 1560, 1080, 125, 91, 64),
+ B_196_ACACIA_DOOR("minecraft:acacia_door", 196, "Acacia Door", 1680, 1080, 127, 72, 45),
+ B_197_DARK_OAK_DOOR("minecraft:dark_oak_door", 197, "Dark Oak Door", 1800, 1080, 58, 39, 19),
+ B_198_GRASS_PATH("minecraft:grass_path", 198, "Grass Path", 1920, 1080, 115, 88, 54),
+ B_199_FRAME("minecraft:frame", 199, "Item Frame", 2040, 1080, 125, 92, 60),
+ B_200_CHORUS_FLOWER("minecraft:chorus_flower", 200, "Chorus Flower", 2160, 1080, 127, 105, 127),
+ B_201_PURPUR_BLOCK("minecraft:purpur_block", 201, "Purpur Block", 2280, 1080, 133, 98, 133),
+ B_202_COLORED_TORCH_RG("minecraft:colored_torch_rg", 202, "Red Torch", 0, 1200, 137, 76, 53),
+ B_203_PURPUR_STAIRS("minecraft:purpur_stairs", 203, "Purpur Stairs", 120, 1200, 137, 102, 138),
+ B_204_COLORED_TORCH_BP("minecraft:colored_torch_bp", 204, "Blue Torch", 240, 1200, 97, 89, 97),
+ B_205_UNDYED_SHULKER_BOX("minecraft:undyed_shulker_box", 205, "Shulker Box ", 360, 1200, 100, 70, 100),
+ B_206_END_BRICKS("minecraft:end_bricks", 206, "End Stone Bricks", 480, 1200, 171, 175, 126),
+ B_207_FROSTED_ICE("minecraft:frosted_ice", 207, "Frosted Ice", 600, 1200, 114, 144, 199),
+ B_208_END_ROD("minecraft:end_rod", 208, "End Rod", 720, 1200, 169, 162, 153),
+ B_209_END_GATEWAY("minecraft:end_gateway", 209, "End Gateway", 840, 1200, 6, 15, 24),
+ B_213_MAGMA("minecraft:magma", 213, "Magma Block", 960, 1200, 112, 49, 24),
+ B_214_NETHER_WART_BLOCK("minecraft:nether_wart_block", 214, "Nether Wart Block", 1080, 1200, 90, 2, 2),
+ B_215_RED_NETHER_BRICK("minecraft:red_nether_brick", 215, "Red Nether Brick", 1200, 1200, 54, 5, 7),
+ B_216_BONE_BLOCK("minecraft:bone_block", 216, "Bone Block", 1320, 1200, 174, 171, 155),
+ B_217_STRUCTURE_VOID("minecraft:structure_void", 217, "Structure Void", 1440, 1200, 203, 0, 0),
+ B_218_SHULKER_BOX("minecraft:shulker_box", 218, "Shulker Box", 1560, 1200, 135, 139, 140),
+ B_219_PURPLE_GLAZED_TERRACOTTA("minecraft:purple_glazed_terracotta", 219, "Purple Glazed Terracotta", 1680, 1200, 87, 38, 122),
+ B_220_WHITE_GLAZED_TERRACOTTA("minecraft:white_glazed_terracotta", 220, "White Glazed Terracotta", 1800, 1200, 150, 168, 161),
+ B_221_ORANGE_GLAZED_TERRACOTTA("minecraft:orange_glazed_terracotta", 221, "Orange Glazed Terracotta", 1920, 1200, 123, 117, 74),
+ B_222_MAGENTA_GLAZED_TERRACOTTA("minecraft:magenta_glazed_terracotta", 222, "Magenta Glazed Terracotta", 2040, 1200, 165, 79, 153),
+ B_223_LIGHT_BLUE_GLAZED_TERRACOTTA("minecraft:light_blue_glazed_terracotta", 223, "Light Blue Glazed Terracotta", 2160, 1200, 74, 130, 167),
+ B_224_YELLOW_GLAZED_TERRACOTTA("minecraft:yellow_glazed_terracotta", 224, "Yellow Glazed Terracotta", 2280, 1200, 186, 152, 71),
+ B_225_LIME_GLAZED_TERRACOTTA("minecraft:lime_glazed_terracotta", 225, "Lime Glazed Terracotta", 0, 1320, 128, 156, 44),
+ B_226_PINK_GLAZED_TERRACOTTA("minecraft:pink_glazed_terracotta", 226, "Pink Glazed Terracotta", 120, 1320, 186, 122, 145),
+ B_227_GRAY_GLAZED_TERRACOTTA("minecraft:gray_glazed_terracotta", 227, "Gray Glazed Terracotta", 240, 1320, 65, 71, 74),
+ B_228_SILVER_GLAZED_TERRACOTTA("minecraft:silver_glazed_terracotta", 228, "Light Gray Glazed Terracotta", 360, 1320, 114, 131, 134),
+ B_229_CYAN_GLAZED_TERRACOTTA("minecraft:cyan_glazed_terracotta", 229, "Cyan Glazed Terracotta", 480, 1320, 41, 94, 100),
+ B_231_BLUE_GLAZED_TERRACOTTA("minecraft:blue_glazed_terracotta", 231, "Blue Glazed Terracotta", 600, 1320, 37, 51, 111),
+ B_232_BROWN_GLAZED_TERRACOTTA("minecraft:brown_glazed_terracotta", 232, "Brown Glazed Terracotta", 720, 1320, 95, 84, 69),
+ B_233_GREEN_GLAZED_TERRACOTTA("minecraft:green_glazed_terracotta", 233, "Green Glazed Terracotta", 840, 1320, 93, 113, 54),
+ B_234_RED_GLAZED_TERRACOTTA("minecraft:red_glazed_terracotta", 234, "Red Glazed Terracotta", 960, 1320, 144, 47, 42),
+ B_235_BLACK_GLAZED_TERRACOTTA("minecraft:black_glazed_terracotta", 235, "Black Glazed Terracotta", 1080, 1320, 53, 23, 25),
+ B_236_CONCRETE("minecraft:concrete", 236, "Concrete", 1200, 1320, 162, 167, 167),
+ B_237_CONCRETEPOWDER("minecraft:concretepowder", 237, "Concrete Powder", 1320, 1320, 177, 178, 178),
+ B_238_CHEMISTRY_TABLE("minecraft:chemistry_table", 238, "Compound Creator", 1440, 1320, 111, 103, 89),
+ B_239_UNDERWATER_TORCH("minecraft:underwater_torch", 239, "Underwater Torch", 1560, 1320, 80, 120, 110),
+ B_240_CHORUS_PLANT("minecraft:chorus_plant", 240, "Chorus Plant", 1680, 1320, 72, 44, 73),
+ B_241_STAINED_GLASS("minecraft:stained_glass", 241, "Stained Glass", 1800, 1320, 202, 202, 204),
+ B_242_CAMERA("minecraft:camera", 242, "Camera", 1920, 1320, 63, 51, 34),
+ B_243_PODZOL("minecraft:podzol", 243, "Podzol", 2040, 1320, 87, 61, 35),
+ B_244_BEETROOT("minecraft:beetroot", 244, "Beetroots", 2160, 1320, 101, 122, 40),
+ B_245_STONECUTTER("minecraft:stonecutter", 245, "Stonecutter", 2280, 1320, 90, 90, 90),
+ B_246_GLOWINGOBSIDIAN("minecraft:glowingobsidian", 246, "Glowing Obsidian", 0, 1440, 62, 2, 10),
+ B_247_NETHERREACTOR("minecraft:netherreactor", 247, "Nether Reactor Core", 120, 1440, 94, 134, 142),
+ B_248_INFO_UPDATE("minecraft:info_update", 248, "Update Game Block ", 240, 1440, 91, 88, 46),
+ B_249_INFO_UPDATE2("minecraft:info_update2", 249, "Update Game Block ", 360, 1440, 91, 87, 46),
+ B_250_MOVINGBLOCK("minecraft:movingblock", 250, "Block moved by Piston", -1, 0, -1, 0, 0),
+ B_251_OBSERVER("minecraft:observer", 251, "Observer", 480, 1440, 72, 72, 73),
+ B_252_STRUCTURE_BLOCK("minecraft:structure_block", 252, "Structure Block", 600, 1440, 68, 57, 69),
+ B_253_HARD_GLASS("minecraft:hard_glass", 253, "Hardened Glass", 720, 1440, 164, 193, 183),
+ B_254_HARD_STAINED_GLASS("minecraft:hard_stained_glass", 254, "Hardened Stained Glass", 840, 1440, 194, 194, 194),
+ B_255_RESERVED6("minecraft:reserved6", 255, "reserved6", 960, 1440, 91, 88, 46),
+ B_256_("minecraft:", 256, "", -1, 0, -1, 0, 0),
+ B_257_PRISMARINE_STAIRS("minecraft:prismarine_stairs", 257, "Prismarine Stairs", 1080, 1440, 80, 131, 119),
+ B_258_DARK_PRISMARINE_STAIRS("minecraft:dark_prismarine_stairs", 258, "Dark Prismarine Stairs", 1200, 1440, 42, 74, 62),
+ B_259_PRISMARINE_BRICKS_STAIRS("minecraft:prismarine_bricks_stairs", 259, "Prismarine Brick Stairs", 1320, 1440, 80, 138, 129),
+ B_260_STRIPPED_SPRUCE_LOG("minecraft:stripped_spruce_log", 260, "Stripped Spruce Log", 1440, 1440, 87, 67, 39),
+ B_261_STRIPPED_BIRCH_LOG("minecraft:stripped_birch_log", 261, "Stripped Birch Log", 1560, 1440, 152, 136, 91),
+ B_262_STRIPPED_JUNGLE_LOG("minecraft:stripped_jungle_log", 262, "Stripped Jungle Log", 1680, 1440, 132, 101, 65),
+ B_263_STRIPPED_ACACIA_LOG("minecraft:stripped_acacia_log", 263, "Stripped Acacia Log", 1800, 1440, 134, 72, 44),
+ B_264_STRIPPED_DARK_OAK_LOG("minecraft:stripped_dark_oak_log", 264, "Stripped Dark Oak Log", 1920, 1440, 66, 50, 31),
+ B_265_STRIPPED_OAK_LOG("minecraft:stripped_oak_log", 265, "Stripped Oak Log", 2040, 1440, 133, 108, 64),
+ B_266_BLUE_ICE("minecraft:blue_ice", 266, "Blue Ice", 2160, 1440, 95, 133, 196),
+ //B_267_ELEMENT_1("minecraft:element_1", 267, "Hydrogen", 2280, 1440, 117, 145, 87),
+//B_268_ELEMENT_2("minecraft:element_2", 268, "Helium", 0, 1560, 155, 116, 182),
+//B_269_ELEMENT_3("minecraft:element_3", 269, "Lithium", 120, 1560, 101, 123, 181),
+//B_270_ELEMENT_4("minecraft:element_4", 270, "Beryllium", 240, 1560, 92, 148, 162),
+//B_271_ELEMENT_5("minecraft:element_5", 271, "Boron", 360, 1560, 158, 130, 128),
+//B_272_ELEMENT_6("minecraft:element_6", 272, "Carbon", 480, 1560, 116, 144, 86),
+//B_273_ELEMENT_7("minecraft:element_7", 273, "Nitrogen", 600, 1560, 117, 145, 87),
+//B_274_ELEMENT_8("minecraft:element_8", 274, "Oxygen", 720, 1560, 117, 145, 87),
+//B_275_ELEMENT_9("minecraft:element_9", 275, "Fluorine", 840, 1560, 185, 136, 86),
+//B_276_ELEMENT_10("minecraft:element_10", 276, "Neon", 960, 1560, 155, 117, 182),
+//B_277_ELEMENT_11("minecraft:element_11", 277, "Sodium", 1080, 1560, 107, 127, 182),
+//B_278_ELEMENT_12("minecraft:element_12", 278, "Magnesium", 1200, 1560, 95, 149, 163),
+//B_279_ELEMENT_13("minecraft:element_13", 279, "Aluminum", 1320, 1560, 154, 150, 135),
+//B_280_ELEMENT_14("minecraft:element_14", 280, "Silicon", 1440, 1560, 158, 130, 129),
+//B_281_ELEMENT_15("minecraft:element_15", 281, "Phosphorus", 1560, 1560, 117, 145, 87),
+//B_282_ELEMENT_16("minecraft:element_16", 282, "Sulfur", 1680, 1560, 117, 145, 87),
+//B_283_ELEMENT_17("minecraft:element_17", 283, "Chlorine", 1800, 1560, 183, 136, 87),
+//B_284_ELEMENT_18("minecraft:element_18", 284, "Argon", 1920, 1560, 155, 115, 182),
+//B_285_ELEMENT_19("minecraft:element_19", 285, "Potassium", 2040, 1560, 101, 123, 181),
+//B_286_ELEMENT_20("minecraft:element_20", 286, "Calcium", 2160, 1560, 90, 148, 162),
+//B_287_ELEMENT_21("minecraft:element_21", 287, "Scandium", 2280, 1560, 127, 127, 127),
+//B_288_ELEMENT_22("minecraft:element_22", 288, "Titanium", 0, 1680, 127, 127, 127),
+//B_289_ELEMENT_23("minecraft:element_23", 289, "Vanadium", 120, 1680, 126, 126, 126),
+//B_290_ELEMENT_24("minecraft:element_24", 290, "Chromium", 240, 1680, 128, 128, 128),
+//B_291_ELEMENT_25("minecraft:element_25", 291, "Manganese", 360, 1680, 130, 130, 130),
+//B_292_ELEMENT_26("minecraft:element_26", 292, "Iron", 480, 1680, 130, 130, 130),
+//B_293_ELEMENT_27("minecraft:element_27", 293, "Cobalt", 600, 1680, 127, 127, 127),
+//B_294_ELEMENT_28("minecraft:element_28", 294, "Nickel", 720, 1680, 128, 128, 128),
+//B_295_ELEMENT_29("minecraft:element_29", 295, "Copper", 840, 1680, 128, 128, 128),
+//B_296_ELEMENT_30("minecraft:element_30", 296, "Zinc", 960, 1680, 129, 129, 129),
+//B_297_ELEMENT_31("minecraft:element_31", 297, "Gallium", 1080, 1680, 155, 151, 136),
+//B_298_ELEMENT_32("minecraft:element_32", 298, "Germanium", 1200, 1680, 160, 134, 132),
+//B_299_ELEMENT_33("minecraft:element_33", 299, "Arsenic", 1320, 1680, 160, 133, 132),
+//B_300_ELEMENT_34("minecraft:element_34", 300, "Selenium", 1440, 1680, 122, 148, 94),
+//B_301_ELEMENT_35("minecraft:element_35", 301, "Bromine", 1560, 1680, 184, 138, 93),
+//B_302_ELEMENT_36("minecraft:element_36", 302, "Krypton", 1680, 1680, 155, 114, 182),
+//B_303_ELEMENT_37("minecraft:element_37", 303, "Rubidium", 1800, 1680, 108, 128, 182),
+//B_304_ELEMENT_38("minecraft:element_38", 304, "Strontium", 1920, 1680, 88, 147, 161),
+//B_305_ELEMENT_39("minecraft:element_39", 305, "Yttrium", 2040, 1680, 125, 125, 125),
+//B_306_ELEMENT_40("minecraft:element_40", 306, "Zirconium", 2160, 1680, 128, 128, 128),
+//B_307_ELEMENT_41("minecraft:element_41", 307, "Niobium", 2280, 1680, 130, 130, 130),
+//B_308_ELEMENT_42("minecraft:element_42", 308, "Molybdenum", 0, 1800, 130, 130, 130),
+//B_309_ELEMENT_43("minecraft:element_43", 309, "Technetium", 120, 1800, 127, 127, 127),
+//B_310_ELEMENT_44("minecraft:element_44", 310, "Ruthenium", 240, 1800, 130, 130, 130),
+//B_311_ELEMENT_45("minecraft:element_45", 311, "Rhodium", 360, 1800, 130, 130, 130),
+//B_312_ELEMENT_46("minecraft:element_46", 312, "Palladium", 480, 1800, 130, 130, 130),
+//B_313_ELEMENT_47("minecraft:element_47", 313, "Silver", 600, 1800, 131, 131, 131),
+//B_314_ELEMENT_48("minecraft:element_48", 314, "Cadmium", 720, 1800, 129, 129, 129),
+//B_315_ELEMENT_49("minecraft:element_49", 315, "Indium", 840, 1800, 155, 150, 135),
+//B_316_ELEMENT_50("minecraft:element_50", 316, "Tin", 960, 1800, 155, 150, 135),
+//B_317_ELEMENT_51("minecraft:element_51", 317, "Antimony", 1080, 1800, 159, 133, 131),
+//B_318_ELEMENT_52("minecraft:element_52", 318, "Tellurium", 1200, 1800, 160, 133, 132),
+//B_319_ELEMENT_53("minecraft:element_53", 319, "Iodine", 1320, 1800, 183, 135, 86),
+//B_320_ELEMENT_54("minecraft:element_54", 320, "Xenon", 1440, 1800, 155, 116, 182),
+//B_321_ELEMENT_55("minecraft:element_55", 321, "Cesium", 1560, 1800, 106, 126, 181),
+//B_322_ELEMENT_56("minecraft:element_56", 322, "Barium", 1680, 1800, 93, 149, 162),
+//B_323_ELEMENT_57("minecraft:element_57", 323, "Lanthanum", 1800, 1800, 181, 138, 175),
+//B_324_ELEMENT_58("minecraft:element_58", 324, "Cerium", 1920, 1800, 181, 139, 175),
+//B_325_ELEMENT_59("minecraft:element_59", 325, "Praseodymium", 2040, 1800, 181, 138, 175),
+//B_326_ELEMENT_60("minecraft:element_60", 326, "Neodymium", 2160, 1800, 181, 140, 175),
+//B_327_ELEMENT_61("minecraft:element_61", 327, "Promethium", 2280, 1800, 181, 138, 175),
+//B_328_ELEMENT_62("minecraft:element_62", 328, "Samarium", 0, 1920, 181, 139, 175),
+//B_329_ELEMENT_63("minecraft:element_63", 329, "Europium", 120, 1920, 181, 139, 175),
+//B_330_ELEMENT_64("minecraft:element_64", 330, "Gadolinium", 240, 1920, 181, 139, 175),
+//B_331_ELEMENT_65("minecraft:element_65", 331, "Terbium", 360, 1920, 181, 139, 175),
+//B_332_ELEMENT_66("minecraft:element_66", 332, "Dysprosium", 480, 1920, 181, 140, 175),
+//B_333_ELEMENT_67("minecraft:element_67", 333, "Holmium", 600, 1920, 181, 138, 175),
+//B_334_ELEMENT_68("minecraft:element_68", 334, "Erbium", 720, 1920, 181, 138, 175),
+//B_335_ELEMENT_69("minecraft:element_69", 335, "Thulium", 840, 1920, 181, 138, 175),
+//B_336_ELEMENT_70("minecraft:element_70", 336, "Ytterbium", 960, 1920, 181, 138, 175),
+//B_337_ELEMENT_71("minecraft:element_71", 337, "Lutetium", 1080, 1920, 181, 137, 174),
+//B_338_ELEMENT_72("minecraft:element_72", 338, "Hafnium", 1200, 1920, 129, 129, 129),
+//B_339_ELEMENT_73("minecraft:element_73", 339, "Tantalum", 1320, 1920, 129, 129, 129),
+//B_340_ELEMENT_74("minecraft:element_74", 340, "Tungsten", 1440, 1920, 127, 127, 127),
+//B_341_ELEMENT_75("minecraft:element_75", 341, "Rhenium", 1560, 1920, 131, 131, 131),
+//B_342_ELEMENT_76("minecraft:element_76", 342, "Osmium", 1680, 1920, 129, 129, 129),
+//B_343_ELEMENT_77("minecraft:element_77", 343, "Iridium", 1800, 1920, 127, 127, 127),
+//B_344_ELEMENT_78("minecraft:element_78", 344, "Platinum", 1920, 1920, 128, 128, 128),
+//B_345_ELEMENT_79("minecraft:element_79", 345, "Gold", 2040, 1920, 129, 129, 129),
+//B_346_ELEMENT_80("minecraft:element_80", 346, "Mercury", 2160, 1920, 131, 131, 131),
+//B_347_ELEMENT_81("minecraft:element_81", 347, "Thallium", 2280, 1920, 154, 149, 134),
+//B_348_ELEMENT_82("minecraft:element_82", 348, "Lead", 0, 2040, 155, 151, 136),
+//B_349_ELEMENT_83("minecraft:element_83", 349, "Bismuth", 120, 2040, 155, 150, 135),
+//B_350_ELEMENT_84("minecraft:element_84", 350, "Polonium", 240, 2040, 159, 132, 130),
+//B_351_ELEMENT_85("minecraft:element_85", 351, "Astatine", 360, 2040, 184, 138, 92),
+//B_352_ELEMENT_86("minecraft:element_86", 352, "Radon", 480, 2040, 155, 116, 182),
+//B_353_ELEMENT_87("minecraft:element_87", 353, "Francium", 600, 2040, 104, 125, 181),
+//B_354_ELEMENT_88("minecraft:element_88", 354, "Radium", 720, 2040, 93, 149, 162),
+//B_355_ELEMENT_89("minecraft:element_89", 355, "Actinium", 840, 2040, 114, 89, 156),
+//B_356_ELEMENT_90("minecraft:element_90", 356, "Thorium", 960, 2040, 115, 90, 156),
+//B_357_ELEMENT_91("minecraft:element_91", 357, "Protactinium", 1080, 2040, 115, 90, 156),
+//B_358_ELEMENT_92("minecraft:element_92", 358, "Uranium", 1200, 2040, 111, 84, 154),
+//B_359_ELEMENT_93("minecraft:element_93", 359, "Neptunium", 1320, 2040, 117, 93, 157),
+//B_360_ELEMENT_94("minecraft:element_94", 360, "Plutonium", 1440, 2040, 114, 89, 156),
+//B_361_ELEMENT_95("minecraft:element_95", 361, "Americium", 1560, 2040, 117, 92, 157),
+//B_362_ELEMENT_96("minecraft:element_96", 362, "Curium", 1680, 2040, 115, 90, 156),
+//B_363_ELEMENT_97("minecraft:element_97", 363, "Berkelium", 1800, 2040, 116, 92, 157),
+//B_364_ELEMENT_98("minecraft:element_98", 364, "Californium", 1920, 2040, 114, 88, 156),
+//B_365_ELEMENT_99("minecraft:element_99", 365, "Einsteinium", 2040, 2040, 116, 91, 156),
+//B_366_ELEMENT_100("minecraft:element_100", 366, "Fermium", 2160, 2040, 116, 92, 157),
+//B_367_ELEMENT_101("minecraft:element_101", 367, "Mendelevium", 2280, 2040, 118, 94, 157),
+//B_368_ELEMENT_102("minecraft:element_102", 368, "Nobelium", 0, 2160, 116, 91, 157),
+//B_369_ELEMENT_103("minecraft:element_103", 369, "Lawrencium", 120, 2160, 114, 88, 156),
+//B_370_ELEMENT_104("minecraft:element_104", 370, "Rutherfordium", 240, 2160, 130, 130, 130),
+//B_371_ELEMENT_105("minecraft:element_105", 371, "Dubnium", 360, 2160, 131, 131, 131),
+//B_372_ELEMENT_106("minecraft:element_106", 372, "Seaborgium", 480, 2160, 131, 131, 131),
+//B_373_ELEMENT_107("minecraft:element_107", 373, "Bohrium", 600, 2160, 131, 131, 131),
+//B_374_ELEMENT_108("minecraft:element_108", 374, "Hassium", 720, 2160, 130, 130, 130),
+//B_375_ELEMENT_109("minecraft:element_109", 375, "Meitnerium", 840, 2160, 130, 130, 130),
+//B_376_ELEMENT_110("minecraft:element_110", 376, "Darmstadtium", 960, 2160, 130, 130, 130),
+//B_377_ELEMENT_111("minecraft:element_111", 377, "Roentgenium", 1080, 2160, 131, 131, 131),
+//B_378_ELEMENT_112("minecraft:element_112", 378, "Copernicium", 1200, 2160, 128, 128, 128),
+//B_379_ELEMENT_113("minecraft:element_113", 379, "Nihonium", 1320, 2160, 156, 152, 137),
+//B_380_ELEMENT_114("minecraft:element_114", 380, "Flerovium", 1440, 2160, 154, 150, 135),
+//B_381_ELEMENT_115("minecraft:element_115", 381, "Moscovium", 1560, 2160, 155, 151, 136),
+//B_382_ELEMENT_116("minecraft:element_116", 382, "Livermorium", 1680, 2160, 154, 150, 134),
+//B_383_ELEMENT_117("minecraft:element_117", 383, "Tennessine", 1800, 2160, 183, 137, 91),
+//B_384_ELEMENT_118("minecraft:element_118", 384, "Oganesson", 1920, 2160, 156, 118, 182),
+ B_385_SEAGRASS("minecraft:seagrass", 385, "Seagrass", 2040, 2160, 52, 128, 10),
+ B_386_CORAL("minecraft:coral", 386, "Coral", 2160, 2160, 33, 58, 138),
+ B_387_CORAL_BLOCK("minecraft:coral_block", 387, "Coral Block", 2280, 2160, 38, 68, 162),
+ B_388_CORAL_FAN("minecraft:coral_fan", 388, "Coral Fan", 0, 2280, 54, 96, 219),
+ B_389_CORAL_FAN_DEAD("minecraft:coral_fan_dead", 389, "Dead Coral Fan", 120, 2280, 135, 128, 124),
+ B_390_CORAL_FAN_HANG("minecraft:coral_fan_hang", 390, "Coral Fan", 240, 2280, 54, 96, 219),
+ B_391_CORAL_FAN_HANG2("minecraft:coral_fan_hang2", 391, "Coral Fan", 360, 2280, 168, 34, 168),
+ B_392_CORAL_FAN_HANG3("minecraft:coral_fan_hang3", 392, "Coral Fan", 480, 2280, 219, 195, 66),
+ B_393_KELP("minecraft:kelp", 393, "Kelp", 600, 2280, 86, 126, 39),
+ B_394_DRIED_KELP_BLOCK("minecraft:dried_kelp_block", 394, "Dried Kelp Block", 720, 2280, 33, 41, 25),
+ B_395_ACACIA_BUTTON("minecraft:acacia_button", 395, "Acacia Button", 840, 2280, 138, 74, 41),
+ B_396_BIRCH_BUTTON("minecraft:birch_button", 396, "Birch Button", 960, 2280, 158, 144, 100),
+ B_397_DARK_OAK_BUTTON("minecraft:dark_oak_button", 397, "Dark Oak Button", 1080, 2280, 55, 36, 16),
+ B_398_JUNGLE_BUTTON("minecraft:jungle_button", 398, "Jungle Button", 1200, 2280, 133, 96, 68),
+ B_399_SPRUCE_BUTTON("minecraft:spruce_button", 399, "Spruce Button", 1320, 2280, 95, 70, 40),
+ B_400_ACACIA_TRAPDOOR("minecraft:acacia_trapdoor", 400, "Acacia Trapdoor", 1440, 2280, 124, 68, 39),
+ B_401_BIRCH_TRAPDOOR("minecraft:birch_trapdoor", 401, "Birch Trapdoor", 1560, 2280, 163, 152, 119),
+ B_402_DARK_OAK_TRAPDOOR("minecraft:dark_oak_trapdoor", 402, "Dark Oak Trapdoor", 1680, 2280, 59, 39, 18),
+ B_403_JUNGLE_TRAPDOOR("minecraft:jungle_trapdoor", 403, "Jungle Trapdoor", 1800, 2280, 122, 88, 61),
+ B_404_SPRUCE_TRAPDOOR("minecraft:spruce_trapdoor", 404, "Spruce Trapdoor", 1920, 2280, 93, 70, 42),
+ B_405_ACACIA_PRESSURE_PLATE("minecraft:acacia_pressure_plate", 405, "Acacia Pressure Plate", 2040, 2280, 154, 82, 46),
+ B_406_BIRCH_PRESSURE_PLATE("minecraft:birch_pressure_plate", 406, "Birch Pressure Plate", 2160, 2280, 177, 161, 111),
+ B_407_DARK_OAK_PRESSURE_PLATE("minecraft:dark_oak_pressure_plate", 407, "Dark Oak Pressure Plate", 2280, 2280, 60, 38, 18),
+ B_408_JUNGLE_PRESSURE_PLATE("minecraft:jungle_pressure_plate", 408, "Jungle Pressure Plate", 0, 2400, 146, 104, 73),
+ B_409_SPRUCE_PRESSURE_PLATE("minecraft:spruce_pressure_plate", 409, "Spruce Pressure Plate", 120, 2400, 105, 77, 44),
+ B_410_CARVED_PUMPKIN("minecraft:carved_pumpkin", 410, "Carved Pumpkin", 240, 2400, 140, 82, 17),
+ B_411_SEA_PICKLE("minecraft:sea_pickle", 411, "Sea Pickle", 360, 2400, 81, 86, 39),
+ B_412_CONDUIT("minecraft:conduit", 412, "Conduit", 480, 2400, 125, 108, 88),
+ B_414_TURTLE_EGG("minecraft:turtle_egg", 414, "Sea Turtle Egg", 600, 2400, 172, 173, 149),
+ B_415_BUBBLE_COLUMN("minecraft:bubble_column", 415, "Bubble Column", 720, 2400, 93, 201, 251),
+ B_416_BARRIER("minecraft:barrier", 416, "Barrier", 840, 2400, 211, 0, 0),
+ B_417_STONE_SLAB3("minecraft:stone_slab3", 417, "End Stone Brick Slab", 960, 2400, 180, 184, 133),
+ B_418_BAMBOO("minecraft:bamboo", 418, "Bamboo", 1080, 2400, 86, 123, 32),
+ B_419_BAMBOO_SAPLING("minecraft:bamboo_sapling", 419, "Bamboo Sapling", 1200, 2400, 89, 89, 34),
+ B_420_SCAFFOLDING("minecraft:scaffolding", 420, "Scaffolding", 1320, 2400, 158, 129, 73),
+ B_421_STONE_SLAB4("minecraft:stone_slab4", 421, "Mossy Stone Brick Slab", 1440, 2400, 96, 100, 89),
+ B_422_DOUBLE_STONE_SLAB3("minecraft:double_stone_slab3", 422, "Double End Stone Brick Slab", 1560, 2400, 171, 175, 126),
+ B_423_DOUBLE_STONE_SLAB4("minecraft:double_stone_slab4", 423, "Double Mossy Stone Brick Slab", 1680, 2400, 90, 94, 82),
+ B_424_GRANITE_STAIRS("minecraft:granite_stairs", 424, "Granite Stairs", 1800, 2400, 120, 83, 69),
+ B_425_DIORITE_STAIRS("minecraft:diorite_stairs", 425, "Diorite Stairs", 1920, 2400, 153, 153, 154),
+ B_426_ANDESITE_STAIRS("minecraft:andesite_stairs", 426, "Andesite Stairs", 2040, 2400, 109, 109, 109),
+ B_427_POLISHED_GRANITE_STAIRS("minecraft:polished_granite_stairs", 427, "Polished Granite Stairs", 2160, 2400, 122, 85, 71),
+ B_428_POLISHED_DIORITE_STAIRS("minecraft:polished_diorite_stairs", 428, "Polished Diorite Stairs", 2280, 2400, 153, 153, 154),
+ B_429_POLISHED_ANDESITE_STAIRS("minecraft:polished_andesite_stairs", 429, "Polished Andesite Stairs", 0, 2520, 105, 107, 107),
+ B_430_MOSSY_STONE_BRICK_STAIRS("minecraft:mossy_stone_brick_stairs", 430, "Mossy Stone Brick Stairs", 120, 2520, 92, 96, 84),
+ B_431_SMOOTH_RED_SANDSTONE_STAIRS("minecraft:smooth_red_sandstone_stairs", 431, "Smooth Red Sandstone Stairs", 240, 2520, 147, 79, 25),
+ B_432_SMOOTH_SANDSTONE_STAIRS("minecraft:smooth_sandstone_stairs", 432, "Smooth Sandstone Stairs", 360, 2520, 181, 173, 139),
+ B_433_END_BRICK_STAIRS("minecraft:end_brick_stairs", 433, "End Stone Brick Stairs", 480, 2520, 174, 178, 129),
+ B_434_MOSSY_COBBLESTONE_STAIRS("minecraft:mossy_cobblestone_stairs", 434, "Mossy Cobblestone Stairs", 600, 2520, 89, 95, 77),
+ B_435_NORMAL_STONE_STAIRS("minecraft:normal_stone_stairs", 435, "Stone Stairs", 720, 2520, 100, 100, 100),
+ B_436_SPRUCE_STANDING_SIGN("minecraft:spruce_standing_sign", 436, "Spruce Standing Sign", 840, 2520, 73, 54, 31),
+ B_437_SPRUCE_WALL_SIGN("minecraft:spruce_wall_sign", 437, "Spruce Wall Sign", 960, 2520, 80, 60, 35),
+ B_438_SMOOTH_STONE("minecraft:smooth_stone", 438, "Smooth Stone", 1080, 2520, 123, 123, 123),
+ B_439_RED_NETHER_BRICK_STAIRS("minecraft:red_nether_brick_stairs", 439, "Red Nether Brick Stairs", 1200, 2520, 56, 5, 7),
+ B_440_SMOOTH_QUARTZ_STAIRS("minecraft:smooth_quartz_stairs", 440, "Smooth Quartz Stairs", 1320, 2520, 189, 184, 179),
+ B_441_BIRCH_STANDING_SIGN("minecraft:birch_standing_sign", 441, "Birch Standing Sign", 1440, 2520, 147, 136, 98),
+ B_442_BIRCH_WALL_SIGN("minecraft:birch_wall_sign", 442, "Birch Wall Sign", 1560, 2520, 149, 137, 93),
+ B_443_JUNGLE_STANDING_SIGN("minecraft:jungle_standing_sign", 443, "Jungle Standing Sign", 1680, 2520, 110, 80, 53),
+ B_444_JUNGLE_WALL_SIGN("minecraft:jungle_wall_sign", 444, "Jungle Wall Sign", 1800, 2520, 120, 86, 59),
+ B_445_ACACIA_STANDING_SIGN("minecraft:acacia_standing_sign", 445, "Acacia Standing Sign", 1920, 2520, 120, 69, 41),
+ B_446_ACACIA_WALL_SIGN("minecraft:acacia_wall_sign", 446, "Acacia Wall Sign", 2040, 2520, 129, 70, 39),
+ B_447_DARKOAK_STANDING_SIGN("minecraft:darkoak_standing_sign", 447, "Dark Oak Standing Sign", 2160, 2520, 44, 29, 14),
+ B_448_DARKOAK_WALL_SIGN("minecraft:darkoak_wall_sign", 448, "Dark Oak Wall Sign", 2280, 2520, 46, 29, 13),
+ B_449_LECTERN("minecraft:lectern", 449, "Lectern", 0, 2640, 141, 107, 64),
+ B_450_GRINDSTONE("minecraft:grindstone", 450, "Grindstone", 120, 2640, 96, 92, 87),
+ B_451_BLAST_FURNACE("minecraft:blast_furnace", 451, "Blast Furnace", 240, 2640, 76, 76, 76),
+ B_452_STONECUTTER_BLOCK("minecraft:stonecutter_block", 452, "Stonecutter Block", 360, 2640, 104, 96, 89),
+ B_453_SMOKER("minecraft:smoker", 453, "Smoker", 480, 2640, 71, 64, 55),
+ B_454_LIT_SMOKER("minecraft:lit_smoker", 454, "Lit Smoker", 600, 2640, 79, 70, 58),
+ B_455_CARTOGRAPHY_TABLE("minecraft:cartography_table", 455, "Cartography Table", 720, 2640, 58, 44, 30),
+ B_456_FLETCHING_TABLE("minecraft:fletching_table", 456, "Fletching Table", 840, 2640, 125, 113, 83),
+ B_457_SMITHING_TABLE("minecraft:smithing_table", 457, "Smithing Table", 960, 2640, 37, 31, 35),
+ B_458_BARREL("minecraft:barrel", 458, "Barrel", 1080, 2640, 92, 69, 41),
+ B_459_LOOM("minecraft:loom", 459, "Loom", 1200, 2640, 114, 90, 65),
+ B_461_BELL("minecraft:bell", 461, "Bell", 1320, 2640, 121, 113, 77),
+ B_462_SWEET_BERRY_BUSH("minecraft:sweet_berry_bush", 462, "Sweet Berry Bush", 1440, 2640, 47, 55, 36),
+ B_463_LANTERN("minecraft:lantern", 463, "Lantern", 1560, 2640, 97, 79, 63),
+ B_464_CAMPFIRE("minecraft:campfire", 464, "Campfire", 1680, 2640, 146, 110, 50),
+ B_465_LAVA_CAULDRON("minecraft:lava_cauldron", 465, "Lava Cauldron", 1800, 2640, 76, 60, 51),
+ B_466_JIGSAW("minecraft:jigsaw", 466, "Jigsaw", 1920, 2640, 59, 59, 59),
+ B_467_WOOD("minecraft:wood", 467, "Wood", 2040, 2640, 97, 76, 45),
+ B_468_COMPOSTER("minecraft:composter", 468, "Composter", 2160, 2640, 90, 57, 27),
+ B_469_LIT_BLAST_FURNACE("minecraft:lit_blast_furnace", 469, "Lit Blast Furnace", 2280, 2640, 79, 77, 76),
+ B_470_LIGHT_BLOCK("minecraft:light_block", 470, "Light Block", 0, 2760, 153, 147, 149),
+ B_471_WITHER_ROSE("minecraft:wither_rose", 471, "Wither Rose", 120, 2760, 44, 47, 24),
+ B_472_STICKYPISTONARMCOLLISION("minecraft:stickypistonarmcollision", 472, "Sticky Piston Head", 240, 2760, 101, 107, 73),
+ B_473_BEE_NEST("minecraft:bee_nest", 473, "Bee Nest", 360, 2760, 152, 118, 60),
+ B_474_BEEHIVE("minecraft:beehive", 474, "Beehive", 480, 2760, 131, 106, 65),
+ B_475_HONEY_BLOCK("minecraft:honey_block", 475, "Honey Block", 600, 2760, 197, 136, 32),
+ B_476_HONEYCOMB_BLOCK("minecraft:honeycomb_block", 476, "Honeycomb Block", 720, 2760, 182, 117, 23),
+ B_210_ALLOW("minecraft:allow", 210, "Allow", 840, 2760, 106, 90, 66),
+ B_211_DENY("minecraft:deny", 211, "Deny", 960, 2760, 87, 87, 87),
+ B_212_BORDER("minecraft:border", 212, "Border", 1080, 2760, 125, 36, 29),
+ B_230_CHALKBOARD("minecraft:chalkboard", 230, "Chalkboard", 1200, 2760, 71, 69, 57);
+//B_242_CAMERA("minecraft:camera", 242, "", 1320, 2760, 63, 51, 34),
+
+
+ private static int SIZE = 120;
+
+ private static WeakReference iconsSheet = new WeakReference<>(null);
+
+ private String identifier;
+
+ private String name;
+
+ private int legacy_id;
+
+ private int iconX;
+
+ private int iconY;
+
+ private int color;
+
+ //@Nullable
+ private WeakReference icon;
+
+ ListingBlock(String identifier, int legacy_id, String name, int iconX, int iconY, int r, int g, int b) {
+ this.identifier = identifier;
+ this.legacy_id = legacy_id;
+ this.name = name;
+ this.iconX = iconX;
+ this.iconY = iconY;
+ if (r < 0)
+ color = Color.TRANSPARENT;
+ else
+ color = Color.rgb(r, g, b);
+ icon = new WeakReference<>(null);
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public int getLegacy_id() {
+ return legacy_id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Bitmap getIcon(AssetManager assMan) {
+ Bitmap icon = this.icon.get();
+ if (icon == null) {
+ if (iconX >= 0) {
+ Bitmap sheet = iconsSheet.get();
+ try {
+ if (sheet == null) {
+ sheet = BitmapFactory.decodeStream(assMan.open("block_icons.png"));
+ iconsSheet = new WeakReference<>(sheet);
+ }
+ icon = Bitmap.createBitmap(sheet, iconX, iconY, SIZE, SIZE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (icon == null)
+ icon = Bitmap.createBitmap(SIZE, SIZE, Bitmap.Config.ARGB_8888);
+ this.icon = new WeakReference<>(icon);
+ }
+ return icon;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlock.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlock.java
new file mode 100644
index 00000000..a95e0c57
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlock.java
@@ -0,0 +1,93 @@
+package com.mithrilmania.blocktopograph.block;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
+import com.mithrilmania.blocktopograph.nbt.tags.Tag;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+public class OldBlock implements Serializable {
+
+ @NonNull
+ private OldBlockType oldBlockType;
+
+ @NonNull
+ private KnownBlockRepr legacyBlock;
+
+ private ListingBlock listingBlock;
+
+ @NonNull
+ private CompoundTag states;
+
+ private int version;
+
+ OldBlock(@NonNull OldBlockType oldBlockType, @NonNull CompoundTag states, int version) {
+ this.oldBlockType = oldBlockType;
+ this.states = states;
+ this.version = version;
+ KnownBlockRepr legacyBlock = BlockWithStatesToLegacyBlockMapper.getBestRepr(this);
+ if (legacyBlock == null) {
+ for (ListingBlock lb : ListingBlock.values()) {
+ if (lb.getIdentifier().equals(oldBlockType.getName())) {
+ listingBlock = lb;
+ break;
+ }
+ }
+ legacyBlock = KnownBlockRepr.guessBlockNew(oldBlockType.getName());
+ }
+ this.legacyBlock = legacyBlock;
+ }
+
+ OldBlock(@NonNull OldBlockType oldBlockType, @NonNull KnownBlockRepr legacyBlock, int version) {
+ this.oldBlockType = oldBlockType;
+ this.states = new CompoundTag("states", new ArrayList<>());
+ this.version = version;
+ this.legacyBlock = legacyBlock;
+ }
+
+ @NonNull
+ public String getBlockType() {
+ return oldBlockType.getName();
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public boolean isOfSameType(OldBlock oldBlock) {
+ return oldBlockType == oldBlock.oldBlockType;
+ }
+
+ public Tag getState(String key) {
+ return states.getChildTagByKey(key);
+ }
+
+ @NonNull
+ public KnownBlockRepr getLegacyBlock() {
+ return legacyBlock;
+ }
+
+ public int getColor() {
+ if (listingBlock != null)
+ return listingBlock.getColor();
+ return legacyBlock.color;
+ }
+
+ @NonNull
+ public CompoundTag getStates() {
+ return states;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof OldBlock)) return false;
+ OldBlock another = (OldBlock) obj;
+ // Ref compare.
+ if (oldBlockType != another.oldBlockType) return false;
+ return states.equals(another.states);
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlockRegistry.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlockRegistry.java
new file mode 100644
index 00000000..38e79a3c
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlockRegistry.java
@@ -0,0 +1,52 @@
+package com.mithrilmania.blocktopograph.block;
+
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Map;
+
+public class OldBlockRegistry {
+
+ private int limitedTypes;
+ private Map blockTypes;
+
+ public OldBlockRegistry() {
+ blockTypes = new Hashtable<>(1024);
+ }
+
+ public OldBlockRegistry(int limitedTypes) {
+ this();
+ this.limitedTypes = limitedTypes;
+ }
+
+ @NonNull
+ private OldBlockType getBlockType(String name) {
+ OldBlockType ret = blockTypes.get(name);
+ if (ret == null) {
+ ret = new OldBlockType(name);
+ if (limitedTypes > 0 && blockTypes.size() >= limitedTypes)
+ throw new RuntimeException("Block types exceeds your set limit.");
+ blockTypes.put(name, ret);
+ }
+ return ret;
+ }
+
+ @NonNull
+ public OldBlock createBlock(@NonNull String name, @NonNull CompoundTag states, int version) {
+ return new OldBlock(getBlockType(name), states, version);
+ }
+
+ @NonNull
+ public OldBlock createBlock(@NonNull String name) {
+ return new OldBlock(getBlockType(name), new CompoundTag("states", new ArrayList<>()), 3841);
+ }
+
+ @NonNull
+ public OldBlock createBlock(@NonNull KnownBlockRepr legacyBlock) {
+ return new OldBlock(getBlockType(legacyBlock.identifier), legacyBlock, 1);
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlockType.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlockType.java
new file mode 100644
index 00000000..6ab2d1b0
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/OldBlockType.java
@@ -0,0 +1,16 @@
+package com.mithrilmania.blocktopograph.block;
+
+import java.io.Serializable;
+
+public class OldBlockType implements Serializable {
+
+ private final String name;
+
+ public OldBlockType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/BitValuesRange.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/BitValuesRange.java
new file mode 100644
index 00000000..6da14fa7
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/BitValuesRange.java
@@ -0,0 +1,4 @@
+package com.mithrilmania.blocktopograph.block.blockproperty;
+
+public class BitValuesRange extends ValuesRange {
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/BlockProperty.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/BlockProperty.java
new file mode 100644
index 00000000..be27b3ae
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/BlockProperty.java
@@ -0,0 +1,134 @@
+package com.mithrilmania.blocktopograph.block.blockproperty;
+
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.nbt.convert.NBTConstants;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum BlockProperty {
+ AGE_BIT("age_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ ALLOW_UNDERWATER_BIT("allow_underwater_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ ATTACHED_BIT("attached_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ BREWING_STAND_SLOT_A_BIT("brewing_stand_slot_a_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ BREWING_STAND_SLOT_B_BIT("brewing_stand_slot_b_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ BREWING_STAND_SLOT_C_BIT("brewing_stand_slot_c_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ BUTTON_PRESSED_BIT("button_pressed_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ CONDITIONAL_BIT("conditional_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ CORAL_HANG_TYPE_BIT("coral_hang_type_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ COVERED_BIT("covered_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ DEAD_BIT("dead_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ DISARMED_BIT("disarmed_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ DOOR_HINGE_BIT("door_hinge_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ END_PORTAL_EYE_BIT("end_portal_eye_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ EXPLODE_BIT("explode_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ HEAD_PIECE_BIT("head_piece_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ IN_WALL_BIT("in_wall_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ INFINIBURN_BIT("infiniburn_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ ITEM_FRAME_MAP_BIT("item_frame_map_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ NO_DROP_BIT("no_drop_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ OCCUPIED_BIT("occupied_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ OPEN_BIT("open_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ OUTPUT_LIT_BIT("output_lit_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ OUTPUT_SUBTRACT_BIT("output_subtract_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ PERSISTENT_BIT("persistent_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ POWERED_BIT("powered_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ RAIL_DATA_BIT("rail_data_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ SUSPENDED_BIT("suspended_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ TOGGLE_BIT("toggle_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ TOP_SLOT_BIT("top_slot_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ TRIGGERED_BIT("triggered_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ UPDATE_BIT("update_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ UPPER_BLOCK_BIT("upper_block_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ UPSIDE_DOWN_BIT("upside_down_bit", NBTConstants.NBTType.BYTE, new BitValuesRange()),
+ AGE("age", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ BITE_COUNTER("bite_counter", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ CLUSTER_COUNT("cluster_count", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0, 1, 2, 3})),
+ CORAL_DIRECTION("coral_direction", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0, 1, 2, 3})),
+ CORAL_FAN_DIRECTION("coral_fan_direction", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0, 1})),
+ DEPRECATED("deprecated", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ DIRECTION("direction", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0, 1, 2, 3})),
+ FACING_DIRECTION("facing_direction", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0, 1, 2, 3, 4, 5})),
+ FILL_LEVEL("fill_level", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ GROUND_SIGN_DIRECTION("ground_sign_direction", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ GROWTH("growth", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ HEIGHT("height", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ HUGE_MUSHROOM_BITS("huge_mushroom_bits", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ KELP_AGE("kelp_age", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0, 1, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 6, 7, 8, 9})),
+ LIQUID_DEPTH("liquid_depth", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ MOISTURIZED_AMOUNT("moisturized_amount", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ RAIL_DIRECTION("rail_direction", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ REDSTONE_SIGNAL("redstone_signal", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0, 1, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 6, 7, 8, 9})),
+ REPEATER_DELAY("repeater_delay", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ VINE_DIRECTION_BITS("vine_direction_bits", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0})),
+ WEIRDO_DIRECTION("weirdo_direction", NBTConstants.NBTType.INT, new EnumValuesRange(new Integer[]{0, 1, 2, 3})),
+ CAULDRON_LIQUID("cauldron_liquid", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"water"})),
+ CHEMISTRY_TABLE_TYPE("chemistry_table_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"compound_creator", "element_constructor", "lab_table", "material_reducer"})),
+ CHISEL_TYPE("chisel_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"chiseled", "default", "lines", "smooth"})),
+ COLOR("color", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"black", "blue", "brown", "cyan", "gray", "green", "light_blue", "lime", "magenta", "orange", "pink", "purple", "red", "silver", "white", "yellow"})),
+ CORAL_COLOR("coral_color", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"blue", "pink", "purple", "red", "yellow"})),
+ DAMAGE("damage", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"slightly_damaged", "undamaged", "very_damaged"})),
+ DIRT_TYPE("dirt_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"normal"})),
+ DOUBLE_PLANT_TYPE("double_plant_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"fern", "grass", "paeonia", "rose", "sunflower", "syringa"})),
+ FLOWER_TYPE("flower_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"allium", "houstonia", "orchid", "oxeye", "poppy", "tulip_orange", "tulip_pink", "tulip_red", "tulip_white"})),
+ LEVER_DIRECTION("lever_direction", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"down_east_west"})),
+ MONSTER_EGG_STONE_TYPE("monster_egg_stone_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"chiseled_stone_brick", "cobblestone", "cracked_stone_brick", "mossy_stone_brick", "stone", "stone_brick"})),
+ NEW_LEAF_TYPE("new_leaf_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"acacia", "dark_oak"})),
+ NEW_LOG_TYPE("new_log_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"acacia", "dark_oak"})),
+ OLD_LEAF_TYPE("old_leaf_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"birch", "jungle", "oak", "spruce"})),
+ OLD_LOG_TYPE("old_log_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"birch", "jungle", "oak", "spruce"})),
+ PILLAR_AXIS("pillar_axis", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"x", "y", "z"})),
+ PORTAL_AXIS("portal_axis", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"unknown"})),
+ PRISMARINE_BLOCK_TYPE("prismarine_block_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"bricks", "dark", "default"})),
+ SAND_STONE_TYPE("sand_stone_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"cut", "default", "heiroglyphs"})),
+ SAND_TYPE("sand_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"normal", "red"})),
+ SAPLING_TYPE("sapling_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"acacia", "birch", "dark_oak", "jungle", "oak", "spruce"})),
+ SEA_GRASS_TYPE("sea_grass_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"default", "double_bot", "double_top"})),
+ SPONGE_TYPE("sponge_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"dry", "wet"})),
+ STONE_BRICK_TYPE("stone_brick_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"chiseled", "cracked", "default", "mossy", "smooth"})),
+ STONE_SLAB_TYPE("stone_slab_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"brick", "cobblestone", "nether_brick", "quartz", "sandstone", "smooth_stone", "stone_brick", "wood"})),
+ STONE_SLAB_TYPE_2("stone_slab_type_2", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"purpur", "red_sandstone"})),
+ STONE_TYPE("stone_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"andesite", "andesite_smooth", "diorite", "diorite_smooth", "granite", "granite_smooth", "stone"})),
+ STRUCTURE_BLOCK_TYPE("structure_block_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"corner", "data", "export", "invalid", "load", "save"})),
+ TALL_GRASS_TYPE("tall_grass_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"fern", "tall"})),
+ TORCH_FACING_DIRECTION("torch_facing_direction", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"east", "north", "south", "top", "unknown", "west"})),
+ WALL_BLOCK_TYPE("wall_block_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"cobblestone", "mossy_cobblestone"})),
+ WOOD_TYPE("wood_type", NBTConstants.NBTType.STRING, new EnumValuesRange(new String[]{"acacia", "birch", "dark_oak", "jungle", "oak", "spruce"}));
+
+
+ private static final Map blockProperties = new HashMap<>();
+
+ private final String name;
+
+ private final NBTConstants.NBTType type;
+
+ private final ValuesRange valuesRange;
+
+ static {
+ for (var property : BlockProperty.values()) blockProperties.put(property.name, property);
+ }
+
+ BlockProperty(String name, NBTConstants.NBTType type, ValuesRange valuesRange) {
+ this.name = name;
+ this.type = type;
+ this.valuesRange = valuesRange;
+ }
+
+ @Nullable
+ public static BlockProperty get(String name){
+ return blockProperties.get(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public NBTConstants.NBTType getType() {
+ return type;
+ }
+
+ public ValuesRange getValuesRange() {
+ return valuesRange;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/EnumValuesRange.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/EnumValuesRange.java
new file mode 100644
index 00000000..a12171ae
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/EnumValuesRange.java
@@ -0,0 +1,16 @@
+package com.mithrilmania.blocktopograph.block.blockproperty;
+
+import com.mithrilmania.blocktopograph.nbt.tags.Tag;
+
+public class EnumValuesRange extends ValuesRange {
+
+ private final Object[] values;
+
+ public EnumValuesRange(Object[] values) {
+ this.values = values;
+ }
+
+ public Object[] getValues() {
+ return values;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/ValuesRange.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/ValuesRange.java
new file mode 100644
index 00000000..dd67e8ca
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/blockproperty/ValuesRange.java
@@ -0,0 +1,4 @@
+package com.mithrilmania.blocktopograph.block.blockproperty;
+
+public abstract class ValuesRange {
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/BlockIcon.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/BlockIcon.java
new file mode 100644
index 00000000..3500921b
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/BlockIcon.java
@@ -0,0 +1,11 @@
+package com.mithrilmania.blocktopograph.block.icon;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+
+import java.io.Serializable;
+
+public abstract class BlockIcon implements Serializable{
+
+ abstract public Bitmap getIcon(Context context);
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/NoBlockIcon.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/NoBlockIcon.java
new file mode 100644
index 00000000..8fff5dac
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/NoBlockIcon.java
@@ -0,0 +1,11 @@
+package com.mithrilmania.blocktopograph.block.icon;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+
+public class NoBlockIcon extends BlockIcon{
+
+ public Bitmap getIcon(Context context){
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/TexPathBlockIcon.java b/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/TexPathBlockIcon.java
new file mode 100644
index 00000000..55145b86
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/block/icon/TexPathBlockIcon.java
@@ -0,0 +1,45 @@
+package com.mithrilmania.blocktopograph.block.icon;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+
+import java.io.FileNotFoundException;
+import java.lang.ref.WeakReference;
+
+public class TexPathBlockIcon extends BlockIcon {
+
+ private final String texPath;
+
+ private transient WeakReference texture;
+
+ public TexPathBlockIcon(String texPath) {
+ this.texPath = texPath;
+ texture = null;
+ }
+
+ public Bitmap getIcon(Context context) {
+ var result = texture == null ? null : texture.get();
+ if (result == null) {
+ result = loadIcon(context);
+ if (result != null) texture = new WeakReference<>(result);
+ }
+ return result;
+ }
+
+ private Bitmap loadIcon(Context context) {
+ try {
+ return Bitmap.createScaledBitmap(
+ BitmapFactory.decodeStream(
+ context.getAssets().open(texPath)), 120, 120, false);
+ } catch (FileNotFoundException e) {
+ //TODO file-paths were generated from block names; some do not actually exist...
+ } catch (Exception e) {
+ Log.d(KnownBlockRepr.class, e);
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/BedrockChunk.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/BedrockChunk.java
new file mode 100644
index 00000000..c98dd4a4
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/BedrockChunk.java
@@ -0,0 +1,302 @@
+package com.mithrilmania.blocktopograph.chunk;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.BuildConfig;
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.Block;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+import com.mithrilmania.blocktopograph.chunk.terrain.TerrainSubChunk;
+import com.mithrilmania.blocktopograph.map.Biome;
+import com.mithrilmania.blocktopograph.map.Dimension;
+import com.mithrilmania.blocktopograph.util.ColorUtil;
+import com.mithrilmania.blocktopograph.util.Noise;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public final class BedrockChunk extends Chunk {
+
+ private static final int POS_HEIGHTMAP = 0;
+ private static final int POS_BIOME_DATA = 0x200;
+ public static final int DATA2D_LENGTH = 0x300;
+
+ private boolean mHasBlockLight;
+ private final boolean[] mDirtyList;
+ private final boolean[] mVoidList;
+ private final boolean[] mErrorList;
+ private boolean mIs2dDirty;
+ private final TerrainSubChunk[] mTerrainSubChunks;
+ private volatile ByteBuffer data2D;
+
+ BedrockChunk(WorldData worldData, Version version, int chunkX, int chunkZ, Dimension dimension,
+ boolean createIfMissing) {
+ super(worldData, version, chunkX, chunkZ, dimension);
+ mVoidList = new boolean[16];
+ mErrorList = new boolean[16];
+ mDirtyList = new boolean[16];
+ mTerrainSubChunks = new TerrainSubChunk[16];
+ load2dData(createIfMissing);
+ mHasBlockLight = true;
+ mIs2dDirty = false;
+ }
+
+ private void load2dData(boolean createIfMissing) {
+ if (data2D == null) {
+ try {
+ byte[] rawData = mWorldData.get().getChunkData(
+ mChunkX, mChunkZ, ChunkTag.DATA_2D, mDimension, (byte) 0, false);
+ if (rawData == null) {
+ if (createIfMissing) {
+ this.data2D = ByteBuffer.allocate(DATA2D_LENGTH);
+ } else {
+ mIsError = true;
+ mIsVoid = true;
+ }
+ return;
+ }
+ this.data2D = ByteBuffer.wrap(rawData);
+ } catch (Exception e) {
+ if (BuildConfig.DEBUG) {
+ Log.d(this, e);
+ }
+ mIsError = true;
+ mIsVoid = true;
+ }
+ }
+ }
+
+ @Nullable
+ private TerrainSubChunk getSubChunk(int which, boolean createIfMissing) {
+ if (mIsError || mVoidList[which]) return null;
+ TerrainSubChunk ret = mTerrainSubChunks[which];
+ if (ret == null) {
+ byte[] raw;
+ WorldData worldData = mWorldData.get();
+ try {
+ raw = worldData.getChunkData(mChunkX, mChunkZ,
+ ChunkTag.TERRAIN, mDimension, (byte) which, true);
+ if (raw == null && !createIfMissing) {
+ mVoidList[which] = true;
+ return null;
+ }
+ } catch (Exception e) {
+ if (BuildConfig.DEBUG) {
+ Log.d(this, e);
+ }
+ mErrorList[which] = true;
+ mVoidList[which] = true;
+ return null;
+ }
+ ret = raw == null ?
+ TerrainSubChunk.createEmpty(8) :
+ TerrainSubChunk.create(raw);
+ if (ret == null || ret.isError()) {
+ mVoidList[which] = true;
+ mErrorList[which] = true;
+ ret = null;
+ } else if (!ret.hasBlockLight()) mHasBlockLight = false;
+ mTerrainSubChunks[which] = ret;
+ }
+ return ret;
+ }
+
+ private int get2dOffset(int x, int z) {
+ return (z << 4) | x;
+ }
+
+ @Override
+ public boolean supportsBlockLightValues() {
+ return mHasBlockLight;
+ }
+
+ @Override
+ public boolean supportsHeightMap() {
+ return true;
+ }
+
+ @Override
+ public int getHeightLimit() {
+ return 256;
+ }
+
+ @Override
+ public int getHeightMapValue(int x, int z) {
+ if (mIsVoid) return 0;
+ short h = data2D.getShort(POS_HEIGHTMAP + (get2dOffset(x, z) << 1));
+ return ((h & 0xff) << 8) | ((h >> 8) & 0xff);
+ }
+
+ private void setHeightMapValue(int x, int z, short height) {
+ if (mIsVoid) return;
+ data2D.putShort(POS_HEIGHTMAP + (get2dOffset(x, z) << 1), Short.reverseBytes(height));
+ }
+
+ @Override
+ public int getBiome(int x, int z) {
+ if (mIsVoid) return 0;
+ return data2D.get(POS_BIOME_DATA + get2dOffset(x, z));
+ }
+
+ @Override
+ public void setBiome(int x, int z, int id) {
+ if (mIsVoid) return;
+ data2D.put(POS_BIOME_DATA + get2dOffset(x, z), (byte) id);
+ mIs2dDirty = true;
+ }
+
+ private int getNoise(int x, int z) {
+ // noise values are between -1 and 1
+ // 0.0001 is added to the coordinates because integer values result in 0
+ double xval = (mChunkX << 4) | x;
+ double zval = (mChunkZ << 4) | z;
+ double oct1 = Noise.noise(
+ (xval / 100.0) % 256 + 0.0001,
+ (zval / 100.0) % 256 + 0.0001);
+ double oct2 = Noise.noise(
+ (xval / 20.0) % 256 + 0.0001,
+ (zval / 20.0) % 256 + 0.0001);
+ double oct3 = Noise.noise(
+ (xval / 3.0) % 256 + 0.0001,
+ (zval / 3.0) % 256 + 0.0001);
+ return (int) (60 + (40 * oct1) + (14 * oct2) + (6 * oct3));
+ }
+
+ @Override
+ public int getGrassColor(int x, int z) {
+ Biome biome = Biome.getBiome(getBiome(x, z) & 0xff);
+ int noise = getNoise(x, z);
+ int r = 30 + (biome.color.red / 5) + noise;
+ int g = 110 + (biome.color.green / 5) + noise;
+ int b = 30 + (biome.color.blue / 5) + noise;
+ return ColorUtil.truncateRgb(r, g, b);
+ }
+
+ @NonNull
+ @Override
+ public BlockTemplate getBlockTemplate(int x, int y, int z, int layer) {
+ if (x >= 16 || y >= 256 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return BlockTemplates.getAirTemplate();
+ TerrainSubChunk subChunk = getSubChunk(y >> 4, false);
+ if (subChunk == null)
+ return BlockTemplates.getAirTemplate();
+ return subChunk.getBlockTemplate(x, y & 0xf, z, layer);
+ }
+
+ @NonNull
+ @Override
+ public Block getBlock(int x, int y, int z, int layer) {
+ if (x >= 16 || y >= 256 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ throw new IllegalArgumentException();
+ TerrainSubChunk subChunk = getSubChunk(y >> 4, false);
+ if (subChunk == null)
+ return BlockTemplates.getAirTemplate().getBlock();
+ return subChunk.getBlock(x, y & 0xf, z, layer);
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, int layer, @NonNull Block block) {
+ if (x >= 16 || y >= 256 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return;
+ int which = y >> 4;
+ TerrainSubChunk subChunk = getSubChunk(which, true);
+ if (subChunk == null) return;
+ subChunk.setBlock(x, y & 0xf, z, layer, block);
+ mDirtyList[which] = true;
+ BlockTemplate template = BlockTemplates.getBest(block);
+ // Height increased.
+ if (template != BlockTemplates.getAirTemplate() && getHeightMapValue(x, z) < y) {
+ mIs2dDirty = true;
+ setHeightMapValue(x, z, (short) (y + 1));
+ // Roof removed.
+ } else if (template == BlockTemplates.getAirTemplate() && getHeightMapValue(x, z) == y) {
+ mIs2dDirty = true;
+ int height = 0;
+ for (int h = y - 1; h >= 0; h--) {
+ if (getBlockTemplate(x, h, z) != BlockTemplates.getAirTemplate()) {
+ height = h + 1;
+ break;
+ }
+ }
+ setHeightMapValue(x, z, (short) height);
+ }
+ }
+
+ @Override
+ public int getBlockLightValue(int x, int y, int z) {
+ if (!mHasBlockLight || x >= 16 || y >= 256 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return 0;
+ TerrainSubChunk subChunk = getSubChunk(y >> 4, false);
+ if (subChunk == null) return 0;
+ return subChunk.getBlockLightValue(x, y & 0xf, z);
+ }
+
+ @Override
+ public int getSkyLightValue(int x, int y, int z) {
+ if (x >= 16 || y >= 256 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return 0;
+ TerrainSubChunk subChunk = getSubChunk(y >> 4, false);
+ if (subChunk == null) return 0;
+ return subChunk.getSkyLightValue(x, y & 0xf, z);
+ }
+
+ @Override
+ public int getHighestBlockYUnderAt(int x, int z, int y) {
+ if (x >= 16 || y >= 256 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return -1;
+ TerrainSubChunk subChunk;
+ for (int which = y >> 4; which >= 0; which--) {
+ subChunk = getSubChunk(which, false);
+ if (subChunk == null) continue;
+ for (int innerY = (which == (y >> 4)) ? y & 0xf : 15; innerY >= 0; innerY--) {
+ if (subChunk.getBlockTemplate(x, innerY, z, 0) != BlockTemplates.getAirTemplate())
+ return (which << 4) | innerY;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public int getCaveYUnderAt(int x, int z, int y) {
+ if (x >= 16 || y >= 256 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return -1;
+ TerrainSubChunk subChunk;
+ for (int which = y >> 4; which >= 0; which--) {
+ subChunk = getSubChunk(which, false);
+ if (subChunk == null) continue;
+ for (int innerY = (which == (y >> 4)) ? y & 0xf : 15; innerY >= 0; innerY--) {
+ if (subChunk.getBlockTemplate(x, innerY, z, 0) == BlockTemplates.getAirTemplate())
+ return (which << 4) | innerY;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public void save() throws WorldData.WorldDBException, IOException {
+
+ if (mIsError || mIsVoid) return;
+
+ WorldData worldData = mWorldData.get();
+ if (worldData == null)
+ throw new RuntimeException("World data is null.");
+
+ // Save biome and hightmap.
+ if (mIs2dDirty)
+ worldData.writeChunkData(
+ mChunkX, mChunkZ, ChunkTag.DATA_2D, mDimension, (byte) 0, false, data2D.array());
+
+ // Save subChunks.
+ for (int i = 0, mTerrainSubChunksLength = mTerrainSubChunks.length; i < mTerrainSubChunksLength; i++) {
+ TerrainSubChunk subChunk = mTerrainSubChunks[i];
+ if (subChunk == null || mVoidList[i] || !mDirtyList[i]) continue;
+ //Log.d(this,"Saving "+i);
+ subChunk.save(worldData, mChunkX, mChunkZ, mDimension, i);
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/Chunk.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/Chunk.java
index e473b1d5..fc888daa 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/Chunk.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/Chunk.java
@@ -1,122 +1,172 @@
package com.mithrilmania.blocktopograph.chunk;
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.Log;
import com.mithrilmania.blocktopograph.WorldData;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
+import com.mithrilmania.blocktopograph.block.Block;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
import com.mithrilmania.blocktopograph.map.Dimension;
-import java.util.concurrent.atomic.AtomicReferenceArray;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.stream.IntStream;
+
+public abstract class Chunk {
+
+ protected final WeakReference mWorldData;
+ protected final Version mVersion;
+ public final int mChunkX;
+ public final int mChunkZ;
+ public final Dimension mDimension;
+ protected NBTChunkData mEntity;
+ protected NBTChunkData mTileEntity;
+ boolean mIsVoid;
+ boolean mIsError;
+
+ Chunk(WorldData worldData, Version version, int chunkX, int chunkZ, Dimension dimension) {
+ mWorldData = new WeakReference<>(worldData);
+ mVersion = version;
+ mChunkX = chunkX;
+ mChunkZ = chunkZ;
+ mDimension = dimension;
+ mIsVoid = false;
+ mIsError = false;
+ try {
+ mEntity = version.createEntityChunkData(this);
+ mTileEntity = version.createBlockEntityChunkData(this);
+ } catch (Version.VersionException e) {
+ Log.d(this, e);
+ }
+ }
+ public static Chunk createEmpty(@NonNull WorldData worldData, int chunkX, int chunkZ, Dimension dimension,
+ Version createOfVersion) {
+ Chunk chunk;
+ switch (createOfVersion) {
+ case V1_2_PLUS:
+ case V1_16_PLUS:
+ try {
+ worldData.writeChunkData(chunkX, chunkZ, ChunkTag.GENERATOR_STAGE, dimension, (byte) 0, false, new byte[]{2, 0, 0, 0});
+ worldData.writeChunkData(chunkX, chunkZ, ChunkTag.VERSION_PRE16, dimension, (byte) 0, false, new byte[]{0xf});
+ chunk = new BedrockChunk(worldData, createOfVersion, chunkX, chunkZ, dimension, true);
+ } catch (Exception e) {
+ Log.d(Chunk.class, e);
+ chunk = new VoidChunk(worldData, createOfVersion, chunkX, chunkZ, dimension);
+ }
+ break;
+ default:
+ chunk = new VoidChunk(worldData, createOfVersion, chunkX, chunkZ, dimension);
+ }
+ return chunk;
+ }
-public class Chunk {
+ public static Chunk create(@NonNull WorldData worldData, int chunkX, int chunkZ, Dimension dimension,
+ boolean createIfMissing, Version createOfVersion) {
+ Version version;
+ try {
+ byte[] data = worldData.getChunkData(chunkX, chunkZ, ChunkTag.VERSION_PRE16, dimension);
+ if (data == null)
+ data = worldData.getChunkData(chunkX, chunkZ, ChunkTag.VERSION, dimension);
+ if (data == null && createIfMissing)
+ return createEmpty(worldData, chunkX, chunkZ, dimension, createOfVersion);
+ version = Version.getVersion(data);
+ } catch (WorldData.WorldDBLoadException | WorldData.WorldDBException e) {
+ Log.d(Chunk.class, e);
+ version = Version.ERROR;
+ }
+ Chunk chunk;
+ switch (version) {
+// case ERROR:
+// case OLD_LIMITED:
+// chunk = new VoidChunk(worldData, version, chunkX, chunkZ, dimension);
+// chunk.mIsError = true;
+// break;
+// case v0_9:
+// chunk = new PocketChunk(worldData, version, chunkX, chunkZ, dimension);
+// break;
+// case V1_0:
+// case V1_1:
+ case V1_2_PLUS:
+ case V1_16_PLUS:
+ chunk = new BedrockChunk(worldData, version, chunkX, chunkZ, dimension, false);
+ break;
+ case NULL:
+ default:
+ chunk = new VoidChunk(worldData, version, chunkX, chunkZ, dimension);
+ }
+ return chunk;
+ }
- public final WorldData worldData;
+ public final WorldData getWorldData() {
+ return mWorldData.get();
+ }
- public final int x, z;
- public final Dimension dimension;
+ public final boolean isVoid() {
+ return mIsVoid;
+ }
- private Version version;
+ public final boolean isError() {
+ return mIsError;
+ }
- private AtomicReferenceArray
- terrain = new AtomicReferenceArray<>(256);
+ abstract public boolean supportsBlockLightValues();
- private volatile NBTChunkData entity, blockEntity;
+ abstract public boolean supportsHeightMap();
- public Chunk(WorldData worldData, int x, int z, Dimension dimension) {
- this.worldData = worldData;
- this.x = x;
- this.z = z;
- this.dimension = dimension;
- }
+ abstract public int getHeightLimit();
- public TerrainChunkData getTerrain(byte subChunk) throws Version.VersionException {
- TerrainChunkData data = terrain.get(subChunk & 0xff);
- if(data == null){
- data = this.getVersion().createTerrainChunkData(this, subChunk);
- terrain.set(subChunk & 0xff, data);
- }
- return data;
- }
+ abstract public int getHeightMapValue(int x, int z);
- public NBTChunkData getEntity() throws Version.VersionException {
- if(entity == null) entity = this.getVersion().createEntityChunkData(this);
- return entity;
- }
+ abstract public int getBiome(int x, int z);
+
+ abstract public void setBiome(int x, int z, int id);
+ abstract public int getGrassColor(int x, int z);
- public NBTChunkData getBlockEntity() throws Version.VersionException {
- if(blockEntity == null) blockEntity = this.getVersion().createBlockEntityChunkData(this);
- return blockEntity;
+ @NonNull
+ public BlockTemplate getBlockTemplate(int x, int y, int z) {
+ return getBlockTemplate(x, y, z, 0);
}
- public Version getVersion(){
- if(this.version == null) try {
- byte[] data = this.worldData.getChunkData(x, z, ChunkTag.VERSION, dimension, (byte) 0, false);
- this.version = Version.getVersion(data);
- } catch (WorldData.WorldDBLoadException | WorldData.WorldDBException e) {
- e.printStackTrace();
- this.version = Version.ERROR;
- }
+ @NonNull
+ abstract public BlockTemplate getBlockTemplate(int x, int y, int z, int layer);
- return this.version;
+ @NonNull
+ public Block getBlock(int x, int y, int z) {
+ return getBlock(x, y, z, 0);
}
+ @NonNull
+ abstract public Block getBlock(int x, int y, int z, int layer);
- //TODO: should we use the heightmap???
- public int getHighestBlockYAt(int x, int z) throws Version.VersionException {
- Version cVersion = getVersion();
- TerrainChunkData data;
- for(int subChunk = cVersion.subChunks - 1; subChunk >= 0; subChunk--) {
- data = this.getTerrain((byte) subChunk);
- if (data == null || !data.loadTerrain()) continue;
+ abstract public void setBlock(int x, int y, int z, int layer, @NonNull Block block);
- for (int y = cVersion.subChunkHeight; y >= 0; y--) {
- if (data.getBlockTypeId(x & 15, y, z & 15) != 0)
- return (subChunk * cVersion.subChunkHeight) + y;
- }
- }
- return -1;
- }
+ abstract public int getBlockLightValue(int x, int y, int z);
- public int getHighestBlockYUnderAt(int x, int z, int y) throws Version.VersionException {
- Version cVersion = getVersion();
- int offset = y % cVersion.subChunkHeight;
- int subChunk = y / cVersion.subChunkHeight;
- TerrainChunkData data;
+ abstract public int getSkyLightValue(int x, int y, int z);
- for(; subChunk >= 0; subChunk--) {
- data = this.getTerrain((byte) subChunk);
- if (data == null || !data.loadTerrain()) continue;
+ abstract public int getHighestBlockYUnderAt(int x, int z, int y);
- for (y = offset; y >= 0; y--) {
- if (data.getBlockTypeId(x & 15, y, z & 15) != 0)
- return (subChunk * cVersion.subChunkHeight) + y;
- }
+ abstract public int getCaveYUnderAt(int x, int z, int y);
- //start at the top of the next chunk! (current offset might differ)
- offset = cVersion.subChunkHeight - 1;
- }
- return -1;
- }
+ abstract public void save() throws WorldData.WorldDBException, IOException;
- public int getCaveYUnderAt(int x, int z, int y) throws Version.VersionException {
- Version cVersion = getVersion();
- int offset = y % cVersion.subChunkHeight;
- int subChunk = y / cVersion.subChunkHeight;
- TerrainChunkData data;
-
- for(; subChunk >= 0; subChunk--) {
- data = this.getTerrain((byte) subChunk);
- if (data == null || !data.loadTerrain()) continue;
- for (y = offset; y >= 0; y--) {
- if (data.getBlockTypeId(x & 15, y, z & 15) == 0)
- return (subChunk * cVersion.subChunkHeight) + y;
- }
-
- //start at the top of the next chunk! (current offset might differ)
- offset = cVersion.subChunkHeight - 1;
- }
- return -1;
+ public void deleteThis() throws Exception {
+ // TODO: delete all with given prefix
+ WorldData worldData = mWorldData.get();
+ if (worldData == null) throw new RuntimeException("World data is null.");
+ worldData.removeFullChunk(mChunkX, mChunkZ, mDimension);
+ // Prevent saving.
+ mIsError = true;
}
+ public final NBTChunkData getEntity() {
+ return mEntity;
+ }
+ public final NBTChunkData getBlockEntity() {
+ return mTileEntity;
+ }
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkData.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkData.java
index f0f496f3..01ed759a 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkData.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkData.java
@@ -4,15 +4,15 @@
import com.mithrilmania.blocktopograph.WorldData;
import java.io.IOException;
+import java.lang.ref.WeakReference;
public abstract class ChunkData {
- public final Chunk chunk;
+ public final WeakReference chunk;
-
- public ChunkData(Chunk chunk){
- this.chunk = chunk;
+ public ChunkData(Chunk chunk) {
+ this.chunk = new WeakReference<>(chunk);
}
public abstract void createEmpty();
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkManager.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkManager.java
index fbdf8a06..82f12d61 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkManager.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkManager.java
@@ -1,49 +1,5 @@
package com.mithrilmania.blocktopograph.chunk;
-import android.annotation.SuppressLint;
-
-import com.mithrilmania.blocktopograph.WorldData;
-import com.mithrilmania.blocktopograph.chunk.terrain.V0_9_TerrainChunkData;
-import com.mithrilmania.blocktopograph.map.Dimension;
-
-import java.util.HashMap;
-import java.util.Map;
-
-
public class ChunkManager {
- @SuppressLint("UseSparseArrays")
- private Map chunks = new HashMap<>();
-
- private WorldData worldData;
-
- public final Dimension dimension;
-
- public ChunkManager(WorldData worldData, Dimension dimension){
- this.worldData = worldData;
- this.dimension = dimension;
- }
-
-
- public static long xzToKey(int x, int z){
- return (((long) x) << 32) | (((long) z) & 0xFFFFFFFFL);
- }
-
- public Chunk getChunk(int cX, int cZ) {
- long key = xzToKey(cX, cZ);
- Chunk chunk = chunks.get(key);
- if(chunk == null) {
- chunk = new Chunk(worldData, cX, cZ, dimension);
- this.chunks.put(key, chunk);
- }
- return chunk;
- }
-
- public void disposeAll(){
- this.chunks.clear();
- }
-
-
-
-
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkTag.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkTag.java
index 50344d49..be7ab281 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkTag.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/ChunkTag.java
@@ -2,7 +2,7 @@
/**
* Reference from Tommaso Checchi (/u/mojang_tommo), MCPE developer:
- * https://www.reddit.com/r/MCPE/comments/5cw2tm/level_format_changes_in_mcpe_0171_100/d9zv9s8/
+ * https://www.reddit.com/r/MCPE/comments/5cw2tm/level_format_changes_in_mcpe_0171_100/d9zv9s8/
*/
public enum ChunkTag {
@@ -15,13 +15,14 @@ public enum ChunkTag {
PENDING_TICKS((byte) 0x33),//TODO untested
BLOCK_EXTRA_DATA((byte) 0x34),//TODO untested, 32768 bytes, used for top-snow.
BIOME_STATE((byte) 0x35),//TODO untested
- VERSION((byte) 0x76);
-
+ GENERATOR_STAGE((byte) 0x36),
+ VERSION_PRE16((byte) 0x76),
+ VERSION((byte) 0x2c);;
public final byte dataID;
- ChunkTag(byte dataID){
+ ChunkTag(byte dataID) {
this.dataID = dataID;
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/NBTChunkData.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/NBTChunkData.java
index ac685f61..5d78fbf6 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/NBTChunkData.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/NBTChunkData.java
@@ -22,7 +22,8 @@ public NBTChunkData(Chunk chunk, ChunkTag dataType) {
}
public void load() throws WorldData.WorldDBLoadException, WorldData.WorldDBException, IOException {
- loadFromByteArray(chunk.worldData.getChunkData(chunk.x, chunk.z, dataType, this.chunk.dimension, (byte) 0, false));
+ Chunk chunk = this.chunk.get();
+ loadFromByteArray(chunk.getWorldData().getChunkData(chunk.mChunkX, chunk.mChunkZ, dataType, chunk.mDimension, (byte) 0, false));
}
public void loadFromByteArray(byte[] data) throws IOException {
@@ -32,12 +33,13 @@ public void loadFromByteArray(byte[] data) throws IOException {
public void write() throws WorldData.WorldDBException, IOException {
if (this.tags == null) this.tags = new ArrayList<>();
byte[] data = DataConverter.write(this.tags);
- this.chunk.worldData.writeChunkData(this.chunk.x, this.chunk.z, this.dataType, this.chunk.dimension, (byte) 0, false, data);
+ Chunk chunk = this.chunk.get();
+ chunk.getWorldData().writeChunkData(chunk.mChunkX, chunk.mChunkZ, this.dataType, chunk.mDimension, (byte) 0, false, data);
}
@Override
public void createEmpty() {
- if(this.tags == null) this.tags = new ArrayList<>();
+ if (this.tags == null) this.tags = new ArrayList<>();
this.tags.add(new IntTag("Placeholder", 42));
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/PocketChunk.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/PocketChunk.java
new file mode 100644
index 00000000..f4a9ec15
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/PocketChunk.java
@@ -0,0 +1,223 @@
+/*
+package com.mithrilmania.blocktopograph.chunk;
+
+import android.graphics.Color;
+
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+import com.mithrilmania.blocktopograph.map.Dimension;
+
+import java.nio.ByteBuffer;
+
+public final class PocketChunk extends Chunk {
+
+
+ private static final int POS_BLOCK_IDS = 0;
+ private static final int POS_META_DATA = 0x8000;
+ private static final int POS_SKY_LIGHT = 0xc000;
+ private static final int POS_BLOCK_LIGHT = 0x10000;
+ //Isn't this "dirty table"?
+ //Seems Proto got it wrong...
+ private static final int POS_HEIGHTMAP = 0x14000;
+ private static final int POS_BIOME_DATA = 0x14100;
+ private static final int LENGTH = 0x14500;
+
+ private volatile ByteBuffer mData;
+
+ PocketChunk(WorldData worldData, Version version, int chunkX, int chunkZ, Dimension dimension) {
+ super(worldData, version, chunkX, chunkZ, dimension);
+ tryLoad();
+ }
+
+ private void tryLoad() {
+ if (mData == null) {
+ try {
+ byte[] rawData = mWorldData.get().getChunkData(mChunkX, mChunkZ, ChunkTag.V0_9_LEGACY_TERRAIN, mDimension, (byte) 0, false);
+ if (rawData == null) {
+ mIsVoid = true;
+ return;
+ }
+ mData = ByteBuffer.allocate(rawData.length);
+ mData.put(rawData, 0, rawData.length);
+ mIsVoid = false;
+ } catch (Exception e) {
+ mIsError = true;
+ mIsVoid = true;
+ }
+ }
+ }
+
+ public void createEmpty() {
+ byte[] chunk = new byte[LENGTH];
+ int x, y, z, i = 0;
+ byte bedrock = (byte) 7;
+ byte sandstone = (byte) 24;
+
+ //generate super basic terrain (one layer of bedrock, 31 layers of sandstone)
+ //Emmm but why
+ for (x = 0; x < 16; x++) {
+ for (z = 0; z < 16; z++) {
+ for (y = 0; y < 128; y++, i++) {
+ chunk[i] = (y == 0 ? bedrock : (y < 32 ? sandstone : 0));
+ }
+ }
+ }
+
+ //fill meta-data with 0
+ for (; i < POS_SKY_LIGHT; i++) {
+ chunk[i] = 0;
+ }
+
+ //fill blocklight with 0xff
+ for (; i < POS_BLOCK_LIGHT; i++) {
+ chunk[i] = (byte) 0xff;
+ }
+
+ //fill block-light with 0xff
+ for (; i < POS_HEIGHTMAP; i++) {
+ chunk[i] = (byte) 0xff;
+ }
+
+ //fill heightmap
+ for (; i < POS_BIOME_DATA; i++) {
+ chunk[i] = 32;
+ }
+
+ //fill biome data
+ for (; i < LENGTH; ) {
+ chunk[i++] = 1;//biome: plains
+ chunk[i++] = (byte) 42;//r
+ chunk[i++] = (byte) 42;//g
+ chunk[i++] = (byte) 42;//b
+ }
+
+ this.mData = ByteBuffer.wrap(chunk);
+ }
+
+ private int getOffset(int x, int y, int z) {
+ // I prefer shifts than multiplies, prefer "bit or" than plus.
+ // I know compiler and Android runtime can optimize
+ // but this is cool, right?!
+ // No, not at all. I saw you filled the shift wrong and debugged for an hour one day.
+ return (((x << 4) | z) << 7) | y;
+ }
+
+ private int get2dOffset(int x, int z) {
+ return (z << 4) | x;
+ }
+
+ @Override
+ public boolean supportsBlockLightValues() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsHeightMap() {
+ return false;
+ }
+
+ @Override
+ public int getHeightLimit() {
+ return 128;
+ }
+
+ @Override
+ public int getHeightMapValue(int x, int z) {
+ if (x >= 16 || z >= 16 || x < 0 || z < 0 || mIsVoid)
+ return 0;
+ //There's no height map saved here!
+ //Do it the hard way!
+ for (int offset = POS_BLOCK_IDS + getOffset(x, 127, z), y = 127; y >= 0; y--, offset--) {
+ if (mData.get(offset) != 0) return y + 1;
+ }
+ return 0;
+ }
+
+ @Override
+ public int getBiome(int x, int z) {
+ return mData.get(POS_BIOME_DATA + (get2dOffset(x, z) << 2));
+ }
+
+ @Override
+ public void setBiome(int x, int z, int id) {
+ mData.put(POS_BIOME_DATA + (get2dOffset(x, z) << 2), (byte) id);
+ }
+
+ @Override
+ public int getGrassColor(int x, int z) {
+ int offset = POS_BIOME_DATA + (get2dOffset(x, z) << 2);
+ return Color.rgb(mData.get(offset + 1) & 0xff, mData.get(offset + 2) & 0xff, mData.get(offset + 3) & 0xff);
+ }
+
+ @NonNull
+ @Override
+ public OldBlock getBlock(int x, int y, int z) {
+ return getBlock(x, y, z, 0);
+ }
+
+ @NonNull
+ @Override
+ public OldBlock getBlock(int x, int y, int z, int layer) {
+ return mWorldData.get().mOldBlockRegistry.createBlock(getKnownBlock(x, y, z, layer));
+ }
+
+ @NonNull
+ private KnownBlockRepr getKnownBlock(int x, int y, int z, int layer) {
+ if (x >= 16 || y >= 128 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return KnownBlockRepr.B_0_0_AIR;
+ int offset = getOffset(x, y, z);
+ int id = mData.get(POS_BLOCK_IDS + offset) & 0xff;
+ int data = mData.get(POS_META_DATA + (offset >>> 1));
+ data = (offset & 1) == 1 ? ((data >>> 4) & 0xf) : (data & 0xf);
+ return KnownBlockRepr.getBestBlock(id, data);
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, int layer, @NonNull OldBlock oldBlock) {
+ //TODO implement setBlock for pocket chunk
+ }
+
+ @Override
+ public int getBlockLightValue(int x, int y, int z) {
+ if (x >= 16 || y >= 128 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return 0;
+ int offset = getOffset(x, y, z);
+ int dualData = mData.get(POS_BLOCK_LIGHT + (offset >>> 1));
+ return (offset & 1) == 1 ? (dualData >>> 4) & 0xf : dualData & 0xf;
+ }
+
+ @Override
+ public int getSkyLightValue(int x, int y, int z) {
+ if (x >= 16 || y >= 128 || z >= 16 || x < 0 || y < 0 || z < 0 || mIsVoid)
+ return 0;
+ int offset = getOffset(x, y, z);
+ int dualData = mData.get(POS_SKY_LIGHT + (offset >>> 1));
+ return (offset & 1) == 1 ? (dualData >>> 4) & 0xf : dualData & 0xf;
+ }
+
+ @Override
+ public int getHighestBlockYUnderAt(int x, int z, int y) {
+ for (int yy = y; yy >= 0; yy--) {
+ if (getKnownBlock(x & 0xf, yy, z & 0xf, 0) != KnownBlockRepr.B_0_0_AIR) return yy;
+ }
+ return -1;
+ }
+
+ @Override
+ public int getCaveYUnderAt(int x, int z, int y) {
+ for (int yy = y; yy >= 0; yy--) {
+ if (getKnownBlock(x & 0xf, yy, z & 0xf, 0) == KnownBlockRepr.B_0_0_AIR) return yy;
+ }
+ return -1;
+ }
+
+ @Override
+ public void save() {
+ // TODO implement save for pocket chunk
+ if (mIsError || mIsVoid) return;
+ }
+}
+*/
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/Version.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/Version.java
index 5d3c57d7..5d0386d3 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/Version.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/Version.java
@@ -3,12 +3,9 @@
import android.util.SparseArray;
-import com.mithrilmania.blocktopograph.Log;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
-import com.mithrilmania.blocktopograph.chunk.terrain.V0_9_TerrainChunkData;
-import com.mithrilmania.blocktopograph.chunk.terrain.V1_0_TerrainChunkData;
-import com.mithrilmania.blocktopograph.chunk.terrain.V1_1_TerrainChunkData;
-import com.mithrilmania.blocktopograph.util.ConvertUtil;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
public enum Version {
@@ -17,15 +14,17 @@ public enum Version {
OLD_LIMITED("v0.2.0", "classic mcpe, 16x16x16x16x18 world, level.dat; introduced in v0.2.0", 1, 128, 1),
v0_9("v0.9.0", "infinite xz, zlib leveldb; introduced in v0.9.0", 2, 128, 1),
V1_0("v1.0.0", "Stacked sub-chunks, 256 world-height, 16 high sub-chunks; introduced in alpha v1.0.0 (v0.17)", 3, 16, 16),
- V1_1("v1.1.0", "Block-light is not stored anymore", 4, 16, 16);
+ V1_1("v1.1.0", "KnownBlockRepr-light is not stored anymore", 4, 16, 16),
+ V1_2_PLUS("v1.2.0.13", "Global numeric id replaced with string id and per-chunk numeric id", 7, 16, 16),
+ V1_16_PLUS("v1.16(17)", "val is replaced by block states",0x16,16,16);
- public static final int LATEST_SUPPORTED_VERSION = V1_1.id;
+ public static final int LATEST_SUPPORTED_VERSION = V1_16_PLUS.id;
public final String displayName, description;
public final int id, subChunkHeight, subChunks;
- Version(String displayName, String description, int id, int subChunkHeight, int subChunks){
+ Version(String displayName, String description, int id, int subChunkHeight, int subChunks) {
this.displayName = displayName;
this.description = description;
this.id = id;
@@ -34,25 +33,29 @@ public enum Version {
}
private static final SparseArray versionMap;
+
static {
versionMap = new SparseArray<>();
- for(Version b : Version.values()){
+ for (Version b : Version.values()) {
versionMap.put(b.id, b);
}
}
- public static Version getVersion(byte[] data){
+
+ @NonNull
+ public static Version getVersion(@Nullable byte[] data) {
//Log.d("Data version: "+ ConvertUtil.bytesToHexStr(data));
//`data` is supposed to be one byte,
// but it might grow to contain more data later on, or larger version ids.
// Looking up the first byte is sufficient for now.
- if(data == null || data.length <= 0) {
+ if (data == null || data.length <= 0) {
return NULL;
} else {
int versionNumber = data[0] & 0xff;
//fallback version
- if(versionNumber > LATEST_SUPPORTED_VERSION) {
+ //You can't just do this...
+ if (versionNumber > LATEST_SUPPORTED_VERSION) {
versionNumber = LATEST_SUPPORTED_VERSION;
}
@@ -62,27 +65,9 @@ public static Version getVersion(byte[] data){
}
}
- public TerrainChunkData createTerrainChunkData(Chunk chunk, byte subChunk) throws VersionException {
- switch (this){
- case ERROR:
- case NULL:
- return null;
- case OLD_LIMITED:
- throw new VersionException("Handling terrain chunk data is NOT supported for this version!", this);
- case v0_9:
- return new V0_9_TerrainChunkData(chunk, subChunk);
- case V1_0:
- return new V1_0_TerrainChunkData(chunk, subChunk);
- case V1_1:
- return new V1_1_TerrainChunkData(chunk, subChunk);
- default:
- //use the latest version, like nothing will ever happen...
- return new V1_1_TerrainChunkData(chunk, subChunk);
- }
- }
-
+ @Nullable
public NBTChunkData createEntityChunkData(Chunk chunk) throws VersionException {
- switch (this){
+ switch (this) {
case ERROR:
case NULL:
return null;
@@ -94,8 +79,9 @@ public NBTChunkData createEntityChunkData(Chunk chunk) throws VersionException {
}
}
+ @Nullable
public NBTChunkData createBlockEntityChunkData(Chunk chunk) throws VersionException {
- switch (this){
+ switch (this) {
case ERROR:
case NULL:
return null;
@@ -107,14 +93,16 @@ public NBTChunkData createBlockEntityChunkData(Chunk chunk) throws VersionExcept
}
}
+ @NonNull
+
@Override
- public String toString(){
- return "[MCPE version \""+displayName+"\" (version-code: "+id+")]";
+ public String toString() {
+ return "[MCPE version \"" + displayName + "\" (version-code: " + id + ")]";
}
public static class VersionException extends Exception {
- VersionException(String msg, Version version){
+ VersionException(String msg, @NonNull Version version) {
super(msg + " " + version.toString());
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/VoidChunk.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/VoidChunk.java
new file mode 100644
index 00000000..6c521804
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/VoidChunk.java
@@ -0,0 +1,94 @@
+package com.mithrilmania.blocktopograph.chunk;
+
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.Block;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.map.Dimension;
+
+
+public final class VoidChunk extends Chunk {
+
+ VoidChunk(WorldData worldData, Version version, int chunkX, int chunkZ, Dimension dimension) {
+ super(worldData, version, chunkX, chunkZ, dimension);
+ mIsVoid = true;
+ }
+
+ @Override
+ public boolean supportsBlockLightValues() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsHeightMap() {
+ return false;
+ }
+
+ @Override
+ public int getHeightLimit() {
+ return 0;
+ }
+
+ @Override
+ public int getHeightMapValue(int x, int z) {
+ return 0;
+ }
+
+ @Override
+ public int getBiome(int x, int z) {
+ return 0;
+ }
+
+ @Override
+ public void setBiome(int x, int z, int id) {
+ }
+
+ @Override
+ public int getGrassColor(int x, int z) {
+ return 0;
+ }
+
+ @NonNull
+ @Override
+ public BlockTemplate getBlockTemplate(int x, int y, int z, int layer) {
+ return BlockTemplates.getAirTemplate();
+ }
+
+ @NonNull
+ @Override
+ public Block getBlock(int x, int y, int z, int layer) {
+ throw new RuntimeException();
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, int layer, @NonNull Block block) {
+ throw new RuntimeException();
+ }
+
+ @Override
+ public int getBlockLightValue(int x, int y, int z) {
+ return 0;
+ }
+
+ @Override
+ public int getSkyLightValue(int x, int y, int z) {
+ return 0;
+ }
+
+ @Override
+ public int getHighestBlockYUnderAt(int x, int z, int y) {
+ return -1;
+ }
+
+ @Override
+ public int getCaveYUnderAt(int x, int z, int y) {
+ return -1;
+ }
+
+ @Override
+ public void save() {
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/PreV1d2d13TerrainSubChunk.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/PreV1d2d13TerrainSubChunk.java
new file mode 100644
index 00000000..3cb23bb6
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/PreV1d2d13TerrainSubChunk.java
@@ -0,0 +1,77 @@
+/*
+package com.mithrilmania.blocktopograph.chunk.terrain;
+
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.block.OldBlockRegistry;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+import com.mithrilmania.blocktopograph.map.Dimension;
+
+import java.nio.ByteBuffer;
+
+public final class PreV1d2d13TerrainSubChunk extends TerrainSubChunk {
+
+ private static final int POS_BLOCK_IDS = 1;
+ private static final int POS_META_DATA = 0x1001;
+ private static final int POS_SKY_LIGHT = 0x1801;
+ private static final int POS_BLOCK_LIGHT = 0x2001;
+ private static final int TERRAIN_MAX_LENGTH = 0x2801;
+
+ private ByteBuffer mData;
+
+ PreV1d2d13TerrainSubChunk(@NonNull ByteBuffer raw, @NonNull OldBlockRegistry oldBlockRegistry) {
+
+ super(oldBlockRegistry);
+
+ int size = raw.capacity();
+ if (size < POS_SKY_LIGHT || size > TERRAIN_MAX_LENGTH) {
+ mIsError = true;
+ return;
+ }
+ mIsError = false;
+ mData = ByteBuffer.allocate(size);
+ mData.put(raw);
+ mHasSkyLight = size >= POS_BLOCK_LIGHT;
+ mHasBlockLight = size == TERRAIN_MAX_LENGTH;
+ }
+
+ @NonNull
+ @Override
+ public OldBlock getBlock(int x, int y, int z, int layer) {
+ if (mIsError) return getAir();
+ int offset = getOffset(x, y, z);
+ int id = mData.get(POS_BLOCK_IDS + offset) & 0xff;
+ int data = mData.get(POS_META_DATA + (offset >>> 1));
+ data = (offset & 1) == 1 ? ((data >>> 4) & 0xf) : (data & 0xf);
+ return wrapKnownBlock(KnownBlockRepr.getBestBlock(id, data));
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, int layer, @NonNull OldBlock oldBlock) {
+ // TODO implement setBlock for pre v1.2.13 subChunk.
+ }
+
+ @Override
+ public int getBlockLightValue(int x, int y, int z) {
+ if (mIsError || !mHasBlockLight) return 0;
+ int offset = getOffset(x, y, z);
+ int dualData = mData.get(POS_BLOCK_LIGHT + (offset >>> 1));
+ return (offset & 1) == 1 ? (dualData >>> 4) & 0xf : dualData & 0xf;
+ }
+
+ @Override
+ public int getSkyLightValue(int x, int y, int z) {
+ if (mIsError || !mHasSkyLight) return 0;
+ int offset = getOffset(x, y, z);
+ int dualData = mData.get(POS_SKY_LIGHT + (offset >>> 1));
+ return (offset & 1) == 1 ? (dualData >>> 4) & 0xf : dualData & 0xf;
+ }
+
+ @Override
+ public void save(WorldData worldData, int chunkX, int chunkZ, Dimension dimension, int which) {
+ // TODO implement save for pre v1.2.13 subChunk.
+ }
+}
+*/
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/TerrainChunkData.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/TerrainChunkData.java
index 83954845..e91b0a4c 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/TerrainChunkData.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/TerrainChunkData.java
@@ -2,17 +2,25 @@
import com.mithrilmania.blocktopograph.chunk.Chunk;
import com.mithrilmania.blocktopograph.chunk.ChunkData;
+import com.mithrilmania.blocktopograph.util.Noise;
public abstract class TerrainChunkData extends ChunkData {
public final byte subChunk;
+ protected boolean mNotFailed;
+
public TerrainChunkData(Chunk chunk, byte subChunk) {
super(chunk);
+ this.mNotFailed = true;
this.subChunk = subChunk;
}
+ public final boolean hasNotFailed() {
+ return mNotFailed;
+ }
+
public abstract boolean loadTerrain();
public abstract boolean load2DData();
@@ -41,5 +49,21 @@ public TerrainChunkData(Chunk chunk, byte subChunk) {
public abstract int getHeightMapValue(int x, int z);
-
+ protected int getNoise(int base, int x, int z) {
+ // noise values are between -1 and 1
+ // 0.0001 is added to the coordinates because integer values result in 0
+ Chunk chunk = this.chunk.get();
+ double oct1 = Noise.noise(
+ ((double) (chunk.mChunkX * 16 + x) / 100.0) + 0.0001,
+ ((double) (chunk.mChunkZ * 16 + z) / 100.0) + 0.0001);
+ double oct2 = Noise.noise(
+ ((double) (chunk.mChunkX * 16 + x) / 20.0) + 0.0001,
+ ((double) (chunk.mChunkZ * 16 + z) / 20.0) + 0.0001);
+ double oct3 = Noise.noise(
+ ((double) (chunk.mChunkX * 16 + x) / 3.0) + 0.0001,
+ ((double) (chunk.mChunkZ * 16 + z) / 3.0) + 0.0001);
+ return (int) (base + 60 + (40 * oct1) + (14 * oct2) + (6 * oct3));
+ }
+
+
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/TerrainSubChunk.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/TerrainSubChunk.java
new file mode 100644
index 00000000..9940a14d
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/TerrainSubChunk.java
@@ -0,0 +1,117 @@
+package com.mithrilmania.blocktopograph.chunk.terrain;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.Block;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.map.Dimension;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public abstract class TerrainSubChunk {
+
+// private final WeakReference mBlockRegistry;
+
+ boolean mHasSkyLight;
+ boolean mHasBlockLight;
+ boolean mIsError;
+
+ protected TerrainSubChunk() {
+// mBlockRegistry = new WeakReference<>(oldBlockRegistry);
+ }
+
+ @Nullable
+ public static TerrainSubChunk create(@NonNull byte[] rawData) {
+ TerrainSubChunk subChunk;
+ ByteBuffer byteBuffer = ByteBuffer.wrap(rawData);
+ switch (rawData[0]) {
+// case 0:
+// case 2:
+// case 3:
+// case 4:
+// case 5:
+// case 6:
+// case 7:
+// subChunk = new PreV1d2d13TerrainSubChunk(byteBuffer, oldBlockRegistry);
+// break;
+ case 1:
+ case 8:
+ subChunk = new V1d2d13TerrainSubChunk(byteBuffer);
+ break;
+ default:
+ subChunk = null;
+ }
+ return subChunk;
+ }
+
+ @Nullable
+ public static TerrainSubChunk createEmpty(int preferredVersion) {
+ TerrainSubChunk subChunk;
+ switch (preferredVersion) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ subChunk = null;
+ break;
+ case 1:
+ case 8:
+ subChunk = new V1d2d13TerrainSubChunk();
+ break;
+ default:
+ subChunk = null;
+ }
+ return subChunk;
+ }
+
+// @NonNull
+// protected OldBlock wrapKnownBlock(KnownBlockRepr knownBlock) {
+// // TODO: This would be not efficiency for old saves, add corresponding oldBlock to known blocks.
+// return mBlockRegistry.get().createBlock(knownBlock);
+// }
+
+ @NonNull
+ abstract public BlockTemplate getBlockTemplate(int x, int y, int z, int layer);
+
+ @NonNull
+ abstract public Block getBlock(int x, int y, int z, int layer);
+
+ abstract public void setBlock(int x, int y, int z, int layer, @NonNull Block block);
+
+ abstract public int getBlockLightValue(int x, int y, int z);
+
+ abstract public int getSkyLightValue(int x, int y, int z);
+
+ protected static final int getOffset(int x, int y, int z) {
+ return (((x << 4) | z) << 4) | y;
+ }
+
+
+ public final boolean hasBlockLight() {
+ return mHasBlockLight;
+ }
+
+
+ public final boolean isError() {
+ return mIsError;
+ }
+
+// @Nullable
+// protected OldBlockRegistry getBlockRegistry() {
+// OldBlockRegistry oldBlockRegistry = mBlockRegistry.get();
+// if (oldBlockRegistry == null) {
+// mIsError = true;
+// }
+// return oldBlockRegistry;
+// }
+
+ abstract public void save(WorldData worldData, int chunkX, int chunkZ, Dimension dimension, int which) throws WorldData.WorldDBException, IOException;
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V0_9_TerrainChunkData.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V0_9_TerrainChunkData.java
index ca177522..7838fec8 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V0_9_TerrainChunkData.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V0_9_TerrainChunkData.java
@@ -1,3 +1,4 @@
+/*
package com.mithrilmania.blocktopograph.chunk.terrain;
import com.mithrilmania.blocktopograph.WorldData;
@@ -31,36 +32,38 @@ public class V0_9_TerrainChunkData extends TerrainChunkData {
public V0_9_TerrainChunkData(Chunk chunk, byte subChunk) {
super(chunk, subChunk);
+ mNotFailed = tryLoad();
}
@Override
public void write() throws IOException, WorldData.WorldDBException {
- this.chunk.worldData.writeChunkData(chunk.x, chunk.z, ChunkTag.V0_9_LEGACY_TERRAIN, chunk.dimension, subChunk, false, toByteArray());
+ Chunk chunk = this.chunk.get();
+ chunk.getWorldData().writeChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.V0_9_LEGACY_TERRAIN, chunk.mDimension, subChunk, false, toByteArray());
}
@Override
- public boolean loadTerrain(){
- return tryLoad();
+ public boolean loadTerrain() {
+ return mNotFailed;
}
@Override
- public boolean load2DData(){
- return tryLoad();
+ public boolean load2DData() {
+ return mNotFailed;
}
public boolean tryLoad() {
- if(buf == null){
+ if (buf == null) {
try {
- byte[] rawData = this.chunk.worldData.getChunkData(chunk.x, chunk.z, ChunkTag.V0_9_LEGACY_TERRAIN, chunk.dimension, subChunk, false);
- if(rawData == null) return false;
+ Chunk chunk = this.chunk.get();
+ byte[] rawData = chunk.getWorldData().getChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.V0_9_LEGACY_TERRAIN, chunk.mDimension, subChunk, false);
+ if (rawData == null) return false;
this.buf = ByteBuffer.wrap(rawData);
return true;
- } catch (Exception e){
+ } catch (Exception e) {
//data is not present
return false;
}
- }
- else return true;
+ } else return true;
}
public byte[] toByteArray() throws IOException {
@@ -77,36 +80,36 @@ public void createEmpty() {
byte sandstone = (byte) 24;
//generate super basic terrain (one layer of bedrock, 31 layers of sandstone)
- for(x = 0; x < chunkW; x++){
- for(z = 0; z < chunkL; z++){
- for(y = 0; y < chunkH; y++, i++){
+ for (x = 0; x < chunkW; x++) {
+ for (z = 0; z < chunkL; z++) {
+ for (y = 0; y < chunkH; y++, i++) {
chunk[i] = (y == 0 ? bedrock : (y < 32 ? sandstone : 0));
}
}
}
//fill meta-data with 0
- for(; i < POS_SKY_LIGHT; i++){
+ for (; i < POS_SKY_LIGHT; i++) {
chunk[i] = 0;
}
//fill blocklight with 0xff
- for(; i < POS_BLOCK_LIGHT; i++){
+ for (; i < POS_BLOCK_LIGHT; i++) {
chunk[i] = (byte) 0xff;
}
//fill block-light with 0xff
- for(; i < POS_HEIGHTMAP; i++){
+ for (; i < POS_HEIGHTMAP; i++) {
chunk[i] = (byte) 0xff;
}
//fill heightmap
- for(; i < POS_BIOME_DATA; i++){
+ for (; i < POS_BIOME_DATA; i++) {
chunk[i] = 32;
}
//fill biome data
- for(; i < LENGTH;){
+ for (; i < LENGTH; ) {
chunk[i++] = 1;//biome: plains
chunk[i++] = (byte) 42;//r
chunk[i++] = (byte) 42;//g
@@ -161,9 +164,11 @@ public boolean supportsBlockLightValues() {
return true;
}
- /**
+ */
+/**
* Sets a block type, and also set the corresponding dirty table entry and set the saving flag.
- */
+ *//*
+
@Override
public void setBlockTypeId(int x, int y, int z, int type) {
if (x >= chunkW || y >= chunkH || z >= chunkL || x < 0 || y < 0 || z < 0) {
@@ -221,3 +226,4 @@ public int getHeightMapValue(int x, int z) {
}
}
+*/
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_0_TerrainChunkData.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_0_TerrainChunkData.java
index a31cb3b5..8d1eda7a 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_0_TerrainChunkData.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_0_TerrainChunkData.java
@@ -1,11 +1,10 @@
+/*
package com.mithrilmania.blocktopograph.chunk.terrain;
import com.mithrilmania.blocktopograph.WorldData;
import com.mithrilmania.blocktopograph.chunk.Chunk;
import com.mithrilmania.blocktopograph.chunk.ChunkTag;
-import com.mithrilmania.blocktopograph.chunk.Version;
import com.mithrilmania.blocktopograph.map.Biome;
-import com.mithrilmania.blocktopograph.util.Noise;
import java.nio.ByteBuffer;
@@ -33,44 +32,46 @@ public class V1_0_TerrainChunkData extends TerrainChunkData {
public V1_0_TerrainChunkData(Chunk chunk, byte subChunk) {
super(chunk, subChunk);
+ mNotFailed = loadTerrain();
}
@Override
public void write() throws WorldData.WorldDBException {
- this.chunk.worldData.writeChunkData(chunk.x, chunk.z, ChunkTag.TERRAIN, chunk.dimension, subChunk, true, terrainData.array());
- this.chunk.worldData.writeChunkData(chunk.x, chunk.z, ChunkTag.DATA_2D, chunk.dimension, subChunk, true, data2D.array());
+ Chunk chunk = this.chunk.get();
+ chunk.getWorldData().writeChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.TERRAIN, chunk.mDimension, subChunk, true, terrainData.array());
+ chunk.getWorldData().writeChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.DATA_2D, chunk.mDimension, subChunk, true, data2D.array());
}
@Override
public boolean loadTerrain() {
- if(terrainData == null){
+ if (terrainData == null) {
try {
- byte[] rawData = this.chunk.worldData.getChunkData(chunk.x, chunk.z, ChunkTag.TERRAIN, chunk.dimension, subChunk, true);
- if(rawData == null) return false;
+ Chunk chunk = this.chunk.get();
+ byte[] rawData = chunk.getWorldData().getChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.TERRAIN, chunk.mDimension, subChunk, true);
+ if (rawData == null) return false;
this.terrainData = ByteBuffer.wrap(rawData);
return true;
- } catch (Exception e){
+ } catch (Exception e) {
//data is not present
return false;
}
- }
- else return true;
+ } else return mNotFailed;
}
@Override
public boolean load2DData() {
- if(data2D == null){
+ if (data2D == null) {
try {
- byte[] rawData = this.chunk.worldData.getChunkData(chunk.x, chunk.z, ChunkTag.DATA_2D, chunk.dimension, subChunk, false);
- if(rawData == null) return false;
+ Chunk chunk = this.chunk.get();
+ byte[] rawData = chunk.getWorldData().getChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.DATA_2D, chunk.mDimension, subChunk, false);
+ if (rawData == null) return false;
this.data2D = ByteBuffer.wrap(rawData);
return true;
- } catch (Exception e){
+ } catch (Exception e) {
//data is not present
return false;
}
- }
- else return true;
+ } else return true;
}
@@ -87,9 +88,9 @@ public void createEmpty() {
byte sandstone = (byte) 24;
//generate super basic terrain (one layer of bedrock, 31 layers of sandstone)
- for(x = 0; x < chunkW; x++){
- for(z = 0; z < chunkL; z++){
- for(y = 0, realY = chunkH * this.subChunk; y < chunkH; y++, i++, realY++){
+ for (x = 0; x < chunkW; x++) {
+ for (z = 0; z < chunkL; z++) {
+ for (y = 0, realY = chunkH * this.subChunk; y < chunkH; y++, i++, realY++) {
terrain[i] = (realY == 0 ? bedrock : (realY < 32 ? sandstone : 0));
}
}
@@ -97,17 +98,17 @@ public void createEmpty() {
//fill meta-data with 0
- for(; i < POS_META_DATA; i++){
+ for (; i < POS_META_DATA; i++) {
terrain[i] = (byte) 0;
}
//fill blocklight with 0xff
- for(; i < POS_BLOCK_LIGHT; i++){
+ for (; i < POS_BLOCK_LIGHT; i++) {
terrain[i] = (byte) 0xff;
}
//fill block-light with 0xff
- for(; i < TERRAIN_LENGTH; i++){
+ for (; i < TERRAIN_LENGTH; i++) {
terrain[i] = (byte) 0xff;
}
@@ -115,18 +116,18 @@ public void createEmpty() {
i = 0;
- if(this.subChunk == (byte) 0){
+ if (this.subChunk == (byte) 0) {
byte[] data2d = new byte[DATA2D_LENGTH];
//fill heightmap
- for(; i < POS_BIOME_DATA;){
+ for (; i < POS_BIOME_DATA; ) {
data2d[i++] = 0;
data2d[i++] = 32;
}
//fill biome data
- for(; i < DATA2D_LENGTH;){
+ for (; i < DATA2D_LENGTH; ) {
data2d[i++] = 1;//biome: plains
data2d[i++] = (byte) 42;//r
data2d[i++] = (byte) 42;//g
@@ -183,9 +184,11 @@ public boolean supportsBlockLightValues() {
return true;
}
- /**
+ */
+/**
* Sets a block type, and also set the corresponding dirty table entry and set the saving flag.
- */
+ *//*
+
@Override
public void setBlockTypeId(int x, int y, int z, int type) {
if (x >= chunkW || y >= chunkH || z >= chunkL || x < 0 || y < 0 || z < 0) {
@@ -218,25 +221,12 @@ public byte getBiome(int x, int z) {
return data2D.get(POS_BIOME_DATA + get2Di(x, z));
}
- private int getNoise(int base, int x, int z){
- // noise values are between -1 and 1
- // 0.0001 is added to the coordinates because integer values result in 0
- double oct1 = Noise.noise(
- ((double) (this.chunk.x * chunkW + x) / 100.0) + 0.0001,
- ((double) (this.chunk.z * chunkL + z) / 100.0) + 0.0001);
- double oct2 = Noise.noise(
- ((double) (this.chunk.x * chunkW + x) / 20.0) + 0.0001,
- ((double) (this.chunk.z * chunkL + z) / 20.0) + 0.0001);
- double oct3 = Noise.noise(
- ((double) (this.chunk.x * chunkW + x) / 3.0) + 0.0001,
- ((double) (this.chunk.z * chunkL + z) / 3.0) + 0.0001);
- return (int) (base + 60 + (40 * oct1) + (14 * oct2) + (6 * oct3));
- }
-
- /*
+ */
+/*
MCPE 1.0 stopped embedding foliage color data in the chunk data,
so now we fake the colors by combining biome colors with Perlin noise
- */
+ *//*
+
@Override
public byte getGrassR(int x, int z) {
@@ -269,3 +259,4 @@ public int getHeightMapValue(int x, int z) {
return ((h & 0xff) << 8) | ((h >> 8) & 0xff);//little endian to big endian
}
}
+*/
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_1_TerrainChunkData.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_1_TerrainChunkData.java
index 6d9dc4c4..e838c7cf 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_1_TerrainChunkData.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_1_TerrainChunkData.java
@@ -1,10 +1,10 @@
+/*
package com.mithrilmania.blocktopograph.chunk.terrain;
import com.mithrilmania.blocktopograph.WorldData;
import com.mithrilmania.blocktopograph.chunk.Chunk;
import com.mithrilmania.blocktopograph.chunk.ChunkTag;
import com.mithrilmania.blocktopograph.map.Biome;
-import com.mithrilmania.blocktopograph.util.Noise;
import java.nio.ByteBuffer;
@@ -31,44 +31,46 @@ public class V1_1_TerrainChunkData extends TerrainChunkData {
public V1_1_TerrainChunkData(Chunk chunk, byte subChunk) {
super(chunk, subChunk);
+ mNotFailed = loadTerrain();
}
@Override
public void write() throws WorldData.WorldDBException {
- this.chunk.worldData.writeChunkData(chunk.x, chunk.z, ChunkTag.TERRAIN, chunk.dimension, subChunk, true, terrainData.array());
- this.chunk.worldData.writeChunkData(chunk.x, chunk.z, ChunkTag.DATA_2D, chunk.dimension, subChunk, true, data2D.array());
+ Chunk chunk = this.chunk.get();
+ chunk.getWorldData().writeChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.TERRAIN, chunk.mDimension, subChunk, true, terrainData.array());
+ chunk.getWorldData().writeChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.DATA_2D, chunk.mDimension, subChunk, true, data2D.array());
}
@Override
public boolean loadTerrain() {
- if(terrainData == null){
+ if (terrainData == null) {
try {
- byte[] rawData = this.chunk.worldData.getChunkData(chunk.x, chunk.z, ChunkTag.TERRAIN, chunk.dimension, subChunk, true);
- if(rawData == null) return false;
+ Chunk chunk = this.chunk.get();
+ byte[] rawData = chunk.getWorldData().getChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.TERRAIN, chunk.mDimension, subChunk, true);
+ if (rawData == null) return false;
this.terrainData = ByteBuffer.wrap(rawData);
return true;
- } catch (Exception e){
+ } catch (Exception e) {
//data is not present
return false;
}
- }
- else return true;
+ } else return mNotFailed;
}
@Override
public boolean load2DData() {
- if(data2D == null){
+ if (data2D == null) {
try {
- byte[] rawData = this.chunk.worldData.getChunkData(chunk.x, chunk.z, ChunkTag.DATA_2D, chunk.dimension, subChunk, false);
- if(rawData == null) return false;
+ Chunk chunk = this.chunk.get();
+ byte[] rawData = chunk.getWorldData().getChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.DATA_2D, chunk.mDimension, subChunk, false);
+ if (rawData == null) return false;
this.data2D = ByteBuffer.wrap(rawData);
return true;
- } catch (Exception e){
+ } catch (Exception e) {
//data is not present
return false;
}
- }
- else return true;
+ } else return true;
}
@@ -85,9 +87,9 @@ public void createEmpty() {
byte sandstone = (byte) 24;
//generate super basic terrain (one layer of bedrock, 31 layers of sandstone)
- for(x = 0; x < chunkW; x++){
- for(z = 0; z < chunkL; z++){
- for(y = 0, realY = chunkH * this.subChunk; y < chunkH; y++, i++, realY++){
+ for (x = 0; x < chunkW; x++) {
+ for (z = 0; z < chunkL; z++) {
+ for (y = 0, realY = chunkH * this.subChunk; y < chunkH; y++, i++, realY++) {
terrain[i] = (realY == 0 ? bedrock : (realY < 32 ? sandstone : 0));
}
}
@@ -95,12 +97,12 @@ public void createEmpty() {
//fill meta-data with 0
- for(; i < POS_META_DATA; i++){
+ for (; i < POS_META_DATA; i++) {
terrain[i] = (byte) 0;
}
//fill block-light with 0xff
- for(; i < TERRAIN_LENGTH; i++){
+ for (; i < TERRAIN_LENGTH; i++) {
terrain[i] = (byte) 0xff;
}
@@ -108,18 +110,18 @@ public void createEmpty() {
i = 0;
- if(this.subChunk == (byte) 0){
+ if (this.subChunk == (byte) 0) {
byte[] data2d = new byte[DATA2D_LENGTH];
//fill heightmap
- for(; i < POS_BIOME_DATA;){
+ for (; i < POS_BIOME_DATA; ) {
data2d[i++] = 0;
data2d[i++] = 32;
}
//fill biome data
- for(; i < DATA2D_LENGTH;){
+ for (; i < DATA2D_LENGTH; ) {
data2d[i++] = 1;//biome: plains
data2d[i++] = (byte) 42;//r
data2d[i++] = (byte) 42;//g
@@ -152,8 +154,7 @@ public byte getBlockData(int x, int y, int z) {
//dualData = terrainData.get(POS_META_DATA + (offset >>> 1));
dualData = terrainData.get(terrainData.limit() - (offset >>> 1));
return (byte) ((offset & 1) == 1 ? ((dualData >>> 4) & 0xf) : (dualData & 0xf));
- }
- catch (Exception e) {
+ } catch (Exception e) {
return (byte) ((offset & 1) == 1 ? ((dualData >>> 4) & 0xf) : (dualData & 0xf));
}
@@ -181,9 +182,11 @@ public boolean supportsBlockLightValues() {
return false;
}
- /**
+ */
+/**
* Sets a block type, and also set the corresponding dirty table entry and set the saving flag.
- */
+ *//*
+
@Override
public void setBlockTypeId(int x, int y, int z, int type) {
if (x >= chunkW || y >= chunkH || z >= chunkL || x < 0 || y < 0 || z < 0) {
@@ -216,25 +219,12 @@ public byte getBiome(int x, int z) {
return data2D.get(POS_BIOME_DATA + get2Di(x, z));
}
- private int getNoise(int base, int x, int z){
- // noise values are between -1 and 1
- // 0.0001 is added to the coordinates because integer values result in 0
- double oct1 = Noise.noise(
- ((double) (this.chunk.x * chunkW + x) / 100.0) + 0.0001,
- ((double) (this.chunk.z * chunkL + z) / 100.0) + 0.0001);
- double oct2 = Noise.noise(
- ((double) (this.chunk.x * chunkW + x) / 20.0) + 0.0001,
- ((double) (this.chunk.z * chunkL + z) / 20.0) + 0.0001);
- double oct3 = Noise.noise(
- ((double) (this.chunk.x * chunkW + x) / 3.0) + 0.0001,
- ((double) (this.chunk.z * chunkL + z) / 3.0) + 0.0001);
- return (int) (base + 60 + (40 * oct1) + (14 * oct2) + (6 * oct3));
- }
-
- /*
+ */
+/*
MCPE 1.0 stopped embedding foliage color data in the chunk data,
so now we fake the colors by combining biome colors with Perlin noise
- */
+ *//*
+
@Override
public byte getGrassR(int x, int z) {
@@ -267,3 +257,4 @@ public int getHeightMapValue(int x, int z) {
return ((h & 0xff) << 8) | ((h >> 8) & 0xff);//little endian to big endian
}
}
+*/
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_2_Plus_TerrainChunkData.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_2_Plus_TerrainChunkData.java
new file mode 100644
index 00000000..655b493b
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1_2_Plus_TerrainChunkData.java
@@ -0,0 +1,304 @@
+/*
+package com.mithrilmania.blocktopograph.chunk.terrain;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+import com.mithrilmania.blocktopograph.chunk.ChunkTag;
+import com.mithrilmania.blocktopograph.map.Biome;
+import com.mithrilmania.blocktopograph.nbt.convert.NBTInputStream;
+import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
+import com.mithrilmania.blocktopograph.nbt.tags.ShortTag;
+import com.mithrilmania.blocktopograph.nbt.tags.StringTag;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+public class V1_2_Plus_TerrainChunkData extends TerrainChunkData {
+
+ //There could be multiple BlockStorage but we can just display the main.
+ public volatile IntBuffer mainStorage;
+ public volatile ByteBuffer data2D;
+ public volatile List palette;
+ public volatile int blockTypes, blockCodeLenth;
+
+ public static final int chunkW = 16, chunkL = 16, chunkH = 16;
+
+ public static final int area = chunkW * chunkL;
+ public static final int vol = area * chunkH;
+
+ public static final int POS_HEIGHTMAP = 0;
+ // it looks like each biome takes 2 bytes, and the first 1 byte of every 2 bytes is always 0!?
+ public static final int POS_BIOME_DATA = POS_HEIGHTMAP + area + area;
+ public static final int DATA2D_LENGTH = POS_BIOME_DATA + area;
+
+ //Masks used to extract BlockState bits of a certain oldBlock out of a int32, and vice-versa.
+ private static final int[] msk = {0b1, 0b11, 0b111, 0b1111, 0b11111, 0b111111, 0b1111111,
+ 0b11111111,
+ 0b111111111, 0b1111111111, 0b11111111111,
+ 0b111111111111,
+ 0b1111111111111, 0b11111111111111, 0b11111111111111};
+
+ public V1_2_Plus_TerrainChunkData(Chunk chunk, byte subChunk) {
+ super(chunk, subChunk);
+ mNotFailed = loadTerrain();
+ }
+
+ @Override
+ public void write() throws WorldData.WorldDBException {
+ Chunk chunk = this.chunk.get();
+ //this.chunk.worldData.get().writeChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.TERRAIN, chunk.mDimension, subChunk, true, terrainData.array());
+ chunk.getWorldData().writeChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.DATA_2D, chunk.mDimension, subChunk, true, data2D.array());
+ }
+
+ @Override
+ public boolean loadTerrain() {
+ //Don't repeat the work.
+ if (mainStorage == null) {
+ try {
+ //Retrieve raw data from database.
+ Chunk chunk = this.chunk.get();
+ byte[] rawData = chunk.getWorldData().getChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.TERRAIN, chunk.mDimension, subChunk, true);
+ if (rawData == null) return false;
+ ByteBuffer raw = ByteBuffer.wrap(rawData);
+ raw.order(ByteOrder.LITTLE_ENDIAN);
+
+ //The first byte indicates version.
+ switch (rawData[0]) {
+ //1: Only one BlockStorage starting from the next byte.
+ case 1:
+ raw.position(1);
+ break;
+ //8: One or more BlockStorage's, next byte is the count. We only read the first.
+ case 8:
+ raw.position(2);
+ break;
+ //0,2,3,4,5,6,7: Should use a V1_1 terrain, why reaching here?
+ //Else: wtf?
+ default:
+ return false;
+ }
+
+ //Load the BlockStorage.
+ loadBlockStorage(raw);
+ return true;
+ } catch (Exception e) {
+ //data is not present
+ return false;
+ }
+ } else return mNotFailed;
+ }
+
+ private void loadBlockStorage(ByteBuffer raw) throws IOException {
+
+ //Read BlockState length.
+ //this byte = (length << 2) | serializedType.
+ blockCodeLenth = (raw.get() & 0xff) >> 1;
+
+ //We use this much of bytes to store BlockStates.
+ int bufsize = (4095 / (32 / blockCodeLenth) + 1) << 2;
+ ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ mainStorage = byteBuffer.asIntBuffer();
+
+ //No convenient way copy these stuff.
+ byteBuffer.put(raw.array(), raw.position(), bufsize);
+ raw.position(raw.position() + bufsize);
+
+ //Palette items count.
+ int psize = raw.getInt();
+
+ //Construct the palette. Each item is a piece of nbt data.
+ palette = new ArrayList<>(16);
+
+ //NBT reader requires a stream.
+ ByteArrayInputStream bais = new ByteArrayInputStream(raw.array());
+ bais.skip(raw.position());
+
+ //Wrap it.
+ NBTInputStream nis = new NBTInputStream(bais, false);
+ for (int i = 0; i < psize; i++) {
+
+ //Read a piece of nbt data, represented by a root CompoundTag.
+ CompoundTag tag = (CompoundTag) nis.readTag();
+
+ //Read `name` and `val` then resolve the `name` into numeric id.
+ String name = ((StringTag) tag.getChildTagByKey("name")).getValue();
+ int data = ((ShortTag) tag.getChildTagByKey("val")).getValue();
+ palette.add(
+// BlockNameResolver.resolve(name)
+ KnownBlockRepr.resolve(name)
+ << 8 | data);
+ }
+
+ //If one day we need to read more BlockStorage's, this line helps.
+ raw.position(raw.position() + nis.getReadCount());
+ }
+
+ @Override
+ public boolean load2DData() {
+ if (data2D == null) {
+ try {
+ Chunk chunk = this.chunk.get();
+ byte[] rawData = chunk.getWorldData().getChunkData(chunk.mChunkX, chunk.mChunkZ, ChunkTag.DATA_2D, chunk.mDimension, subChunk, false);
+ if (rawData == null) return false;
+ this.data2D = ByteBuffer.wrap(rawData);
+ return true;
+ } catch (Exception e) {
+ //data is not present
+ return false;
+ }
+ } else return true;
+ }
+
+
+ @Override
+ public void createEmpty() {
+
+ int i = 0;
+
+ if (this.subChunk == (byte) 0) {
+
+ byte[] data2d = new byte[DATA2D_LENGTH];
+
+ //fill heightmap
+ for (; i < POS_BIOME_DATA; ) {
+ data2d[i++] = 0;
+ data2d[i++] = 32;
+ }
+
+ //fill biome data
+ for (; i < DATA2D_LENGTH; ) {
+ data2d[i++] = 1;//biome: plains
+ data2d[i++] = (byte) 42;//r
+ data2d[i++] = (byte) 42;//g
+ data2d[i++] = (byte) 42;//b
+ }
+
+ this.data2D = ByteBuffer.wrap(data2d);
+ }
+
+
+ }
+
+ private int getBlockState(int x, int y, int z) {
+
+ if (!mNotFailed) return 0;
+
+ //The codeOffset'th BlockState is wanted.
+ int codeOffset = getOffset(x, y, z);
+
+ //How much BlockStates can one int32 hold?
+ int intCapa = 32 / blockCodeLenth;
+
+ //The int32 that holds the wanted BlockState.
+ int stick = mainStorage.get(codeOffset / intCapa);
+
+ //Get the BlockState. It's also the index in palette array.
+ int ind = (stick >> (codeOffset % intCapa * blockCodeLenth)) & msk[blockCodeLenth - 1];
+
+ //Transform the local BlockState into global id<<8|data structure.
+ return palette.get(ind);
+ }
+
+
+ @Override
+ public byte getBlockTypeId(int x, int y, int z) {
+ if (x >= chunkW || y >= chunkH || z >= chunkL || x < 0 || y < 0 || z < 0) {
+ return 0;
+ }
+ return (byte) (getBlockState(x, y, z) >>> 8);
+ }
+
+ @Override
+ public byte getBlockData(int x, int y, int z) {
+ if (x >= chunkW || y >= chunkH || z >= chunkL || x < 0 || y < 0 || z < 0) {
+ return 0;
+ }
+ return (byte) (getBlockState(x, y, z) & 0xf);
+ }
+
+ @Override
+ public byte getSkyLightValue(int x, int y, int z) {
+ if (x >= chunkW || y >= chunkH || z >= chunkL || x < 0 || y < 0 || z < 0) {
+ return 0;
+ }
+ return 0;
+ }
+
+ @Override
+ public byte getBlockLightValue(int x, int y, int z) {
+ //oldBlock light is not stored anymore
+ return 0;
+ }
+
+ @Override
+ public boolean supportsBlockLightValues() {
+ return false;
+ }
+
+ */
+/**
+ * Sets a oldBlock type, and also set the corresponding dirty table entry and set the saving flag.
+ *//*
+
+ @Override
+ public void setBlockTypeId(int x, int y, int z, int type) {
+ if (x >= chunkW || y >= chunkH || z >= chunkL || x < 0 || y < 0 || z < 0) {
+ return;
+ }
+ }
+
+ @Override
+ public void setBlockData(int x, int y, int z, int newData) {
+ if (x >= chunkW || y >= chunkH || z >= chunkL || x < 0 || y < 0 || z < 0) {
+ return;
+ }
+ }
+
+ private int getOffset(int x, int y, int z) {
+ return (((x << 4) | z) << 4) | y;
+ }
+
+ @Override
+ public byte getBiome(int x, int z) {
+ return data2D.get(POS_BIOME_DATA + get2Di(x, z));
+ }
+
+ @Override
+ public byte getGrassR(int x, int z) {
+ Biome biome = Biome.getBiome(getBiome(x, z) & 0xff);
+ int res = getNoise(30 + (biome.color.red / 5), x, z);
+ return (byte) (res > 0xff ? 0xff : (res < 0 ? 0 : res));
+ }
+
+ @Override
+ public byte getGrassG(int x, int z) {
+ Biome biome = Biome.getBiome(getBiome(x, z) & 0xff);
+ int res = getNoise(120 + (biome.color.green / 5), x, z);
+ return (byte) (res > 0xff ? 0xff : (res < 0 ? 0 : res));
+ }
+
+ @Override
+ public byte getGrassB(int x, int z) {
+ Biome biome = Biome.getBiome(getBiome(x, z) & 0xff);
+ int res = getNoise(30 + (biome.color.blue / 5), x, z);
+ return (byte) (res > 0xff ? 0xff : (res < 0 ? 0 : res));
+ }
+
+ private int get2Di(int x, int z) {
+ return z * chunkL + x;
+ }
+
+ @Override
+ public int getHeightMapValue(int x, int z) {
+ short h = data2D.getShort(POS_HEIGHTMAP + (get2Di(x, z) << 1));
+ return ((h & 0xff) << 8) | ((h >> 8) & 0xff);//little endian to big endian
+ }
+}
+*/
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1d2d13TerrainSubChunk.java b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1d2d13TerrainSubChunk.java
new file mode 100644
index 00000000..b5c69f3f
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/chunk/terrain/V1d2d13TerrainSubChunk.java
@@ -0,0 +1,427 @@
+package com.mithrilmania.blocktopograph.chunk.terrain;
+
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Streams;
+import com.mithrilmania.blocktopograph.BuildConfig;
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.Block;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.BlockType;
+import com.mithrilmania.blocktopograph.block.blockproperty.BlockProperty;
+import com.mithrilmania.blocktopograph.chunk.ChunkTag;
+import com.mithrilmania.blocktopograph.map.Dimension;
+import com.mithrilmania.blocktopograph.nbt.convert.NBTInputStream;
+import com.mithrilmania.blocktopograph.nbt.convert.NBTOutputStream;
+import com.mithrilmania.blocktopograph.nbt.tags.ByteTag;
+import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
+import com.mithrilmania.blocktopograph.nbt.tags.IntTag;
+import com.mithrilmania.blocktopograph.nbt.tags.StringTag;
+import com.mithrilmania.blocktopograph.util.LittleEndianOutputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+public final class V1d2d13TerrainSubChunk extends TerrainSubChunk {
+
+ private boolean mIsDualStorageSupported;
+
+ // Masks used to extract BlockState bits of a certain oldBlock out of a int32, and vice-versa.
+ private static final int[] msk = {0b1, 0b11, 0b111, 0b1111, 0b11111, 0b111111, 0b1111111,
+ 0b11111111,
+ 0b111111111, 0b1111111111, 0b11111111111,
+ 0b111111111111,
+ 0b1111111111111, 0b11111111111111, 0b11111111111111};
+ // There could be multiple BlockStorage let's read the first two.
+ private final BlockStorage[] mStorages;
+
+ V1d2d13TerrainSubChunk() {
+ mStorages = new BlockStorage[2];
+ mIsDualStorageSupported = true;
+ createEmptyBlockStorage(0);
+ }
+
+ V1d2d13TerrainSubChunk(@NonNull ByteBuffer raw) {
+
+ raw.order(ByteOrder.LITTLE_ENDIAN);
+ mStorages = new BlockStorage[2];
+
+ // The first byte indicates version.
+ switch (raw.get(0)) {
+ // 1: Only one BlockStorage starting from the next byte.
+ case 1:
+ mIsDualStorageSupported = false;
+ raw.position(1);
+ try {
+ mStorages[0] = BlockStorage.loadAndMoveForward(raw);
+ } catch (IOException e) {
+ if (BuildConfig.DEBUG) {
+ Log.d(this, e);
+ }
+ mIsError = true;
+ }
+ break;
+ // 8: One or more BlockStorage's, next byte is the count.
+ case 8:
+ mIsDualStorageSupported = true;
+ raw.position(1);
+ int count = raw.get();
+ if (count < 1) {
+ mIsError = true;
+ return;
+ }
+ try {
+ mStorages[0] = BlockStorage.loadAndMoveForward(raw);
+ if (count > 1) mStorages[1] = BlockStorage.loadAndMoveForward(raw);
+ } catch (IOException e) {
+ if (BuildConfig.DEBUG) {
+ Log.d(this, e);
+ }
+ mIsError = true;
+ }
+ break;
+ default:
+ mIsError = true;
+ return;
+ }
+ mHasBlockLight = false;
+ mHasSkyLight = false;
+ }
+
+ @NonNull
+ @Override
+ public BlockTemplate getBlockTemplate(int x, int y, int z, int layer) {
+ if (mIsError) return BlockTemplates.getAirTemplate();
+ BlockStorage storage = mStorages[layer];
+ if (storage == null) return BlockTemplates.getAirTemplate();
+ return storage.getBlock(x, y, z).second;
+ }
+
+ @NonNull
+ @Override
+ public Block getBlock(int x, int y, int z, int layer) {
+ if (mIsError) throw new RuntimeException();
+ BlockStorage storage = mStorages[layer];
+ if (storage == null) return BlockTemplates.getAirTemplate().getBlock();
+ return storage.getBlock(x, y, z).first;
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, int layer, @NonNull Block block) {
+
+ // Has error or not supported.
+ if (mIsError || (layer > 0 && !mIsDualStorageSupported)) throw new RuntimeException();
+
+ BlockStorage storage = mStorages[layer];
+ // Main storage won't be null unless error.
+ if (storage == null) storage = createEmptyBlockStorage(layer);
+
+ // If space is enough.
+ if (storage.setBlockIfSpace(x, y, z, block)) return;
+
+ // Or we have to extend the whole storage.
+ storage = BlockStorage.extend(storage);
+
+ mStorages[layer] = storage;
+ storage.setBlockIfSpace(x, y, z, block);
+ }
+
+ @Override
+ public int getBlockLightValue(int x, int y, int z) {
+ return 0;
+ }
+
+ @Override
+ public int getSkyLightValue(int x, int y, int z) {
+ return 0;
+ }
+
+ private BlockStorage createEmptyBlockStorage(int which) {
+ BlockStorage storage = BlockStorage.createNew();
+ mStorages[which] = storage;
+ return storage;
+ }
+
+ @Override
+ public void save(WorldData worldData, int chunkX, int chunkZ, Dimension dimension, int which) throws WorldData.WorldDBException, IOException {
+
+ if (mIsError) return;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ LittleEndianOutputStream leos = new LittleEndianOutputStream(baos);
+
+ int storageCount = mIsDualStorageSupported ? (mStorages[1] == null ? 1 : 2) : 1;
+
+ if (mIsDualStorageSupported) {
+ leos.write(8);
+ leos.write(storageCount);
+ mStorages[0].write(leos);
+ if (storageCount == 2) mStorages[1].write(leos);
+ } else {
+ leos.write(1);
+ mStorages[0].write(leos);
+ }
+ leos.flush();
+
+ byte[] arr = baos.toByteArray();
+ worldData.writeChunkData(chunkX, chunkZ, ChunkTag.TERRAIN, dimension, (byte) which, true, arr);
+
+ }
+
+ private static class BlockStorage {
+
+ public static final String PALETTE_KEY_ROOT = "";
+ public static final String PALETTE_KEY_NAME = "name";
+ public static final String PALETTE_KEY_STATES = "states";
+ public static final String PALETTE_KEY_VERSION = "version";
+
+ private final byte[] raw;
+
+ // records is a view into raw
+ private final IntBuffer records;
+
+ private final List palette;
+
+ private final List renderPalette;
+
+ private final int blockCodeLenth;
+
+ private BlockStorage() {
+ raw = new byte[512];
+ ByteBuffer bbuff = ByteBuffer.wrap(raw);
+ bbuff.order(ByteOrder.LITTLE_ENDIAN);
+ records = bbuff.asIntBuffer();
+
+ palette = new ArrayList<>(4);
+ renderPalette = new ArrayList<>(4);
+ var airTemplate = BlockTemplates.getAirTemplate();
+ renderPalette.add(airTemplate);
+ palette.add(airTemplate.getBlock());
+
+ blockCodeLenth = 1;
+ }
+
+ // stateful! wrapping with static creation method
+ private BlockStorage(@NonNull ByteBuffer buffer) throws IOException {
+
+ //Read BlockState length.
+ //this byte = (length << 2) | serializedType.
+ blockCodeLenth = (buffer.get() & 0xff) >> 1;
+
+ if (blockCodeLenth > 16) throw new IOException("mBlockLength > 16");
+
+ //We use this much of bytes to store BlockStates.
+ int bufsize = (4095 / (32 / blockCodeLenth) + 1) << 2;
+ byte[] arr = new byte[bufsize];
+ ByteBuffer byteBuffer = ByteBuffer.wrap(arr);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ records = byteBuffer.asIntBuffer();
+ raw = arr;
+
+ //No convenient way copy these stuff.
+ byteBuffer.put(buffer.array(), buffer.position(), bufsize);
+ buffer.position(buffer.position() + bufsize);
+
+ //Palette items count.
+ int psize = buffer.getInt();
+
+// if(psize>(1< most possible bound");
+// }
+
+ //Construct the palette. Each item is a piece of nbt data.
+ palette = new ArrayList<>(16);
+ renderPalette = new ArrayList<>(16);
+
+ //NBT reader requires a stream.
+ var bais = new ByteArrayInputStream(buffer.array());
+
+ // Skip for byte array would not fail.
+ //noinspection ResultOfMethodCallIgnored
+ bais.skip(buffer.position());
+
+ //Wrap it.
+ var nis = new NBTInputStream(bais, false);
+ for (int i = 0; i < psize; i++)
+ //Read a piece of nbt data, represented by a root CompoundTag.
+ addToPalette(deserializeBlock((CompoundTag) nis.readTag()));
+
+ //If one day we need to read more BlockStorage's, this line helps.
+ buffer.position(buffer.position() + nis.getReadCount());
+ }
+
+ private BlockStorage(@NonNull BlockStorage old) {
+ blockCodeLenth = old.blockCodeLenth + 1;
+ palette = new ArrayList<>(old.palette);
+ renderPalette = new ArrayList<>(old.renderPalette);
+ int capa_new = 32 / blockCodeLenth;
+ int capa_old = 32 / old.blockCodeLenth;
+ int stick = 4095 / capa_new + 1;
+ byte[] newRecs = new byte[stick << 2];
+ ByteBuffer newBb = ByteBuffer.wrap(newRecs);
+ newBb.order(ByteOrder.LITTLE_ENDIAN);
+ records = newBb.asIntBuffer();
+ raw = newRecs;
+ for (int i = 0, hold = 0, hnew = 0, mold = 0, mnew = 0; i < 4096; i++) {
+ int idold =
+ (old.records.get(hold) >> (mold * old.blockCodeLenth)) & msk[old.blockCodeLenth - 1];
+ idold <<= mnew * blockCodeLenth;
+ records.put(hnew, records.get(hnew) | idold);
+ mold++;
+ mnew++;
+ if (mold == capa_old) {
+ mold = 0;
+ hold++;
+ }
+ if (mnew == capa_new) {
+ mnew = 0;
+ hnew++;
+ }
+ }
+ }
+
+ public static BlockStorage createNew() {
+ return new BlockStorage();
+ }
+
+ public static BlockStorage loadAndMoveForward(@NonNull ByteBuffer buffer) throws IOException {
+ return new BlockStorage(buffer);
+ }
+
+ public static BlockStorage extend(@NonNull BlockStorage storage) {
+ return new BlockStorage(storage);
+ }
+
+ private void addToPalette(Block block) {
+ palette.add(block);
+ renderPalette.add(BlockTemplates.getBest(block));
+ }
+
+ public boolean setBlockIfSpace(
+ int x, int y, int z, @NonNull Block block) {
+ int code = -1;
+
+ // If in palette.
+ for (int localId = 0, paletteSize = palette.size(); localId < paletteSize; localId++) {
+ Block blockInPalette = palette.get(localId);
+ if (block.equals(blockInPalette)) {
+ code = localId;
+ break;
+ }
+ }
+
+ // Or not.
+ if (code < 0) {
+ // Reached size limit.
+ int max = 1 << blockCodeLenth;
+ int size = palette.size();
+ if (size >= max) return false;
+
+ addToPalette(block);
+ code = size;
+ }
+
+ // The codeOffset'th BlockState is wanted.
+ int codeOffset = getOffset(x, y, z);
+
+ // How much BlockStates can one int32 hold?
+ int intCapa = 32 / blockCodeLenth;
+
+ // The int32 that holds the wanted BlockState.
+ int whichInt = codeOffset / intCapa;
+ int stick = records.get(whichInt);
+ int shift = codeOffset % intCapa * blockCodeLenth;
+ stick &= ~(msk[blockCodeLenth - 1] << shift);
+ stick |= code << shift;
+ records.put(whichInt, stick);
+
+ return true;
+ }
+
+ public Pair getBlock(int x, int y, int z) {
+
+ //The codeOffset'th BlockState is wanted.
+ int codeOffset = getOffset(x, y, z);
+
+ //How much BlockStates can one int32 hold?
+ int intCapa = 32 / blockCodeLenth;
+
+ //The int32 that holds the wanted BlockState.
+ int stick = records.get(codeOffset / intCapa);
+
+ //Get the BlockState. It's also the index in palette array.
+ int ind = (stick >> (codeOffset % intCapa * blockCodeLenth)) & msk[blockCodeLenth - 1];
+
+ //Transform the local BlockState into global id<<8|data structure.
+ return new Pair<>(palette.get(ind), renderPalette.get(ind));
+ }
+
+ private void write(@NonNull LittleEndianOutputStream stream) throws IOException {
+
+ // Code length.
+ stream.write(blockCodeLenth << 1);
+
+ // Int32s.
+ stream.write(raw);
+
+ // Palette size.
+ int size = palette.size();
+ stream.writeInt(size);
+
+ // Palettes.
+ NBTOutputStream nos = new NBTOutputStream(stream, false, true);
+
+ for (int j = 0; j < size; j++)
+ nos.writeTag(serializeBlock(palette.get(j)));
+ }
+
+ private static CompoundTag serializeBlock(@NonNull Block block) {
+ return new CompoundTag(PALETTE_KEY_ROOT, Lists.newArrayList(
+ new StringTag(PALETTE_KEY_NAME, block.getName()),
+ new CompoundTag(PALETTE_KEY_STATES, new ArrayList<>(Streams.concat(Streams.zip(
+ Arrays.stream(block.getType().getKnownProperties()).map(BlockProperty::getName),
+ Arrays.stream(block.getKnownProperties()), Maps::immutableEntry).filter(Objects::nonNull),
+ block.getCustomProperties().entrySet().stream()).map(
+ (entry) -> {
+ var name = entry.getKey();
+ var val = entry.getValue();
+ if (val instanceof Byte) return new ByteTag(name, (Byte) val);
+ else if (val instanceof Integer)
+ return new IntTag(name, (Integer) val);
+ else if (val instanceof String)
+ return new StringTag(name, (String) val);
+ else
+ throw new RuntimeException("block state with unsupported type");
+ }).collect(Collectors.toList()))),
+ new IntTag(PALETTE_KEY_VERSION, 2012)
+ ));
+ }
+
+ private static Block deserializeBlock(@NonNull CompoundTag tag) {
+ var name = ((StringTag) tag.getChildTagByKey(PALETTE_KEY_NAME)).getValue();
+ var blockType = BlockType.get(name);
+ var builder = (blockType == null ? new Block.Builder(name) : new Block.Builder(blockType));
+ for (var state : ((CompoundTag) tag.getChildTagByKey(PALETTE_KEY_STATES)).getValue())
+ builder.setProperty(state);
+ Log.d(BlockStorage.class, "fuckfuckversion" + tag.getChildTagByKey(PALETTE_KEY_VERSION).getValue());
+ return builder.build();
+ }
+
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/flat/EditFlatFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/flat/EditFlatFragment.java
new file mode 100644
index 00000000..96d1e068
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/flat/EditFlatFragment.java
@@ -0,0 +1,261 @@
+package com.mithrilmania.blocktopograph.flat;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.AssetManager;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+
+import com.google.android.material.snackbar.Snackbar;
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.ListingBlock;
+import com.mithrilmania.blocktopograph.databinding.FragLayersBinding;
+import com.mithrilmania.blocktopograph.databinding.ItemWorldLayerBinding;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+import com.woxthebox.draglistview.DragItemAdapter;
+import com.woxthebox.draglistview.DragListView;
+import com.woxthebox.draglistview.swipe.ListSwipeHelper;
+import com.woxthebox.draglistview.swipe.ListSwipeItem;
+
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+import java.util.LinkedList;
+import java.util.List;
+
+public final class EditFlatFragment extends Fragment {
+
+ static final String EXTRA_KEY_LIST_INDEX = "index";
+ static final String EXTRA_KEY_LIST_IS_ADD = "isAdd";
+ static final String EXTRA_KEY_LIST_LAYER = "layer";
+ static final String EXTRA_KEY_LIST_EXISTING_SUM = "existingSum";
+ private static final int REQUEST_CODE_EDIT_LAYER = 2013;
+ private FragLayersBinding mBinding;
+ private MeowAdapter mMeowAdapter;
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ mBinding = DataBindingUtil.inflate(inflater, R.layout.frag_layers, container, false);
+ new LoadTask(this).execute();
+ return mBinding.getRoot();
+ }
+
+ private void onClickAddOrEditLayer(int index, Layer layer, boolean isAdd, int existingSum) {
+ Activity activity = getActivity();
+ if (activity == null) return;
+ startActivityForResult(
+ new Intent(activity, EditLayerDialog.class)
+ .putExtra(EXTRA_KEY_LIST_INDEX, index)
+ .putExtra(EXTRA_KEY_LIST_LAYER, layer)
+ .putExtra(EXTRA_KEY_LIST_IS_ADD, isAdd)
+ .putExtra(EXTRA_KEY_LIST_EXISTING_SUM, existingSum),
+ REQUEST_CODE_EDIT_LAYER
+ );
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CODE_EDIT_LAYER) {
+ if (resultCode != Activity.RESULT_OK) return;
+ int index = data.getIntExtra(EXTRA_KEY_LIST_INDEX, 0);
+ Serializable ser = data.getSerializableExtra(EXTRA_KEY_LIST_LAYER);
+ Layer layer = (Layer) ser;
+ if (data.getBooleanExtra(EXTRA_KEY_LIST_IS_ADD, true)) {
+ mMeowAdapter.insert(index + 1, layer);
+ } else {
+ mMeowAdapter.change(index, layer);
+ }
+ return;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ public List getResultLayers() {
+ return mMeowAdapter.getItemList();
+ }
+
+ private static class LoadTask extends AsyncTask {
+
+ private final WeakReference thiz;
+ private AlertDialog mWaitDialog;
+
+ private LoadTask(EditFlatFragment thiz) {
+ this.thiz = new WeakReference<>(thiz);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ Activity activity = thiz.get().getActivity();
+ if (activity == null) return;
+ mWaitDialog = UiUtil.buildProgressWaitDialog(activity, 0, null);
+ mWaitDialog.show();
+ }
+
+ @Override
+ protected Void doInBackground(Void... voids) {
+ try {
+ Activity activity = thiz.get().getActivity();
+ if (activity == null) return null;
+ ListingBlock.B_1_STONE.getIcon(activity.getAssets());
+ } catch (Exception e) {
+ Log.d(this, e);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ EditFlatFragment thiz = this.thiz.get();
+ //If the activity quit nothing needs to be done.
+ if (thiz == null) return;
+ try {
+ DragListView listView = thiz.mBinding.list;
+ thiz.mMeowAdapter = thiz.new MeowAdapter(thiz.getResources().getAssets());
+ listView.setLayoutManager(new LinearLayoutManager(thiz.getActivity()));
+ listView.setCanDragHorizontally(false);
+ listView.setAdapter(thiz.mMeowAdapter, false);
+ listView.setSwipeListener(thiz.mMeowAdapter);
+ thiz.mMeowAdapter.loadDefault();
+ } catch (Exception e) {
+ Log.d(this, e);
+ Activity activity = thiz.getActivity();
+ if (activity != null) UiUtil.toastError(activity);
+ }
+ mWaitDialog.dismiss();
+ }
+ }
+
+ private class MeowAdapter extends DragItemAdapter implements ListSwipeHelper.OnSwipeListener {
+
+ @NonNull
+ private AssetManager assMan;
+
+ MeowAdapter(@NonNull AssetManager assMan) {
+ setItemList(new LinkedList<>());
+ this.assMan = assMan;
+ }
+
+ @Override
+ public long getUniqueItemId(int i) {
+ Layer layer = mItemList.get(i);
+ //return (((long) i) << 32) | (layer.block.id << 16) | (layer.block.subId << 8) | layer.amount;
+ return layer.uid;
+ }
+
+ void loadDefault() {
+ Layer layer = new Layer(BlockTemplates.getOfType("minecraft:bedrock")[0], 1);
+ addItem(0, layer);
+ layer = new Layer(BlockTemplates.getOfType("minecraft:dirt")[0], 29);
+ addItem(0, layer);
+ layer = new Layer(BlockTemplates.getOfType("minecraft:grass")[0], 1);
+ addItem(0, layer);
+ layer = new Layer(BlockTemplates.getOfType("minecraft:tallgrass")[0],1);
+ addItem(0, layer);
+ }
+
+ void insert(int index, Layer layer) {
+ mItemList.add(index, layer);
+ notifyItemInserted(index);
+ }
+
+ void change(int index, Layer layer) {
+ mItemList.set(index, layer);
+ notifyItemChanged(index, layer);
+ }
+
+ @NonNull
+ @Override
+ public MeowHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int in) {
+ ItemWorldLayerBinding binding = DataBindingUtil.inflate(
+ getLayoutInflater(), R.layout.item_world_layer, mBinding.list, false);
+ MeowHolder holder = new MeowHolder(binding);
+ holder.binding.add.setOnClickListener(view -> {
+ int sum = 0;//Existing height. Total height shall be less then 128 we need to ensure.
+ for (Layer l : mItemList) {
+ sum += l.amount;
+ }
+ onClickAddOrEditLayer(holder.getLayoutPosition(), new Layer(), true, sum);
+ });
+ holder.binding.root.setOnClickListener(view -> {
+ int index = holder.getLayoutPosition();
+ int sum = 0;//Existing height. Total height shall be less then 128 we need to ensure.
+ for (int i = 0, mItemListSize = mItemList.size(); i < mItemListSize; i++) {
+ if (i == index) continue;
+ Layer l = mItemList.get(i);
+ sum += l.amount;
+ }
+ onClickAddOrEditLayer(index, mItemList.get(index), false, sum);
+ });
+ holder.binding.root.setTag(new WeakReference<>(holder));
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull MeowHolder holder, int position) {
+ super.onBindViewHolder(holder, position);
+ Layer layer = mItemList.get(position);
+ holder.binding.setLayer(layer);
+ holder.binding.icon.setImageBitmap(layer.block.getIcon().getIcon(getContext()));
+ }
+
+ @Override
+ public void onItemSwipeStarted(ListSwipeItem item) {
+ }
+
+ @Nullable
+ private MeowHolder getHolderFromTag(@NonNull ListSwipeItem view) {
+ Object tag = view.getTag();
+ if (!(tag instanceof WeakReference)) return null;
+ WeakReference> ref = (WeakReference>) tag;
+ Object mho = ref.get();
+ return (MeowHolder) mho;
+ }
+
+ @Override
+ public void onItemSwipeEnded(ListSwipeItem item, ListSwipeItem.SwipeDirection swipedDirection) {
+ if (swipedDirection != ListSwipeItem.SwipeDirection.LEFT) return;
+ MeowHolder mh = getHolderFromTag(item);
+ if (mh == null) return;
+ int position = mh.getAdapterPosition();
+ int size = mItemList.size();
+ if (size > 1) {
+ mItemList.remove(position);
+ notifyItemRemoved(position);
+ } else if (size == 1) {
+ mItemList.set(0, new Layer());
+ Snackbar.make(mBinding.list, R.string.edit_flat_atleast, Snackbar.LENGTH_SHORT).show();
+ notifyItemChanged(0);
+ }
+ }
+
+ @Override
+ public void onItemSwiping(ListSwipeItem item, float swipedDistanceX) {
+ float alpha = -swipedDistanceX / item.getMeasuredWidth() * 1.2f;
+ MeowHolder mh = getHolderFromTag(item);
+ if (mh == null) return;
+ mh.binding.itemRight.setAlpha(alpha);
+ }
+
+ private class MeowHolder extends DragItemAdapter.ViewHolder {
+
+ ItemWorldLayerBinding binding;
+
+ MeowHolder(@NonNull ItemWorldLayerBinding binding) {
+ super(binding.getRoot(), R.id.icon, false);
+ this.binding = binding;
+ binding.root.setSupportedSwipeDirection(ListSwipeItem.SwipeDirection.LEFT);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/flat/EditLayerDialog.java b/app/src/main/java/com/mithrilmania/blocktopograph/flat/EditLayerDialog.java
new file mode 100644
index 00000000..25f75a87
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/flat/EditLayerDialog.java
@@ -0,0 +1,148 @@
+package com.mithrilmania.blocktopograph.flat;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+import android.widget.EditText;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.databinding.DataBindingUtil;
+
+import com.andreabaccega.formedittextvalidator.Validator;
+import com.andreabaccega.widget.FormEditText;
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.ListingBlock;
+import com.mithrilmania.blocktopograph.databinding.DialogEditLayerBinding;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.io.Serializable;
+
+import static com.mithrilmania.blocktopograph.flat.EditFlatFragment.EXTRA_KEY_LIST_EXISTING_SUM;
+import static com.mithrilmania.blocktopograph.flat.EditFlatFragment.EXTRA_KEY_LIST_INDEX;
+import static com.mithrilmania.blocktopograph.flat.EditFlatFragment.EXTRA_KEY_LIST_IS_ADD;
+import static com.mithrilmania.blocktopograph.flat.EditFlatFragment.EXTRA_KEY_LIST_LAYER;
+
+public final class EditLayerDialog extends AppCompatActivity {
+
+ public static final int REQUEST_CODE_PICK_BLOCK = 2014;
+ private boolean mIsAdd;
+ private int mExistingSum;
+ private int mPositon;
+ private DialogEditLayerBinding mBinding;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mBinding = DataBindingUtil.setContentView(this, R.layout.dialog_edit_layer);
+ setResult(RESULT_CANCELED);
+
+ Intent intent = getIntent();
+ if (savedInstanceState != null || intent == null) {
+ //The activity does not do anything worth restore.
+ finish();
+ return;
+ }
+ Serializable ser = intent.getSerializableExtra(EXTRA_KEY_LIST_LAYER);
+ if (!(ser instanceof Layer)) {
+ Log.d(this, "wtf?");
+ finish();
+ return;
+ }
+ Layer layer = (Layer) ser;
+
+ mPositon = intent.getIntExtra(EXTRA_KEY_LIST_INDEX, -1);
+ mBinding.setLayer(layer);
+ mIsAdd = intent.getBooleanExtra(EXTRA_KEY_LIST_IS_ADD, true);
+ mExistingSum = intent.getIntExtra(EXTRA_KEY_LIST_EXISTING_SUM, 0);
+
+ if (mIsAdd) setTitle(R.string.edit_flat_add_layer_title);
+ else setTitle(R.string.edit_flat_edit_layer_title);
+
+ FormEditText amountBar = mBinding.amount;
+ amountBar.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ mBinding.amount.testValidity();
+ }
+ });
+ amountBar.addValidator(new AmountValidator(getString(R.string.edit_layer_amount_constrait)));
+
+ mBinding.icon.setImageBitmap(layer.block.getIcon().getIcon(this));
+ UiUtil.blendBlockColor(mBinding.frame, layer.block);
+ }
+
+ public void onClickChangeBlock(View view) {
+ startActivityForResult(
+ new Intent(this, PickBlockActivity.class), REQUEST_CODE_PICK_BLOCK
+ );
+ }
+
+ public void onClickPositiveButton(View view) {
+ Layer layer = mBinding.getLayer();
+ String am = mBinding.amount.getText().toString();
+ int ami = 1;
+ if (!am.isEmpty()) try {
+ ami = Integer.parseInt(am);
+ } catch (NumberFormatException e) {
+ //
+ }
+ layer.amount = ami;
+ setResult(RESULT_OK, new Intent()
+ .putExtra(EXTRA_KEY_LIST_INDEX, mPositon)
+ .putExtra(EXTRA_KEY_LIST_IS_ADD, mIsAdd)
+ .putExtra(EXTRA_KEY_LIST_LAYER, layer));
+ finish();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ switch (requestCode) {
+ case REQUEST_CODE_PICK_BLOCK: {
+ if (resultCode != RESULT_OK) return;
+ assert data != null;
+ BlockTemplate block = (BlockTemplate) data.getSerializableExtra(PickBlockActivity.EXTRA_KEY_BLOCK);
+ Layer layer = mBinding.getLayer();
+ layer.block = block;
+ mBinding.setLayer(layer);
+ mBinding.icon.setImageBitmap(layer.block.getIcon().getIcon(this));
+ UiUtil.blendBlockColor(mBinding.frame, block);
+ //mBinding.notifyChange();
+ return;
+ }
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ public class AmountValidator extends Validator {
+
+ AmountValidator(String customErrorMessage) {
+ super(customErrorMessage);
+ }
+
+ @Override
+ public boolean isValid(EditText et) {
+ String text = et.getText().toString();
+ if (text.isEmpty()) return true;
+ int val;
+ try {
+ val = Integer.parseInt(text);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return val >= 0 && val < 128 - mExistingSum;
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/flat/FlatLayers.java b/app/src/main/java/com/mithrilmania/blocktopograph/flat/FlatLayers.java
new file mode 100644
index 00000000..e5522c7e
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/flat/FlatLayers.java
@@ -0,0 +1,113 @@
+package com.mithrilmania.blocktopograph.flat;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public final class FlatLayers {
+
+ private static final String KEY_BIOME_ID = "biome_id";
+ private static final String KEY_BLOCK_LAYERS = "block_layers";
+ private static final String KEY_BLOCK_NAME = "block_name";
+ private static final String KEY_BLOCK_DATA = "block_data";
+ private static final String KEY_COUNT = "count";
+ private static final String KEY_VERSION = "encoding_version";
+ private static final String KEY_STRUCTURE_OPS = "structure_options";
+
+ private boolean hasStructureOps;
+ private int biomeId;
+ private int encodingVersion;
+ private Layer[] mLayers;
+
+ @Nullable
+ public static FlatLayers parse(String json) {
+ try {
+ JSONObject root = new JSONObject(json);
+ FlatLayers layers = new FlatLayers();
+ layers.biomeId = root.getInt(KEY_BIOME_ID);
+ layers.encodingVersion = root.getInt(KEY_VERSION);
+ JSONArray jlayers = root.getJSONArray(KEY_BLOCK_LAYERS);
+ Layer[] alayers = new Layer[jlayers.length()];
+ for (int i = 0; i < alayers.length; i++) {
+ JSONObject jlayer = jlayers.getJSONObject(i);
+ String name = jlayer.getString(KEY_BLOCK_NAME);
+ int id = KnownBlockRepr.resolve(name);
+ int data = jlayer.getInt(KEY_BLOCK_DATA);
+ int count = jlayer.getInt(KEY_COUNT);
+ KnownBlockRepr block = KnownBlockRepr.getBestBlock(id, data);
+ //alayers[i] = new Layer(block, count);
+ }
+ layers.hasStructureOps = root.has(KEY_STRUCTURE_OPS);
+ return layers;
+ } catch (JSONException e) {
+ Log.d(FlatLayers.class, e);
+ }
+ return null;
+ }
+
+ @NonNull
+ public static FlatLayers createNew(int biomeId, Layer[] layers) {
+ FlatLayers ret = new FlatLayers();
+ ret.biomeId = biomeId;
+ ret.encodingVersion = 4;
+ ret.mLayers = layers;
+ return ret;
+ }
+
+ private FlatLayers() {
+ }
+
+ public int getBiomeId() {
+ return biomeId;
+ }
+
+ public void setBiomeId(int biomeId) {
+ this.biomeId = biomeId;
+ }
+
+ public int getEncodingVersion() {
+ return encodingVersion;
+ }
+
+ public void setEncodingVersion(int encodingVersion) {
+ this.encodingVersion = encodingVersion;
+ }
+
+ public Layer[] getmLayers() {
+ return mLayers;
+ }
+
+ public void setmLayers(Layer[] mLayers) {
+ this.mLayers = mLayers;
+ }
+
+ @Nullable
+ public String write() {
+ try {
+ JSONObject root = new JSONObject();
+ root.put(KEY_BIOME_ID, biomeId);
+ root.put(KEY_VERSION, encodingVersion);
+ JSONArray jlayers = new JSONArray();
+ for (Layer layer : mLayers) {
+ JSONObject jlayer = new JSONObject();
+ jlayer.put(KEY_BLOCK_NAME, layer.block.getBlock().getName());
+ //jlayer.put(KEY_BLOCK_DATA, layer.block.subId);
+ jlayer.put(KEY_COUNT, layer.amount);
+ jlayers.put(jlayer);
+ }
+ root.put(KEY_BLOCK_LAYERS, jlayers);
+ if (hasStructureOps) root.put(KEY_STRUCTURE_OPS, null);
+ return root.toString(4);
+ } catch (JSONException e) {
+ Log.d(FlatLayers.class, e);
+ }
+ return null;
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/flat/Layer.java b/app/src/main/java/com/mithrilmania/blocktopograph/flat/Layer.java
new file mode 100644
index 00000000..ab188d18
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/flat/Layer.java
@@ -0,0 +1,46 @@
+package com.mithrilmania.blocktopograph.flat;
+
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.ListingBlock;
+
+import java.io.Serializable;
+
+public final class Layer implements Serializable {
+
+ private static long counter = 0;
+ public BlockTemplate block;
+ public int amount;
+ public long uid;
+
+ private synchronized void genUid() {
+ // What the hell are you doing?
+ // Well calm down my friend....
+ // Nothing serious, right?
+ // ...
+ uid = counter;//System.currentTimeMillis();
+ counter++;
+ }
+
+ public Layer() {
+ block = BlockTemplates.getOfType("minecraft:air")[0];
+ amount = 1;
+ genUid();
+ }
+
+ Layer(BlockTemplate block, int amount) {
+ this.block = block;
+ this.amount = amount;
+ genUid();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof Layer)) return false;
+ Layer another = (Layer) obj;
+ if (amount != another.amount) return false;
+ return block == another.block;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/flat/PickBlockActivity.java b/app/src/main/java/com/mithrilmania/blocktopograph/flat/PickBlockActivity.java
new file mode 100644
index 00000000..c6ee2419
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/flat/PickBlockActivity.java
@@ -0,0 +1,196 @@
+package com.mithrilmania.blocktopograph.flat;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.databinding.DataBindingUtil;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.common.collect.Streams;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.databinding.DialogPickBlockBinding;
+import com.mithrilmania.blocktopograph.databinding.ItemPickBlockBinding;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public final class PickBlockActivity extends AppCompatActivity {
+
+ public static final String EXTRA_KEY_BLOCK = "block";
+ private DialogPickBlockBinding mBinding;
+ private LinearLayoutManager mListManager;
+ private MeowAdapter mAdapter;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mBinding = DataBindingUtil.setContentView(this, R.layout.dialog_pick_block);
+
+ RecyclerView list = mBinding.list;
+ mListManager = new LinearLayoutManager(this);
+ list.setLayoutManager(mListManager);
+ mAdapter = new MeowAdapter();
+ list.setAdapter(mAdapter);
+ setResult(RESULT_CANCELED);
+
+ mBinding.text.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ new UpdateListTask(PickBlockActivity.this).execute();
+ }
+ });
+
+ new UpdateListTask(PickBlockActivity.this).execute();
+ }
+
+ private static class UpdateListTask extends AsyncTask {
+
+ private final WeakReference thiz;
+ private String keyword;
+ private int index1, index2;
+
+ private UpdateListTask(PickBlockActivity thiz) {
+ this.thiz = new WeakReference<>(thiz);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ PickBlockActivity activity = thiz.get();
+ if (activity == null) return;
+ keyword = activity.mBinding.text.getText().toString();
+
+ //Save for restoring.
+ index1 = activity.mListManager.findFirstVisibleItemPosition();
+ index2 = activity.mListManager.findLastVisibleItemPosition();
+ if (index2 <= index1) index2 = index1;
+ }
+
+ @Override
+ protected Void doInBackground(Void... voids) {
+ PickBlockActivity activity = thiz.get();
+ if (activity == null) return null;
+ List list = activity.mAdapter.getListControl();
+
+ //Backup all candidates.
+ BlockTemplate[] olds = null;
+ if (index1 >= 0) {
+ olds = new BlockTemplate[index2 - index1 + 1];
+ for (int i = index1, limit = list.size(); i < olds.length && i < limit; i++) {
+ olds[i] = list.get(i);
+ }
+ }
+ //Reset.
+ list.clear();
+
+ //Restore.
+ String text = keyword;
+ int num;
+ try {
+ num = Integer.parseInt(text);
+ } catch (NumberFormatException e) {
+ num = -1;
+ }
+ for (Iterator it = BlockTemplates.getAll().iterator(); it.hasNext(); ) {
+ BlockTemplate b = it.next();
+ if (
+ (b.getBlock().getName().contains(text)))
+ list.add(b);
+ }
+ int position = -1;
+ if (olds != null) for (BlockTemplate b : olds) {
+ int i = list.indexOf(b);
+ if (i != -1) {
+ position = i;
+ break;
+ }
+ }
+ index1 = position;
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ PickBlockActivity activity = thiz.get();
+ if (activity == null) return;
+ activity.mAdapter.notifyDataSetChanged();
+ if (index1 >= 0) activity.mListManager.scrollToPosition(index1);
+ }
+ }
+
+ private class MeowAdapter extends RecyclerView.Adapter {
+
+ private final List mBlocks;
+
+ private MeowAdapter() {
+ mBlocks = new ArrayList<>(512);
+ }
+
+ @NonNull
+ @Override
+ public MeowHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ ItemPickBlockBinding binding = DataBindingUtil.inflate(
+ getLayoutInflater(), R.layout.item_pick_block, mBinding.list, false);
+ View root = binding.getRoot();
+ MeowHolder holder = new MeowHolder(root);
+ holder.binding = binding;
+ root.setOnClickListener(v -> {
+ //UiUtil.toast(PickBlockActivity.this,""+i);
+ setResult(RESULT_OK, new Intent()
+ .putExtra(EXTRA_KEY_BLOCK, holder.binding.getOldBlock()));//;(KnownBlockRepr) v.getTag()));
+ finish();
+ });
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull MeowHolder meowHolder, int i) {
+ BlockTemplate oldBlock = mBlocks.get(i);
+ ItemPickBlockBinding binding = meowHolder.binding;
+ binding.setOldBlock(oldBlock);
+ //binding.getRoot().setTag(oldBlock);
+ binding.icon.setImageBitmap(oldBlock.getIcon().getIcon(PickBlockActivity.this));
+ UiUtil.blendBlockColor(binding.getRoot(), oldBlock);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mBlocks.size();
+ }
+
+ List getListControl() {
+ return mBlocks;
+ }
+
+ class MeowHolder extends RecyclerView.ViewHolder {
+
+ ItemPickBlockBinding binding;
+
+ MeowHolder(@NonNull View itemView) {
+ super(itemView);
+ }
+ }
+
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/Biome.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/Biome.java
index 3eaedd81..41624d90 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/Biome.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/Biome.java
@@ -2,134 +2,161 @@
import android.util.SparseArray;
-import com.mithrilmania.blocktopograph.util.Color;
+import com.mithrilmania.blocktopograph.util.ColorWrapper;
+
/*
Biome enum for MCPE -- by @mithrilmania
+Reference link: https://minecraft.fandom.com/wiki/Biome/ID
--- Please attribute @mithrilmania for generating+updating this enum
*/
public enum Biome {
- OCEAN(0, "Ocean", Color.fromRGB(2, 0, 112)),
- PLAINS(1, "Plains", Color.fromRGB(140, 176, 96)),
- DESERT(2, "Desert", Color.fromRGB(251, 148, 27)),
- EXTREME_HILLS(3, "Extreme Hills", Color.fromRGB(93, 99, 93)),
- FOREST(4, "Forest", Color.fromRGB(2, 99, 32)),
- TAIGA(5, "Taiga", Color.fromRGB(9, 102, 91)),
- SWAMPLAND(6, "Swampland", Color.fromRGB(4, 200, 139)),
- RIVER(7, "River", Color.fromRGB(1, 1, 255)),
- HELL(8, "Hell", Color.fromRGB(255, 0, 1)),
- SKY(9, "Sky", Color.fromRGB(130, 129, 254)),
- FROZEN_OCEAN(10, "Frozen Ocean", Color.fromRGB(142, 141, 161)),
- FROZEN_RIVER(11, "Frozen River", Color.fromRGB(159, 163, 255)),
- ICE_PLAINS(12, "Ice Plains", Color.fromRGB(255, 254, 255)),
- ICE_MOUNTAINS(13, "Ice Mountains", Color.fromRGB(162, 157, 157)),
- MUSHROOM_ISLAND(14, "Mushroom Island", Color.fromRGB(254, 1, 255)),
- MUSHROOM_ISLAND_SHORE(15, "Mushroom Island Shore", Color.fromRGB(158, 3, 253)),
- BEACH(16, "Beach", Color.fromRGB(250, 223, 85)),
- DESERT_HILLS(17, "Desert Hills", Color.fromRGB(212, 94, 15)),
- FOREST_HILLS(18, "Forest Hills", Color.fromRGB(37, 86, 30)),
- TAIGA_HILLS(19, "Taiga Hills", Color.fromRGB(25, 54, 49)),
- EXTREME_HILLS_EDGE(20, "Extreme Hills Edge", Color.fromRGB(115, 118, 157)),
- JUNGLE(21, "Jungle", Color.fromRGB(82, 122, 7)),
- JUNGLE_HILLS(22, "Jungle Hills", Color.fromRGB(46, 64, 3)),
- JUNGLE_EDGE(23, "Jungle Edge", Color.fromRGB(99, 142, 24)),
- DEEP_OCEAN(24, "Deep Ocean", Color.fromRGB(2, 0, 47)),
- STONE_BEACH(25, "Stone Beach", Color.fromRGB(162, 164, 132)),
- COLD_BEACH(26, "Cold Beach", Color.fromRGB(250, 238, 193)),
- BIRCH_FOREST(27, "Birch Forest", Color.fromRGB(48, 117, 70)),
- BIRCH_FOREST_HILLS(28, "Birch Forest Hills", Color.fromRGB(29, 94, 51)),
- ROOFED_FOREST(29, "Roofed Forest", Color.fromRGB(66, 82, 24)),
- COLD_TAIGA(30, "Cold Taiga", Color.fromRGB(49, 85, 75)),
- COLD_TAIGA_HILLS(31, "Cold Taiga Hills", Color.fromRGB(34, 61, 52)),
- MEGA_TAIGA(32, "Mega Taiga", Color.fromRGB(92, 105, 84)),
- MEGA_TAIGA_HILLS(33, "Mega Taiga Hills", Color.fromRGB(70, 76, 59)),
- EXTREME_HILLS_PLUS(34, "Extreme Hills+", Color.fromRGB(79, 111, 81)),
- SAVANNA(35, "Savanna", Color.fromRGB(192, 180, 94)),
- SAVANNA_PLATEAU(36, "Savanna Plateau", Color.fromRGB(168, 157, 98)),
- MESA(37, "Mesa", Color.fromRGB(220, 66, 19)),
- MESA_PLATEAU_F(38, "Mesa Plateau F", Color.fromRGB(174, 152, 100)),
- MESA_PLATEAU(39, "Mesa Plateau", Color.fromRGB(202, 139, 98)),
-
- //fix the colors for these
- SMALL_END_ISLANDS(40, "Small End Islands",Color.fromRGB(202, 139, 98)),
- END_MIDLANDS(41, "End Midlands",Color.fromRGB(202, 139, 98)),
- END_HIGHLANDS(42, "End Highlands",Color.fromRGB(202, 139, 98)),
- END_BARRENS(43, "End Barrens",Color.fromRGB(202, 139, 98)),
- WARM_OCEAN(44, "Warm Ocean",Color.fromRGB(202, 139, 98)),
- LUKEWARM_OCEAN(45, "Lukewarm Ocean",Color.fromRGB(202, 139, 98)),
- COLD_OCEAN(46, "Cold Ocean",Color.fromRGB(202, 139, 98)),
- DEEP_WARM_OCEAN(47, "Deep Warm Ocean",Color.fromRGB(202, 139, 98)),
- DEEP_LUKEWARM_OCEAN(48, "Deep Lukewarm Ocean",Color.fromRGB(202, 139, 98)),
- DEEP_COLD_OCEAN(49, "Deep Cold Ocean",Color.fromRGB(202, 139, 98)),
- DEEP_FROZEN_OCEAN(50, "Deep Frozen Ocean",Color.fromRGB(202, 139, 98)),
-
- //fix the colors for the void
- THE_VOID(127, "The Void", Color.fromRGB(81, 79, 195)),
-
- OCEAN_M(128, "Ocean M", Color.fromRGB(81, 79, 195)),
- SUNFLOWER_PLAINS(129, "Sunflower Plains", Color.fromRGB(220, 255, 177)),
- DESERT_M(130, "Desert M", Color.fromRGB(255, 230, 101)),
- EXTREME_HILLS_M(131, "Extreme Hills M", Color.fromRGB(177, 176, 174)),
- FLOWER_FOREST(132, "Flower Forest", Color.fromRGB(82, 180, 110)),
- TAIGA_M(133, "Taiga M", Color.fromRGB(90, 182, 171)),
- SWAMPLAND_M(134, "Swampland M", Color.fromRGB(87, 255, 255)),
- RIVER_M(135, "River M", Color.fromRGB(82, 79, 255)),
- HELL_M(136, "Hell M", Color.fromRGB(255, 80, 83)),
- SKY_M(137, "Sky M", Color.fromRGB(210, 211, 255)),
- FROZEN_OCEAN_M(138, "Frozen Ocean M", Color.fromRGB(226, 224, 241)),
- FROZEN_RIVER_M(139, "Frozen River M", Color.fromRGB(239, 242, 255)),
- ICE_PLAINS_SPIKES(140, "Ice Plains Spikes", Color.fromRGB(223, 255, 255)),
- ICE_MOUNTAINS_M(141, "Ice Mountains M", Color.fromRGB(237, 237, 238)),
- MUSHROOM_ISLAND_M(142, "Mushroom Island M", Color.fromRGB(255, 82, 255)),
- MUSHROOM_ISLAND_SHORE_M(143, "Mushroom Island Shore M", Color.fromRGB(243, 82, 255)),
- BEACH_M(144, "Beach M", Color.fromRGB(255, 255, 162)),
- DESERT_HILLS_M(145, "Desert Hills M", Color.fromRGB(255, 177, 100)),
- FOREST_HILLS_M(146, "Forest Hills M", Color.fromRGB(113, 167, 109)),
- TAIGA_HILLS_M(147, "Taiga Hills M", Color.fromRGB(103, 135, 134)),
- EXTREME_HILLS_EDGE_M(148, "Extreme Hills Edge M", Color.fromRGB(196, 203, 234)),
- JUNGLE_M(149, "Jungle M", Color.fromRGB(160, 203, 92)),
- JUNGLE_HILLS_M(150, "Jungle Hills M", Color.fromRGB(127, 146, 86)),
- JUNGLE_EDGE_M(151, "Jungle Edge M", Color.fromRGB(179, 217, 105)),
- DEEP_OCEAN_M(152, "Deep Ocean M", Color.fromRGB(82, 79, 130)),
- STONE_BEACH_M(153, "Stone Beach M", Color.fromRGB(242, 243, 209)),
- COLD_BEACH_M(154, "Cold Beach M", Color.fromRGB(255, 255, 255)),
- BIRCH_FOREST_M(155, "Birch Forest M", Color.fromRGB(131, 194, 148)),
- BIRCH_FOREST_HILLS_M(156, "Birch Forest Hills M", Color.fromRGB(111, 175, 133)),
- ROOFED_FOREST_M(157, "Roofed Forest M", Color.fromRGB(143, 158, 109)),
- COLD_TAIGA_M(158, "Cold Taiga M", Color.fromRGB(132, 163, 156)),
- COLD_TAIGA_HILLS_M(159, "Cold Taiga Hills M", Color.fromRGB(113, 143, 136)),
- MEGA_SPRUCE_TAIGA(160, "Mega Spruce Taiga", Color.fromRGB(168, 180, 164)),
- REDWOOD_TAIGA_HILLS_M(161, "Redwood Taiga Hills M", Color.fromRGB(150, 158, 140)),
- EXTREME_HILLS_PLUS_M(162, "Extreme Hills+ M", Color.fromRGB(161, 194, 158)),
- SAVANNA_M(163, "Savanna M", Color.fromRGB(255, 255, 173)),
- SAVANNA_PLATEAU_M(164, "Savanna Plateau M", Color.fromRGB(247, 238, 180)),
- MESA_BRYCE(165, "Mesa (Bryce)", Color.fromRGB(255, 151, 101)),
- MESA_PLATEAU_F_M(166, "Mesa Plateau F M", Color.fromRGB(255, 234, 179)),
- MESA_PLATEAU_M(167, "Mesa Plateau M", Color.fromRGB(255, 220, 184)),
- BAMBOO_JUNGLE(168, "Bamboo Jungle", Color.fromRGB(255, 220, 184)),
- BAMBOO_JUNGLE_HILLS(169, "Bamboo Jungle Hills", Color.fromRGB(255, 220, 184));
-
- public final int id;
- public final String name;
- public final Color color;
-
- Biome(int id, String name, Color color){
- this.id = id;
- this.name = name;
- this.color = color;
- }
-
- private static final SparseArray biomeMap;
- static {
- biomeMap = new SparseArray<>();
- for(Biome b : Biome.values()){
- biomeMap.put(b.id, b);
- }
- }
-
- public static Biome getBiome(int id){
- return biomeMap.get(id);
- }
+ OCEAN(0, "Ocean", ColorWrapper.fromRGB(2, 0, 112)),
+ PLAINS(1, "Plains", ColorWrapper.fromRGB(140, 176, 96)),
+ DESERT(2, "Desert", ColorWrapper.fromRGB(251, 148, 27)),
+ EXTREME_HILLS(3, "Mountains", ColorWrapper.fromRGB(93, 99, 93)),
+ FOREST(4, "Forest", ColorWrapper.fromRGB(2, 99, 32)),
+ TAIGA(5, "Taiga", ColorWrapper.fromRGB(9, 102, 91)),
+ SWAMPLAND(6, "Swampland", ColorWrapper.fromRGB(4, 200, 139)),
+ RIVER(7, "River", ColorWrapper.fromRGB(1, 1, 255)),
+ HELL(8, "Nether Wastes", ColorWrapper.fromRGB(132, 65, 65)),
+ THE_END(9, "The End", ColorWrapper.fromRGB(130, 129, 254)),
+ FROZEN_OCEAN(10, "Frozen Ocean", ColorWrapper.fromRGB(142, 141, 161)),
+ FROZEN_RIVER(11, "Frozen River", ColorWrapper.fromRGB(159, 163, 255)),
+ ICE_PLAINS(12, "Ice Plains", ColorWrapper.fromRGB(255, 254, 255)),
+ ICE_MOUNTAINS(13, "Ice Mountains", ColorWrapper.fromRGB(162, 157, 157)),
+ MUSHROOM_ISLAND(14, "Mushroom Fields", ColorWrapper.fromRGB(254, 1, 255)),
+ MUSHROOM_ISLAND_SHORE(15, "Mushroom Fields Shore", ColorWrapper.fromRGB(158, 3, 253)),
+ BEACH(16, "Beach", ColorWrapper.fromRGB(250, 223, 85)),
+ DESERT_HILLS(17, "Desert Hills", ColorWrapper.fromRGB(212, 94, 15)),
+ FOREST_HILLS(18, "Wooded Hills", ColorWrapper.fromRGB(37, 86, 30)),
+ TAIGA_HILLS(19, "Taiga Hills", ColorWrapper.fromRGB(25, 54, 49)),
+ EXTREME_HILLS_EDGE(20, "Mountain Edge", ColorWrapper.fromRGB(115, 118, 157)),
+ JUNGLE(21, "Jungle", ColorWrapper.fromRGB(82, 122, 7)),
+ JUNGLE_HILLS(22, "Jungle Hills", ColorWrapper.fromRGB(46, 64, 3)),
+ JUNGLE_EDGE(23, "Jungle Edge", ColorWrapper.fromRGB(99, 142, 24)),
+ DEEP_OCEAN(24, "Deep Ocean", ColorWrapper.fromRGB(2, 0, 47)),
+ STONE_BEACH(25, "Stone Shore", ColorWrapper.fromRGB(162, 164, 132)),
+ COLD_BEACH(26, "Snowy Beach", ColorWrapper.fromRGB(250, 238, 193)),
+ BIRCH_FOREST(27, "Birch Forest", ColorWrapper.fromRGB(48, 117, 70)),
+ BIRCH_FOREST_HILLS(28, "Birch Forest Hills", ColorWrapper.fromRGB(29, 94, 51)),
+ ROOFED_FOREST(29, "Dark Forest", ColorWrapper.fromRGB(66, 82, 24)),
+ COLD_TAIGA(30, "Snowy Taiga", ColorWrapper.fromRGB(49, 85, 75)),
+ COLD_TAIGA_HILLS(31, "Snowy Taiga Hills", ColorWrapper.fromRGB(34, 61, 52)),
+ MEGA_TAIGA(32, "Giant Tree Taiga", ColorWrapper.fromRGB(92, 105, 84)),
+ MEGA_TAIGA_HILLS(33, "Giant Tree Taiga Hills", ColorWrapper.fromRGB(70, 76, 59)),
+ EXTREME_HILLS_PLUS_TREE(34, "Wooded Mountains", ColorWrapper.fromRGB(79, 111, 81)),
+ SAVANNA(35, "Savanna", ColorWrapper.fromRGB(192, 180, 94)),
+ SAVANNA_PLATEAU(36, "Savanna Plateau", ColorWrapper.fromRGB(168, 157, 98)),
+ MESA(37, "Badlands", ColorWrapper.fromRGB(220, 66, 19)),
+ MESA_PLATEAU(38, "Badlands Plateau", ColorWrapper.fromRGB(174, 152, 100)),
+ MESA_PLATEAU_STONE(39, "Wooded Badlands Plateau", ColorWrapper.fromRGB(202, 139, 98)),
+
+ //fix the colors for these
+ WARM_OCEAN(40, "Warm Ocean", ColorWrapper.fromRGB(202, 139, 98)),
+ LUKEWARM_OCEAN(41, "Lukewarm Ocean", ColorWrapper.fromRGB(202, 139, 98)),
+ COLD_OCEAN(42, "Cold Ocean", ColorWrapper.fromRGB(202, 139, 98)),
+ DEEP_WARM_OCEAN(43, "Deep Warm Ocean", ColorWrapper.fromRGB(202, 139, 98)),
+ DEEP_LUKEWARM_OCEAN(44, "Deep Lukewarm Ocean", ColorWrapper.fromRGB(202, 139, 98)),
+ DEEP_COLD_OCEAN(45, "Deep Cold Ocean", ColorWrapper.fromRGB(202, 139, 98)),
+ DEEP_FROZEN_OCEAN(46, "Deep Frozen Ocean", ColorWrapper.fromRGB(202, 139, 98)),
+ LEGACY_FROZEN_OCEAN(47, "Legacy Frozen Ocean", ColorWrapper.fromRGB(202, 139, 98)),
+
+ // Not sure are available ( need tester )
+// OCEAN_M(128, "Ocean M", ColorWrapper.fromRGB(81, 79, 195)),
+
+ SUNFLOWER_PLAINS(129, "Sunflower Plains", ColorWrapper.fromRGB(220, 255, 177)),
+ DESERT_MUTATED(130, "Desert Lakes", ColorWrapper.fromRGB(255, 230, 101)),
+ EXTREME_HILLS_MUTATED(131, "Gravelly Mountains", ColorWrapper.fromRGB(177, 176, 174)),
+ FLOWER_FOREST(132, "Flower Forest", ColorWrapper.fromRGB(82, 180, 110)),
+ TAIGA_MUTATED(133, "Taiga Mountains", ColorWrapper.fromRGB(90, 182, 171)),
+ SWAMPLAND_MUTATED(134, "Swamp Hills", ColorWrapper.fromRGB(87, 255, 255)),
+
+ // Not sure available ( need tester )
+// RIVER_M(135, "River M", ColorWrapper.fromRGB(82, 79, 255)),
+// HELL_M(136, "Hell M", ColorWrapper.fromRGB(255, 80, 83)),
+// SKY_M(137, "Sky M", ColorWrapper.fromRGB(210, 211, 255)),
+// FROZEN_OCEAN_M(138, "Frozen Ocean M", ColorWrapper.fromRGB(226, 224, 241)),
+// FROZEN_RIVER_M(139, "Frozen River M", ColorWrapper.fromRGB(239, 242, 255)),
+
+ ICE_PLAINS_SPIKES(140, "Ice Spikes", ColorWrapper.fromRGB(223, 255, 255)),
+
+ // Not sure available ( need tester )
+// ICE_MOUNTAINS_M(141, "Ice Mountains M", ColorWrapper.fromRGB(237, 237, 238)),
+// MUSHROOM_ISLAND_M(142, "Mushroom Island M", ColorWrapper.fromRGB(255, 82, 255)),
+// MUSHROOM_ISLAND_SHORE_M(143, "Mushroom Island Shore M", ColorWrapper.fromRGB(243, 82, 255)),
+// BEACH_M(144, "Beach M", ColorWrapper.fromRGB(255, 255, 162)),
+// DESERT_HILLS_M(145, "Desert Hills M", ColorWrapper.fromRGB(255, 177, 100)),
+// FOREST_HILLS_M(146, "Forest Hills M", ColorWrapper.fromRGB(113, 167, 109)),
+// TAIGA_HILLS_M(147, "Taiga Hills M", ColorWrapper.fromRGB(103, 135, 134)),
+// EXTREME_HILLS_EDGE_M(148, "Extreme Hills Edge M", ColorWrapper.fromRGB(196, 203, 234)),
+
+ JUNGLE_MUTATED(149, "Modified Jungle", ColorWrapper.fromRGB(160, 203, 92)),
+// JUNGLE_HILLS_M(150, "Jungle Hills M", ColorWrapper.fromRGB(127, 146, 86)),
+ JUNGLE_EDGE_MUTATED(151, "Modified Jungle Edge", ColorWrapper.fromRGB(179, 217, 105)),
+// DEEP_OCEAN_M(152, "Deep Ocean M", ColorWrapper.fromRGB(82, 79, 130)),
+// STONE_BEACH_M(153, "Stone Beach M", ColorWrapper.fromRGB(242, 243, 209)),
+// COLD_BEACH_M(154, "Cold Beach M", ColorWrapper.fromRGB(255, 255, 255)),
+ BIRCH_FOREST_MUTATED(155, "Tall Birch Forest", ColorWrapper.fromRGB(131, 194, 148)),
+ BIRCH_FOREST_HILLS_MUTATED(156, "Tall Birch Hills", ColorWrapper.fromRGB(111, 175, 133)),
+ ROOFED_FOREST_MUTATED(157, "Dark Forest Hills", ColorWrapper.fromRGB(143, 158, 109)),
+ COLD_TAIGA_MUTATED(158, "Snowy Taiga Mountains", ColorWrapper.fromRGB(132, 163, 156)),
+// COLD_TAIGA_HILLS_M(159, "Cold Taiga Hills M", ColorWrapper.fromRGB(113, 143, 136)),
+ REDWOOD_TAIGA_MUTATED(160, "Giant Spruce Taiga", ColorWrapper.fromRGB(168, 180, 164)),
+ REDWOOD_TAIGA_HILLS_MUTATED(161, "Giant Spruce Taiga Hills", ColorWrapper.fromRGB(150, 158, 140)),
+ EXTREME_HILLS_PLUS_TREE_MUTATED(162, "Gravelly Mountains", ColorWrapper.fromRGB(161, 194, 158)),
+ SAVANNA_MUTATED(163, "Shattered Savanna", ColorWrapper.fromRGB(255, 255, 173)),
+ SAVANNA_PLATEAU_MUTATED(164, "Shattered Savanna Plateau", ColorWrapper.fromRGB(247, 238, 180)),
+ MESA_BRYCE(165, "Eroded Badlands", ColorWrapper.fromRGB(255, 151, 101)),
+ MESA_PLATEAU_MUTATED(166, "Modified Badlands Plateau", ColorWrapper.fromRGB(255, 234, 179)),
+ MESA_PLATEAU_STONE_MUTATED(167, "Modified Wooded Badlands Plateau", ColorWrapper.fromRGB(255, 220, 184)),
+ BAMBOO_JUNGLE(168, "Bamboo Jungle", ColorWrapper.fromRGB(255, 220, 184)),
+ BAMBOO_JUNGLE_HILLS(169, "Bamboo Jungle Hills", ColorWrapper.fromRGB(255, 220, 184)),
+
+ // 1.16 BIOME
+ SOUL_SAND_VALLEY(178, "Soul Sand Valley", ColorWrapper.fromRGB(66, 113, 114)),
+ CRIMSON_FOREST(179, "Crimson Forest", ColorWrapper.fromRGB(141, 30, 40)),
+ WARPED_FOREST(180, "Warped Forest", ColorWrapper.fromRGB(22, 126, 134)),
+ BASALT_DELTAS(181, "Basalt Deltas", ColorWrapper.fromRGB(75, 69, 71)),
+
+ // 1.17 BIOME ?
+ JAGGED_PEAKS(182, "Jagged Peaks", ColorWrapper.fromRGB(0, 0, 0)),
+ FROZEN_PEAKS(183, "Frozen Peaks", ColorWrapper.fromRGB(0, 0, 0)),
+ SNOWY_SLOPES(184, "Snowy Slopes", ColorWrapper.fromRGB(0, 0, 0)),
+ GROVE(185, "Grove", ColorWrapper.fromRGB(0, 0, 0)),
+ MEADOW(186, "Meadow", ColorWrapper.fromRGB(0, 0, 0)),
+ LUSH_CAVES(187, "Lush Caves", ColorWrapper.fromRGB(0, 0, 0)),
+ DRIPSTONE_CAVES(188, "Dripstone Caves", ColorWrapper.fromRGB(0, 0, 0)),
+ STONY_PEAKS(189, "Stony Peaks", ColorWrapper.fromRGB(0, 0, 0))
+ ;
+
+ private static final SparseArray biomeMap;
+
+ static {
+ biomeMap = new SparseArray<>();
+ for (Biome b : Biome.values()) {
+ biomeMap.put(b.id, b);
+ }
+ }
+
+ public final int id;
+ public final String name;
+ public final ColorWrapper color;
+
+ Biome(int id, String name, ColorWrapper color) {
+ this.id = id;
+ this.name = name;
+ this.color = color;
+ }
+
+ public static Biome getBiome(int id) {
+ return biomeMap.get(id);
+ }
+
+
+ public String getName() {
+ return name;
+ }
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/Block.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/Block.java
deleted file mode 100644
index 1f17fd3d..00000000
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/Block.java
+++ /dev/null
@@ -1,904 +0,0 @@
-package com.mithrilmania.blocktopograph.map;
-
-import android.content.res.AssetManager;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.support.annotation.NonNull;
-import android.util.SparseArray;
-
-import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
-import com.mithrilmania.blocktopograph.util.NamedBitmapProviderHandle;
-import com.mithrilmania.blocktopograph.util.Color;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by mithrilmania
- *
- * ==========================
- * POCKET EDITION BLOCKS ONLY
- * ==========================
- *
- * uvs are up to date with MCPE 0.14.0
- *
- --- Please attribute @mithrilmania for generating+updating this enum
- */
-public enum Block implements NamedBitmapProviderHandle, NamedBitmapProvider {
-
- /*
- * ==============================
- * Blocks
- * ==============================
- */
-
- B_0_0_AIR("air", null, 0, 0, null, 0x00000000, false),
- B_1_0_STONE("stone", "stone", 1, 0, "blocks/stone.png", 0xff464646, false),
- B_1_1_STONE_GRANITE("stone", "granite", 1, 1, "blocks/stone_granite.png", 0xff8c7167, false),
- B_1_2_STONE_GRANITE_SMOOTH("stone", "granite_smooth", 1, 2, "blocks/stone_granite_smooth.png", 0xff946251, false),
- B_1_3_STONE_DIORITE("stone", "diorite", 1, 3, "blocks/stone_diorite.png", 0xffc6c6c6, false),
- B_1_4_STONE_DIORITE_SMOOTH("stone", "diorite_smooth", 1, 4, "blocks/stone_diorite_smooth.png", 0xffbebec1, false),
- B_1_5_STONE_ANDESITE("stone", "andesite", 1, 5, "blocks/stone_andesite.png", 0xff797777, false),
- B_1_6_STONE_ANDESITE_SMOOTH("stone", "andesite_smooth", 1, 6, "blocks/stone_andesite_smooth.png", 0xff828382, false),
- B_2_0_GRASS("grass", null, 2, 0, "blocks/grass_side_carried.png", 0xff939393, true),
- B_3_0_DIRT("dirt", null, 3, 0, "blocks/dirt.png", 0xff866043, true),
- B_4_0_COBBLESTONE("cobblestone", null, 4, 0, "blocks/cobblestone.png", 0xff7a7a7a, false),
- B_5_0_PLANKS_OAK("planks", "oak", 5, 0, "blocks/planks_oak.png", 0xff9c7f4e, false),
- B_5_1_PLANKS_SPRUCE("planks", "spruce", 5, 1, "blocks/planks_spruce.png", 0xff674d2e, false),
- B_5_2_PLANKS_BIRCH("planks", "birch", 5, 2, "blocks/planks_birch.png", 0xffc3b37b, false),
- B_5_3_PLANKS_JUNGLE("planks", "jungle", 5, 3, "blocks/planks_jungle.png", 0xff9a6e4d, false),
- B_5_4_PLANKS_ACACIA("planks", "acacia", 5, 4, "blocks/planks_acacia.png", 0xffaa5a2f, false),
- B_5_5_PLANKS_BIG_OAK("planks", "big_oak", 5, 5, "blocks/planks_big_oak.png", 0xff3b260f, false),
- B_6_0_SAPLING_OAK("sapling", "oak", 6, 0, "blocks/sapling_oak.png", 0x6b476625, false),
- B_6_1_SAPLING_SPRUCE("sapling", "spruce", 6, 1, "blocks/sapling_spruce.png", 0x53333a21, false),
- B_6_2_SAPLING_BIRCH("sapling", "birch", 6, 2, "blocks/sapling_birch.png", 0x6b769654, false),
- B_6_3_SAPLING_JUNGLE("sapling", "jungle", 6, 3, "blocks/sapling_jungle.png", 0x55305612, false),
- B_6_4_SAPLING_ACACIA("sapling", "acacia", 6, 4, "blocks/sapling_acacia.png", 0xff718919, false),
- B_6_5_SAPLING_BIG_OAK("sapling", "big_oak", 6, 5, "blocks/sapling_roofed_oak.png", 0xff6f522d, false),
- B_7_0_BEDROCK("bedrock", null, 7, 0, "blocks/bedrock.png", 0xff535353, false),
- B_8_0_FLOWING_WATER("flowing_water", null, 8, 0, "blocks/water_flow.png", 0x802e43f4, false),
- B_9_0_WATER("water", null, 9, 0, "blocks/water_still.png", 0x802e43f4, false),
- B_10_0_FLOWING_LAVA("flowing_lava", null, 10, 0, "blocks/lava_flow.png", 0xf0d45a12, false),
- B_11_0_LAVA("lava", null, 11, 0, "blocks/lava_still.png", 0xf0d45a12, false),
- B_12_0_SAND_DEFAULT("sand", "default", 12, 0, "blocks/sand.png", 0xffdbd3a0, false),
- B_12_1_SAND_RED("sand", "red", 12, 1, "blocks/red_sand.png", 0xffa7531f, false),
- B_13_0_GRAVEL("gravel", null, 13, 0, "blocks/gravel.png", 0xff7e7c7a, false),
- B_14_0_GOLD_ORE("gold_ore", null, 14, 0, "blocks/gold_ore.png", 0xff8f8b7c, false),
- B_15_0_IRON_ORE("iron_ore", null, 15, 0, "blocks/iron_ore.png", 0xff87827e, false),
- B_16_0_COAL_ORE("coal_ore", null, 16, 0, "blocks/coal_ore.png", 0xff737373, false),
- B_17_0_LOG_OAK("log", "oak", 17, 0, "blocks/log_oak.png", 0xff9a7d4d, false),
- B_17_1_LOG_SPRUCE("log", "spruce", 17, 1, "blocks/log_spruce.png", 0xff9a7d4d, false),
- B_17_2_LOG_BIRCH("log", "birch", 17, 2, "blocks/log_birch.png", 0xff9a7d4d, false),
- B_17_3_LOG_JUNGLE("log", "jungle", 17, 3, "blocks/log_jungle.png", 0xff9a7d4d, false),
- B_18_0_LEAVES_OAK("leaves", "oak", 18, 0, "blocks/leaves_oak.png", 0xff878787, true),
- B_18_1_LEAVES_SPRUCE("leaves", "spruce", 18, 1, "blocks/leaves_spruce.png", 0xff132613, true),
- B_18_2_LEAVES_BIRCH("leaves", "birch", 18, 2, "blocks/leaves_birch.png", 0xff283816, true),
- B_18_3_LEAVES_JUNGLE("leaves", "jungle", 18, 3, "blocks/leaves_jungle.png", 0xff918e86, true),
- B_19_0_SPONGE_DRY("sponge", "dry", 19, 0, "blocks/sponge_dry.png", 0xffb6b639, false),
- B_19_1_SPONGE_WET("sponge", "wet", 19, 1, "blocks/sponge_wet.png", 0xff9b9a33, false),
- B_20_0_GLASS("glass", null, 20, 0, "blocks/glass.png", 0x46daf0f4, false),
- B_21_0_LAPIS_ORE("lapis_ore", null, 21, 0, "blocks/lapis_ore.png", 0xff667086, false),
- B_22_0_LAPIS_BLOCK("lapis_block", null, 22, 0, "blocks/lapis_block.png", 0xff1d47a5, false),
- B_23_0_DISPENSER("dispenser", null, 23, 0, "blocks/dispenser.png", 0xff606060, false),
- B_24_0_SANDSTONE_DEFAULT("sandstone", "default", 24, 0, "blocks/sandstone_default.png", 0xffdad29e, false),
- B_24_1_SANDSTONE_CHISELED("sandstone", "chiseled", 24, 1, "blocks/sandstone_chiseled.png", 0xffdad1a2, false),
- B_24_2_SANDSTONE_SMOOTH("sandstone", "smooth", 24, 2, "blocks/sandstone_smooth.png", 0xffdad1a2, false),
- B_25_0_NOTEBLOCK("noteblock", null, 25, 0, "blocks/noteblock.png", 0xff644332, false),
- B_26_0_BED("bed", null, 26, 0, "blocks/bed.png", 0xff8e1616, false),
- B_27_0_GOLDEN_RAIL("golden_rail", null, 27, 0, "blocks/golden_rail.png", 0xab9a6846, false),
- B_28_0_DETECTOR_RAIL("detector_rail", null, 28, 0, "blocks/detector_rail.png", 0x9b786559, false),
- B_29_0_STICKY_PISTON("sticky_piston", null, 29, 0, "blocks/sticky_piston.png", 0xff8d9263, false),
- B_30_0_WEB("web", null, 30, 0, "blocks/web.png", 0x68dcdcdc, false),
- B_31_1_TALLGRASS_FERN("tallgrass", "fern", 31, 1, "blocks/tallgrass_fern.png", 0xff747474, true),
- B_31_2_TALLGRASS_GRASS("tallgrass", "grass", 31, 2, "blocks/tallgrass_grass.png", 0x4e787878, true),
- B_32_0_DEADBUSH("deadbush", null, 32, 0, "blocks/deadbush.png", 0x517b4f19, false),
- B_33_0_PISTON("piston", null, 33, 0, "blocks/piston.png", 0xff998159, false),
- B_34_0_PISTONARMCOLLISION("pistonArmCollision", null, 34, 0, "blocks/pistonArmCollision.png", 0xff9c7f4e, false),
- B_35_0_WOOL_WHITE("wool", "white", 35, 0, "blocks/wool_colored_white.png", 0xffdddddd, false),
- B_35_1_WOOL_ORANGE("wool", "orange", 35, 1, "blocks/wool_colored_orange.png", 0xffdb7d3e, false),
- B_35_2_WOOL_MAGENTA("wool", "magenta", 35, 2, "blocks/wool_colored_magenta.png", 0xffb350bc, false),
- B_35_3_WOOL_LIGHT_BLUE("wool", "light_blue", 35, 3, "blocks/wool_colored_light_blue.png", 0xff6a8ac9, false),
- B_35_4_WOOL_YELLOW("wool", "yellow", 35, 4, "blocks/wool_colored_yellow.png", 0xffb1a627, false),
- B_35_5_WOOL_LIME("wool", "lime", 35, 5, "blocks/wool_colored_lime.png", 0xff41ae38, false),
- B_35_6_WOOL_PINK("wool", "pink", 35, 6, "blocks/wool_colored_pink.png", 0xffd08499, false),
- B_35_7_WOOL_GRAY("wool", "gray", 35, 7, "blocks/wool_colored_gray.png", 0xff404040, false),
- B_35_8_WOOL_SILVER("wool", "silver", 35, 8, "blocks/wool_colored_silver.png", 0xff9aa1a1, false),
- B_35_9_WOOL_CYAN("wool", "cyan", 35, 9, "blocks/wool_colored_cyan.png", 0xff2e6e89, false),
- B_35_10_WOOL_PURPLE("wool", "purple", 35, 10, "blocks/wool_colored_purple.png", 0xff7e3db5, false),
- B_35_11_WOOL_BLUE("wool", "blue", 35, 11, "blocks/wool_colored_blue.png", 0xff2e388d, false),
- B_35_12_WOOL_BROWN("wool", "brown", 35, 12, "blocks/wool_colored_brown.png", 0xff4f321f, false),
- B_35_13_WOOL_GREEN("wool", "green", 35, 13, "blocks/wool_colored_green.png", 0xff35461b, false),
- B_35_14_WOOL_RED("wool", "red", 35, 14, "blocks/wool_colored_red.png", 0xff963430, false),
- B_35_15_WOOL_BLACK("wool", "black", 35, 15, "blocks/wool_colored_black.png", 0xff191616, false),
- B_37_0_YELLOW_FLOWER("yellow_flower", null, 37, 0, "blocks/yellow_flower.png", 0x1e6ca200, false),
- B_38_0_RED_FLOWER_POPPY("red_flower", "poppy", 38, 0, "blocks/flower_poppy.png", 0x1d8a2b0d, false),
- B_38_1_RED_FLOWER_BLUE_ORCHID("red_flower", "blue_orchid", 38, 1, "blocks/flower_blue_orchid.png", 0x1d188fd3, false),
- B_38_2_RED_FLOWER_ALLIUM("red_flower", "allium", 38, 2, "blocks/flower_allium.png", 0x1ddbb7f8, false),
- B_38_3_RED_FLOWER_HOUSTONIA("red_flower", "houstonia", 38, 3, "blocks/flower_houstonia.png", 0x1defef99, false),
- B_38_4_RED_FLOWER_TULIP_RED("red_flower", "tulip_red", 38, 4, "blocks/flower_tulip_red.png", 0x1dbd2604, false),
- B_38_5_RED_FLOWER_TULIP_ORANGE("red_flower", "tulip_orange", 38, 5, "blocks/flower_tulip_orange.png", 0x1dd06713, false),
- B_38_6_RED_FLOWER_TULIP_WHITE("red_flower", "tulip_white", 38, 6, "blocks/flower_tulip_white.png", 0x1df9f9f9, false),
- B_38_7_RED_FLOWER_TULIP_PINK("red_flower", "tulip_pink", 38, 7, "blocks/flower_tulip_pink.png", 0x1dbeb3be, false),
- B_38_8_RED_FLOWER_OXEYE_DAISY("red_flower", "oxeye_daisy", 38, 8, "blocks/flower_oxeye_daisy.png", 0x1ddadada, false),
- B_39_0_BROWN_MUSHROOM("brown_mushroom", null, 39, 0, "blocks/brown_mushroom.png", 0x198a6953, false),
- B_40_0_RED_MUSHROOM("red_mushroom", null, 40, 0, "blocks/red_mushroom.png", 0x21c33538, false),
- B_41_0_GOLD_BLOCK("gold_block", null, 41, 0, "blocks/gold_block.png", 0xfff9ec4e, false),
- B_42_0_IRON_BLOCK("iron_block", null, 42, 0, "blocks/iron_block.png", 0xffdbdbdb, false),
- B_43_0_DOUBLE_STONE_SLAB_STONE("double_stone_slab", "stone", 43, 0, "blocks/double_stone_slab_stone.png", 0xff9f9f9f, false),
- B_43_1_DOUBLE_STONE_SLAB_SAND("double_stone_slab", "sand", 43, 1, "blocks/double_stone_slab_sand.png", 0xffdad29e, false),
- B_43_2_DOUBLE_STONE_SLAB_WOOD("double_stone_slab", "wood", 43, 2, "blocks/double_stone_slab_wood.png", 0xff9c7f4e, false),
- B_43_3_DOUBLE_STONE_SLAB_COBBLE("double_stone_slab", "cobble", 43, 3, "blocks/double_stone_slab_cobble.png", 0xff7a7a7a, false),
- B_43_4_DOUBLE_STONE_SLAB_BRICK("double_stone_slab", "brick", 43, 4, "blocks/double_stone_slab_brick.png", 0xff926356, false),
- B_43_5_DOUBLE_STONE_SLAB_SMOOTH_STONE_BRICK("double_stone_slab", "smooth_stone_brick", 43, 5, "blocks/double_stone_slab_smooth_stone_brick.png", 0xff7d7d7d, false),
- B_43_6_DOUBLE_STONE_SLAB_QUARTZ("double_stone_slab", "quartz", 43, 6, "blocks/double_stone_slab_quartz.png", 0xff2c161a, false),
- B_43_7_DOUBLE_STONE_SLAB_NETHER_BRICK("double_stone_slab", "nether_brick", 43, 7, "blocks/double_stone_slab_nether_brick.png", 0xffece9e2, false),
- B_43_8_DOUBLE_STONE_SLAB_RED_SANDSTONE("double_stone_slab", "red_sandstone", 43, 8, "blocks/double_stone_slab_red_sandstone.png", 0xff9f9f9f, false),
- B_44_0_STONE_SLAB_STONE("stone_slab", "stone", 44, 0, "blocks/stone_slab_side.png", 0xff9f9f9f, false),
- B_44_1_STONE_SLAB_SAND("stone_slab", "sand", 44, 1, "blocks/stone_slab_side.png", 0xffdad29e, false),
- B_44_2_STONE_SLAB_WOOD("stone_slab", "wood", 44, 2, "blocks/stone_slab_side.png", 0xff9c7f4e, false),
- B_44_3_STONE_SLAB_COBBLE("stone_slab", "cobble", 44, 3, "blocks/stone_slab_side.png", 0xff7a7a7a, false),
- B_44_4_STONE_SLAB_BRICK("stone_slab", "brick", 44, 4, "blocks/stone_slab_side.png", 0xff926356, false),
- B_44_5_STONE_SLAB_SMOOTH_STONE_BRICK("stone_slab", "smooth_stone_brick", 44, 5, "blocks/stone_slab_side.png", 0xff7d7d7d, false),
- B_44_6_STONE_SLAB_QUARTZ("stone_slab", "quartz", 44, 6, "blocks/stone_slab_side.png", 0xff2c161a, false),
- B_44_7_STONE_SLAB_NETHER_BRICK("stone_slab", "nether_brick", 44, 7, "blocks/stone_slab_side.png", 0xffece9e2, false),
- B_45_0_BRICK_BLOCK("brick_block", null, 45, 0, "blocks/brick_block.png", 0xff926356, false),
- B_46_0_TNT("tnt", null, 46, 0, "blocks/tnt.png", 0xff82412f, false),
- B_47_0_BOOKSHELF("bookshelf", null, 47, 0, "blocks/bookshelf.png", 0xff6b5839, false),
- B_48_0_MOSSY_COBBLESTONE("mossy_cobblestone", null, 48, 0, "blocks/mossy_cobblestone.png", 0xff677967, false),
- B_49_0_OBSIDIAN("obsidian", null, 49, 0, "blocks/obsidian.png", 0xff14121d, false),
- B_50_0_TORCH("torch", null, 50, 0, "blocks/torch.png", 0x13826a3a, false),
- B_51_0_FIRE("fire", null, 51, 0, "blocks/fire.png", 0x8bd38c35, false),
- B_52_0_MOB_SPAWNER("mob_spawner", null, 52, 0, "blocks/mob_spawner.png", 0x9b1a2731, false),
- B_53_0_OAK_STAIRS("oak_stairs", null, 53, 0, "blocks/oak_stairs.png", 0xff9c7f4e, false),
- B_54_0_CHEST("chest", null, 54, 0, "blocks/chest_front.png", 0xc86f5739, false),
- B_55_0_REDSTONE_WIRE("redstone_wire", null, 55, 0, "blocks/redstone_wire.png", 0x80fa1010, false),
- B_56_0_DIAMOND_ORE("diamond_ore", null, 56, 0, "blocks/diamond_ore.png", 0xff818c8f, false),
- B_57_0_DIAMOND_BLOCK("diamond_block", null, 57, 0, "blocks/diamond_block.png", 0xff61dbd5, false),
- B_58_0_CRAFTING_TABLE("crafting_table", null, 58, 0, "blocks/crafting_table.png", 0xff6b472a, false),
- B_59_0_WHEAT("wheat", null, 59, 0, "blocks/wheat.png", 0x0500b312, false),
- B_60_0_FARMLAND("farmland", null, 60, 0, "blocks/farmland.png", 0xff734b2d, false),
- B_61_0_FURNACE("furnace", null, 61, 0, "blocks/furnace.png", 0xff606060, false),
- B_62_0_LIT_FURNACE("lit_furnace", null, 62, 0, "blocks/lit_furnace.png", 0xff606060, false),
- B_63_0_STANDING_SIGN("standing_sign", null, 63, 0, "blocks/standing_sign.png", 0x566f5739, false),
- B_64_0_WOODEN_DOOR("wooden_door", null, 64, 0, "blocks/wooden_door.png", 0xcf866733, false),
- B_65_0_LADDER("ladder", null, 65, 0, "blocks/ladder.png", 0x8f795f34, false),
- B_66_0_RAIL("rail", null, 66, 0, "blocks/rail.png", 0x8f796c58, false),
- B_67_0_STONE_STAIRS("stone_stairs", null, 67, 0, "blocks/stone_stairs.png", 0xff7a7a7a, false),
- B_68_0_WALL_SIGN("wall_sign", null, 68, 0, "blocks/wall_sign.png", 0x206f5739, false),
- B_69_0_LEVER("lever", null, 69, 0, "blocks/lever.png", 0x136a5940, false),
- B_70_0_STONE_PRESSURE_PLATE("stone_pressure_plate", null, 70, 0, "blocks/stone_pressure_plate.png", 0xff7d7d7d, false),
- B_71_0_IRON_DOOR("iron_door", null, 71, 0, "blocks/iron_door.png", 0xcfbababa, false),
- B_72_0_WOODEN_PRESSURE_PLATE("wooden_pressure_plate", null, 72, 0, "blocks/wooden_pressure_plate.png", 0xff9c7f4e, false),
- B_73_0_REDSTONE_ORE("redstone_ore", null, 73, 0, "blocks/redstone_ore.png", 0xff846b6b, false),
- B_74_0_LIT_REDSTONE_ORE("lit_redstone_ore", null, 74, 0, "blocks/lit_redstone_ore.png", 0xff846b6b, false),
- B_75_0_UNLIT_REDSTONE_TORCH("unlit_redstone_torch", null, 75, 0, "blocks/unlit_redstone_torch.png", 0x465d3e26, false),
- B_76_0_REDSTONE_TORCH("redstone_torch", null, 76, 0, "blocks/redstone_torch.png", 0x46a74b29, false),
- B_77_0_STONE_BUTTON("stone_button", null, 77, 0, "blocks/stone_button.png", 0x28565656, false),
- B_78_0_SNOW_LAYER("snow_layer", null, 78, 0, "blocks/snow_layer.png", 0xffeffbfb, false),
- B_79_0_ICE("ice", null, 79, 0, "blocks/ice.png", 0x9f7dadff, false),
- B_80_0_SNOW("snow", null, 80, 0, "blocks/snow.png", 0xffeffbfb, false),
- B_81_0_CACTUS("cactus", null, 81, 0, "blocks/cactus.png", 0xc30d6318, false),
- B_82_0_CLAY("clay", null, 82, 0, "blocks/clay.png", 0xff9ea4b0, false),
- B_83_0_REEDS("reeds", null, 83, 0, "blocks/reeds.png", 0x8c94c065, false),
-
- B_84_0_JUKEBOX("jukebox", null, 84, 0, "blocks/fence_birch_fence.png", 0x8f463822, false),
-
- B_85_0_FENCE_FENCE("fence", "fence", 85, 0, "blocks/fence_fence.png", 0x8f463822, false),
- B_85_1_FENCE_SPRUCE_FENCE("fence", "spruce_fence", 85, 1, "blocks/fence_spruce_fence.png", 0x8f463822, false),
- B_85_2_FENCE_BIRCH_FENCE("fence", "birch_fence", 85, 2, "blocks/fence_birch_fence.png", 0x8f463822, false),
- B_85_3_FENCE_JUNGLE_FENCE("fence", "jungle_fence", 85, 3, "blocks/fence_jungle_fence.png", 0x8f463822, false),
- B_85_4_FENCE_ACACIA_FENCE("fence", "acacia_fence", 85, 4, "blocks/fence_acacia_fence.png", 0x8f463822, false),
- B_85_5_FENCE_DARK_OAK_FENCE("fence", "dark_oak_fence", 85, 5, "blocks/fence_dark_oak_fence.png", 0x8f463822, false),
- B_86_0_PUMPKIN("pumpkin", null, 86, 0, "blocks/pumpkin.png", 0xffc07615, false),
- B_87_0_NETHERRACK("netherrack", null, 87, 0, "blocks/netherrack.png", 0xff6f3634, false),
- B_88_0_SOUL_SAND("soul_sand", null, 88, 0, "blocks/soul_sand.png", 0xff544033, false),
- B_89_0_GLOWSTONE("glowstone", null, 89, 0, "blocks/glowstone.png", 0xff8f7645, false),
- B_90_0_PORTAL("portal", null, 90, 0, "blocks/portal.png", 0xc8410491, false),
- B_91_0_LIT_PUMPKIN("lit_pumpkin", null, 91, 0, "blocks/lit_pumpkin.png", 0xffc07615, false),
- B_92_0_CAKE("cake", null, 92, 0, "blocks/cake.png", 0xc3e4cdce, false),
- B_93_0_UNPOWERED_REPEATER("unpowered_repeater", null, 93, 0, "blocks/unpowered_repeater.png", 0xff979393, false),
- B_94_0_POWERED_REPEATER("powered_repeater", null, 94, 0, "blocks/powered_repeater.png", 0xffa09393, false),
- B_95_0_INVISIBLEBEDROCK("invisibleBedrock", null, 95, 0, "blocks/invisibleBedrock.png", 0x3c282828, false),
- B_96_0_TRAPDOOR("trapdoor", null, 96, 0, "blocks/trapdoor.png", 0xdb7e5d2d, false),
- B_97_0_MONSTER_EGG_STONE("monster_egg", "stone", 97, 0, "blocks/monster_egg_stone.png", 0xff7d7d7d, false),
- B_97_1_MONSTER_EGG_COBBLE("monster_egg", "cobble", 97, 1, "blocks/monster_egg_cobble.png", 0xff7a7a7a, false),
- B_97_2_MONSTER_EGG_BRICK("monster_egg", "brick", 97, 2, "blocks/monster_egg_brick.png", 0xff7a7a7a, false),
- B_97_3_MONSTER_EGG_MOSSYBRICK("monster_egg", "mossybrick", 97, 3, "blocks/monster_egg_mossybrick.png", 0xff7b6651, false),
- B_97_4_MONSTER_EGG_CRACKEDBRICK("monster_egg", "crackedbrick", 97, 4, "blocks/monster_egg_crackedbrick.png", 0xff7b6651, false),
- B_97_5_MONSTER_EGG_CHISELEDBRICK("monster_egg", "chiseledbrick", 97, 5, "blocks/monster_egg_chiseledbrick.png", 0xff7b6651, false),
- B_98_0_STONEBRICK_DEFAULT("stonebrick", "default", 98, 0, "blocks/stonebrick_default.png", 0xff7a7a7a, false),
- B_98_1_STONEBRICK_MOSSY("stonebrick", "mossy", 98, 1, "blocks/stonebrick_mossy.png", 0xff72776a, false),
- B_98_2_STONEBRICK_CRACKED("stonebrick", "cracked", 98, 2, "blocks/stonebrick_cracked.png", 0xff767676, false),
- B_98_3_STONEBRICK_CHISELED("stonebrick", "chiseled", 98, 3, "blocks/stonebrick_chiseled.png", 0xff767676, false),
- B_98_4_STONEBRICK_SMOOTH("stonebrick", "smooth", 98, 4, "blocks/stonebrick_smooth.png", 0xff767676, false),
- B_99_0_BROWN_MUSHROOM_BLOCK("brown_mushroom_block", null, 99, 0, "blocks/brown_mushroom_block.png", 0xff8d6a53, false),
- B_100_0_RED_MUSHROOM_BLOCK("red_mushroom_block", null, 100, 0, "blocks/red_mushroom_block.png", 0xffb62524, false),
- B_101_0_IRON_BARS("iron_bars", null, 101, 0, "blocks/iron_bars.png", 0x736d6c6a, false),
- B_102_0_GLASS_PANE("glass_pane", null, 102, 0, "blocks/glass_pane.png", 0x1fd3eff4, false),
- B_103_0_MELON_BLOCK("melon_block", null, 103, 0, "blocks/melon_block.png", 0xff979924, false),
- B_104_0_PUMPKIN_STEM("pumpkin_stem", null, 104, 0, "blocks/pumpkin_stem.png", 0x1e87b759, false),
- B_105_0_MELON_STEM("melon_stem", null, 105, 0, "blocks/melon_stem.png", 0x1e87b759, false),
- B_106_0_VINE("vine", null, 106, 0, "blocks/vine.png", 0x8a6f6f6f, false),
- B_107_0_FENCE_GATE("fence_gate", null, 107, 0, "blocks/fence_gate.png", 0x7b463822, false),
- B_108_0_BRICK_STAIRS("brick_stairs", null, 108, 0, "blocks/brick_stairs.png", 0xff926356, false),
- B_109_0_STONE_BRICK_STAIRS("stone_brick_stairs", null, 109, 0, "blocks/stone_brick_stairs.png", 0xff7a7a7a, false),
- B_110_0_MYCELIUM("mycelium", null, 110, 0, "blocks/mycelium.png", 0xff6f6369, false),
- B_111_0_WATERLILY("waterlily", null, 111, 0, "blocks/waterlily.png", 0x93335a21, false),
- B_112_0_NETHER_BRICK("nether_brick", null, 112, 0, "blocks/nether_brick.png", 0xff2c161a, false),
- B_113_0_NETHER_BRICK_FENCE("nether_brick_fence", null, 113, 0, "blocks/nether_brick_fence.png", 0xff2c161a, false),
- B_114_0_NETHER_BRICK_STAIRS("nether_brick_stairs", null, 114, 0, "blocks/nether_brick_stairs.png", 0xff2c161a, false),
- B_115_0_NETHER_WART("nether_wart", null, 115, 0, "blocks/nether_wart.png", 0x2a6a0e1e, false),
- B_116_0_ENCHANTING_TABLE("enchanting_table", null, 116, 0, "blocks/enchanting_table.png", 0xff67403b, false),
- B_117_0_BREWING_STAND("brewing_stand", null, 117, 0, "blocks/brewing_stand.png", 0x767c6751, false),
- B_118_0_CAULDRON("cauldron", null, 118, 0, "blocks/cauldron.png", 0xff373737, false),
- B_119_0_END_PORTAL("end_portal", null, 119, 0, "blocks/endframe_top.png", 0xff101010, false),
- B_120_0_END_PORTAL_FRAME("end_portal_frame", null, 120, 0, "blocks/endframe_side.png", 0xff597560, false),
- B_121_0_END_STONE("end_stone", null, 121, 0, "blocks/end_stone.png", 0xffdddfa5, false),
- B_122_0_DRAGON_EGG("dragon_egg", null, 122, 0, "blocks/dragon_egg.png", 0xff0c090f, false),
- B_123_0_REDSTONE_LAMP("redstone_lamp", null, 123, 0, "blocks/redstone_lamp.png", 0xff462b1a, false),
- B_124_0_LIT_REDSTONE_LAMP("lit_redstone_lamp", null, 124, 0, "blocks/lit_redstone_lamp.png", 0xff775937, false),
- B_125_0_DROPPER("dropper", null, 125, 0, "blocks/dropper.png", 0xff9c7f4e, false),
- B_126_0_ACTIVATOR_RAIL("activator_rail", null, 126, 0, "blocks/activator_rail.png", 0xff9c7f4e, false),
- B_127_0_COCOA("cocoa", null, 127, 0, "blocks/cocoa.png", 0x2e8a8c40, false),
- B_128_0_SANDSTONE_STAIRS("sandstone_stairs", null, 128, 0, "blocks/sandstone_stairs.png", 0xffdad29e, false),
- B_129_0_EMERALD_ORE("emerald_ore", null, 129, 0, "blocks/emerald_ore.png", 0xff6d8074, false),
- B_130_0_ENDER_CHEST("ender_chest", null, 130, 0, "blocks/ender_chest_front.png", 0xc82c3e40, false),
- B_131_0_TRIPWIRE_HOOK("tripwire_hook", null, 131, 0, "blocks/tripwire_hook.png", 0x2d8a8171, false),
- B_132_0_TRIPWIRE("tripWire", null, 132, 0, "blocks/tripWire.png", 0x2d818181, false),
- B_133_0_EMERALD_BLOCK("emerald_block", null, 133, 0, "blocks/emerald_block.png", 0xff51d975, false),
- B_134_0_SPRUCE_STAIRS("spruce_stairs", null, 134, 0, "blocks/spruce_stairs.png", 0xff674d2e, false),
- B_135_0_BIRCH_STAIRS("birch_stairs", null, 135, 0, "blocks/birch_stairs.png", 0xffc3b37b, false),
- B_136_0_JUNGLE_STAIRS("jungle_stairs", null, 136, 0, "blocks/jungle_stairs.png", 0xff9a6e4d, false),
- B_138_0_BEACON("beacon", null, 138, 0, "blocks/beacon.png", 0xff74ddd7, false),
- B_137_0_IMPULSE_COMMAND_BLOCK("impulse_command_block", null, 137, 0, "blocks/beacon.png", 0xff9a6e4d, false),
- B_137_4_IMPULSE_COMMAND_BLOCK("impulse_command_block", null, 137, 4, "blocks/beacon.png", 0xff9a6e4d, false),
- B_139_0_COBBLESTONE_WALL_NORMAL("cobblestone_wall", "normal", 139, 0, "blocks/cobblestone_wall_normal.png", 0xff7a7a7a, false),
- B_139_1_COBBLESTONE_WALL_MOSSY("cobblestone_wall", "mossy", 139, 1, "blocks/cobblestone_wall_mossy.png", 0xff506a50, false),
- B_140_0_FLOWER_POT("flower_pot", null, 140, 0, "blocks/flower_pot.png", 0x31764133, false),
- B_141_0_CARROTS("carrots", null, 141, 0, "blocks/carrots.png", 0x0901ab10, false),
- B_142_0_POTATOES("potatoes", null, 142, 0, "blocks/potatoes.png", 0x0901ab10, false),
- B_143_0_WOODEN_BUTTON("wooden_button", null, 143, 0, "blocks/wooden_button.png", 0x2878613e, false),
- B_144_0_SKULL("skull", null, 144, 0, "blocks/skull.png", 0x8c8c8c8c, false),
- B_145_0_ANVIL_INTACT("anvil", "intact", 145, 0, "blocks/anvil_intact.png", 0x9f403c3c, false),
- B_145_4_ANVIL_SLIGHTLY_DAMAGED("anvil", "slightly_damaged", 145, 4, "blocks/anvil_slightly_damaged.png", 0x9f403c3c, false),
- B_145_8_ANVIL_VERY_DAMAGED("anvil", "very_damaged", 145, 8, "blocks/anvil_very_damaged.png", 0x9f403c3c, false),
- B_146_0_TRAPPED_CHEST("trapped_chest", null, 146, 0, "blocks/chest_front.png", 0xfe6f5739, false),
- B_147_0_LIGHT_WEIGHTED_PRESSURE_PLATE("light_weighted_pressure_plate", null, 147, 0, "blocks/light_weighted_pressure_plate.png", 0xc8f9ec4e, false),
- B_148_0_HEAVY_WEIGHTED_PRESSURE_PLATE("heavy_weighted_pressure_plate", null, 148, 0, "blocks/heavy_weighted_pressure_plate.png", 0xc8dbdbdb, false),
- B_149_0_UNPOWERED_COMPARATOR("unpowered_comparator", null, 149, 0, "blocks/unpowered_comparator.png", 0xff9c9695, false),
- B_150_0_POWERED_COMPARATOR("powered_comparator", null, 150, 0, "blocks/powered_comparator.png", 0xffa59594, false),
- B_151_0_DAYLIGHT_DETECTOR("daylight_detector", null, 151, 0, "blocks/daylight_detector.png", 0xff82745e, false),
- B_152_0_REDSTONE_BLOCK("redstone_block", null, 152, 0, "blocks/redstone_block.png", 0xffab1b09, false),
- B_153_0_QUARTZ_ORE("quartz_ore", null, 153, 0, "blocks/quartz_ore.png", 0xffd9d1c8, false),
- B_154_0_HOPPER("hopper", null, 154, 0, "blocks/hopper.png", 0xff3e3e3e, false),
- B_155_0_QUARTZ_BLOCK_DEFAULT("quartz_block", "default", 155, 0, "blocks/quartz_block_default.png", 0xffece9e2, false),
- B_155_1_QUARTZ_BLOCK_CHISELED("quartz_block", "chiseled", 155, 1, "blocks/quartz_block_chiseled.png", 0xffe7e4db, false),
- B_155_2_QUARTZ_BLOCK_LINES("quartz_block", "lines", 155, 2, "blocks/quartz_block_lines.png", 0xffe8e5dd, false),
- B_155_3_QUARTZ_BLOCK_DEFAULT("quartz_block", "default", 155, 3, "blocks/quartz_block_default.png", 0xffe7e3db, false),
- B_156_0_QUARTZ_STAIRS("quartz_stairs", null, 156, 0, "blocks/quartz_stairs.png", 0xffece9e2, false),
- B_157_0_DOUBLE_WOODEN_SLAB_OAK("double_wooden_slab", "oak", 157, 0, "blocks/planks_oak.png", 0xb4907449, false),
- B_157_1_DOUBLE_WOODEN_SLAB_SPRUCE("double_wooden_slab", "spruce", 157, 1, "blocks/planks_spruce.png", 0xb4907449, false),
- B_157_2_DOUBLE_WOODEN_SLAB_BIRCH("double_wooden_slab", "birch", 157, 2, "blocks/planks_birch.png", 0xb4907449, false),
- B_157_3_DOUBLE_WOODEN_SLAB_JUNGLE("double_wooden_slab", "jungle", 157, 3, "blocks/planks_jungle.png", 0xb4907449, false),
- B_157_4_DOUBLE_WOODEN_SLAB_ACACIA("double_wooden_slab", "acacia", 157, 4, "blocks/planks_acacia.png", 0xb4907449, false),
- B_157_5_DOUBLE_WOODEN_SLAB_BIG_OAK("double_wooden_slab", "big_oak", 157, 5, "blocks/planks_big_oak.png", 0xb4907449, false),
- B_158_0_WOODEN_SLAB_OAK("wooden_slab", "oak", 158, 0, "blocks/wooden_slab_oak.png", 0xff907449, false),
- B_158_1_WOODEN_SLAB_SPRUCE("wooden_slab", "spruce", 158, 1, "blocks/wooden_slab_spruce.png", 0xff907449, false),
- B_158_2_WOODEN_SLAB_BIRCH("wooden_slab", "birch", 158, 2, "blocks/wooden_slab_birch.png", 0xff907449, false),
- B_158_3_WOODEN_SLAB_JUNGLE("wooden_slab", "jungle", 158, 3, "blocks/wooden_slab_jungle.png", 0xff907449, false),
- B_158_4_WOODEN_SLAB_ACACIA("wooden_slab", "acacia", 158, 4, "blocks/wooden_slab_acacia.png", 0xff907449, false),
- B_158_5_WOODEN_SLAB_BIG_OAK("wooden_slab", "big_oak", 158, 5, "blocks/wooden_slab_big_oak.png", 0xff907449, false),
- B_159_0_STAINED_HARDENED_CLAY_WHITE("stained_hardened_clay", "white", 159, 0, "blocks/hardened_clay_stained_white.png", 0xff836f64, false),
- B_159_1_STAINED_HARDENED_CLAY_ORANGE("stained_hardened_clay", "orange", 159, 1, "blocks/hardened_clay_stained_orange.png", 0xff9d5021, false),
- B_159_2_STAINED_HARDENED_CLAY_MAGENTA("stained_hardened_clay", "magenta", 159, 2, "blocks/hardened_clay_stained_magenta.png", 0xff915369, false),
- B_159_3_STAINED_HARDENED_CLAY_LIGHT_BLUE("stained_hardened_clay", "light_blue", 159, 3, "blocks/hardened_clay_stained_light_blue.png", 0xff706b87, false),
- B_159_4_STAINED_HARDENED_CLAY_YELLOW("stained_hardened_clay", "yellow", 159, 4, "blocks/hardened_clay_stained_yellow.png", 0xffb5801f, false),
- B_159_5_STAINED_HARDENED_CLAY_LIME("stained_hardened_clay", "lime", 159, 5, "blocks/hardened_clay_stained_lime.png", 0xff617030, false),
- B_159_6_STAINED_HARDENED_CLAY_PINK("stained_hardened_clay", "pink", 159, 6, "blocks/hardened_clay_stained_pink.png", 0xff9c4848, false),
- B_159_7_STAINED_HARDENED_CLAY_GRAY("stained_hardened_clay", "gray", 159, 7, "blocks/hardened_clay_stained_gray.png", 0xff392721, false),
- B_159_8_STAINED_HARDENED_CLAY_SILVER("stained_hardened_clay", "silver", 159, 8, "blocks/hardened_clay_stained_silver.png", 0xff81655b, false),
- B_159_9_STAINED_HARDENED_CLAY_CYAN("stained_hardened_clay", "cyan", 159, 9, "blocks/hardened_clay_stained_cyan.png", 0xff565959, false),
- B_159_10_STAINED_HARDENED_CLAY_PURPLE("stained_hardened_clay", "purple", 159, 10, "blocks/hardened_clay_stained_purple.png", 0xff744555, false),
- B_159_11_STAINED_HARDENED_CLAY_BLUE("stained_hardened_clay", "blue", 159, 11, "blocks/hardened_clay_stained_blue.png", 0xff463857, false),
- B_159_12_STAINED_HARDENED_CLAY_BROWN("stained_hardened_clay", "brown", 159, 12, "blocks/hardened_clay_stained_brown.png", 0xff492e1f, false),
- B_159_13_STAINED_HARDENED_CLAY_GREEN("stained_hardened_clay", "green", 159, 13, "blocks/hardened_clay_stained_green.png", 0xff484f26, false),
- B_159_14_STAINED_HARDENED_CLAY_RED("stained_hardened_clay", "red", 159, 14, "blocks/hardened_clay_stained_red.png", 0xffff382b, false),
- B_159_15_STAINED_HARDENED_CLAY_BLACK("stained_hardened_clay", "black", 159, 15, "blocks/hardened_clay_stained_black.png", 0xff21120d, false),
- B_160_0_STAINED_GLASS_PANE_WHITE("stained_glass_pane", "white", 160, 0, "blocks/glass.png", 0x32141414, false),
- B_160_1_STAINED_GLASS_PANE_ORANGE("stained_glass_pane", "orange", 160, 1, "blocks/glass.png", 0x209d5021, false),
- B_160_2_STAINED_GLASS_PANE_MAGENTA("stained_glass_pane", "magenta", 160, 2, "blocks/glass.png", 0x20915369, false),
- B_160_3_STAINED_GLASS_PANE_LIGHT_BLUE("stained_glass_pane", "light_blue", 160, 3, "blocks/glass.png", 0x20706b87, false),
- B_160_4_STAINED_GLASS_PANE_YELLOW("stained_glass_pane", "yellow", 160, 4, "blocks/glass.png", 0x20b5801f, false),
- B_160_5_STAINED_GLASS_PANE_LIME("stained_glass_pane", "lime", 160, 5, "blocks/glass.png", 0x20617030, false),
- B_160_6_STAINED_GLASS_PANE_PINK("stained_glass_pane", "pink", 160, 6, "blocks/glass.png", 0x209c4848, false),
- B_160_7_STAINED_GLASS_PANE_GRAY("stained_glass_pane", "gray", 160, 7, "blocks/glass.png", 0x20392721, false),
- B_160_8_STAINED_GLASS_PANE_SILVER("stained_glass_pane", "silver", 160, 8, "blocks/glass.png", 0x2081655b, false),
- B_160_9_STAINED_GLASS_PANE_CYAN("stained_glass_pane", "cyan", 160, 9, "blocks/glass.png", 0x20565959, false),
- B_160_10_STAINED_GLASS_PANE_PURPLE("stained_glass_pane", "purple", 160, 10, "blocks/glass.png", 0x20744555, false),
- B_160_11_STAINED_GLASS_PANE_BLUE("stained_glass_pane", "blue", 160, 11, "blocks/glass.png", 0x20463857, false),
- B_160_12_STAINED_GLASS_PANE_BROWN("stained_glass_pane", "brown", 160, 12, "blocks/glass.png", 0x20492e1f, false),
- B_160_13_STAINED_GLASS_PANE_GREEN("stained_glass_pane", "green", 160, 13, "blocks/glass.png", 0x20484f26, false),
- B_160_14_STAINED_GLASS_PANE_RED("stained_glass_pane", "red", 160, 14, "blocks/glass.png", 0x20ff382b, false),
- B_160_15_STAINED_GLASS_PANE_BLACK("stained_glass_pane", "black", 160, 15, "blocks/glass.png", 0x2021120d, false),
- B_161_0_LEAVES2_ACACIA("leaves2", "acacia", 161, 0, "blocks/leaves2_acacia.png", 0xff2e780c, true),
- B_161_1_LEAVES2_BIG_OAK("leaves2", "big_oak", 161, 1, "blocks/leaves2_big_oak.png", 0xff878787, true),
- B_162_0_LOG2_ACACIA("log2", "acacia", 162, 0, "blocks/log2_acacia.png", 0xff433f39, false),
- B_162_1_LOG2_BIG_OAK("log2", "big_oak", 162, 1, "blocks/log2_big_oak.png", 0xff2d2213, false),
- B_163_0_ACACIA_STAIRS("acacia_stairs", null, 163, 0, "blocks/acacia_stairs.png", 0xffa95c33, false),
- B_164_0_DARK_OAK_STAIRS("dark_oak_stairs", null, 164, 0, "blocks/dark_oak_stairs.png", 0xff3f2913, false),
- B_165_0_SLIME("slime", null, 165, 0, "blocks/slime.png", 0xc880b672, false),
- B_167_0_IRON_TRAPDOOR("iron_trapdoor", null, 167, 0, "blocks/iron_trapdoor.png", 0xb4cccccc, false),
- B_168_0_PRISMARINE_ROUGH("prismarine", "rough", 168, 0, "blocks/prismarine_rough.png", 0xff426a64, false),
- B_168_1_PRISMARINE_DARK("prismarine", "dark", 168, 1, "blocks/prismarine_dark.png", 0xff577a73, false),
- B_168_2_PRISMARINE_BRICKS("prismarine", "bricks", 168, 2, "blocks/prismarine_bricks.png", 0xff2f483e, false),
- B_169_0_SEALANTERN("seaLantern", null, 169, 0, "blocks/seaLantern.png", 0xffe0eae4, false),
- B_170_0_HAY_BLOCK("hay_block", null, 170, 0, "blocks/hay_block.png", 0xffa3870e, false),
- B_171_0_CARPET_WHITE("carpet", "white", 171, 0, "blocks/carpet_white.png", 0xffdddddd, false),
- B_171_1_CARPET_ORANGE("carpet", "orange", 171, 1, "blocks/carpet_orange.png", 0xffdb7d3e, false),
- B_171_2_CARPET_MAGENTA("carpet", "magenta", 171, 2, "blocks/carpet_magenta.png", 0xffb350bc, false),
- B_171_3_CARPET_LIGHT_BLUE("carpet", "light_blue", 171, 3, "blocks/carpet_light_blue.png", 0xff6a8ac9, false),
- B_171_4_CARPET_YELLOW("carpet", "yellow", 171, 4, "blocks/carpet_yellow.png", 0xffb1a627, false),
- B_171_5_CARPET_LIME("carpet", "lime", 171, 5, "blocks/carpet_lime.png", 0xff41ae38, false),
- B_171_6_CARPET_PINK("carpet", "pink", 171, 6, "blocks/carpet_pink.png", 0xffd08499, false),
- B_171_7_CARPET_GRAY("carpet", "gray", 171, 7, "blocks/carpet_gray.png", 0xff404040, false),
- B_171_8_CARPET_SILVER("carpet", "silver", 171, 8, "blocks/carpet_silver.png", 0xff9aa1a1, false),
- B_171_9_CARPET_CYAN("carpet", "cyan", 171, 9, "blocks/carpet_cyan.png", 0xff2e6e89, false),
- B_171_10_CARPET_PURPLE("carpet", "purple", 171, 10, "blocks/carpet_purple.png", 0xff7e3db5, false),
- B_171_11_CARPET_BLUE("carpet", "blue", 171, 11, "blocks/carpet_blue.png", 0xff2e388d, false),
- B_171_12_CARPET_BROWN("carpet", "brown", 171, 12, "blocks/carpet_brown.png", 0xff4f321f, false),
- B_171_13_CARPET_GREEN("carpet", "green", 171, 13, "blocks/carpet_green.png", 0xff35461b, false),
- B_171_14_CARPET_RED("carpet", "red", 171, 14, "blocks/carpet_red.png", 0xff963430, false),
- B_171_15_CARPET_BLACK("carpet", "black", 171, 15, "blocks/carpet_black.png", 0xff191616, false),
- B_172_0_HARDENED_CLAY("hardened_clay", null, 172, 0, "blocks/hardened_clay.png", 0xff5d3828, false),
- B_173_0_COAL_BLOCK("coal_block", null, 173, 0, "blocks/coal_block.png", 0xff111111, false),
- B_174_0_PACKED_ICE("packed_ice", null, 174, 0, "blocks/packed_ice.png", 0xff97b3e4, false),
- B_175_0_DOUBLE_PLANT_SUNFLOWER("double_plant", "sunflower", 175, 0, "blocks/double_plant_sunflower.png", 0xb4d28219, false),
- B_175_1_DOUBLE_PLANT_SYRINGA("double_plant", "syringa", 175, 1, "blocks/double_plant_syringa.png", 0xb4dec0e2, false),
- B_175_2_DOUBLE_PLANT_GRASS("double_plant", "grass", 175, 2, "blocks/double_plant_grass.png", 0xb4334e2c, false),
- B_175_3_DOUBLE_PLANT_FERN("double_plant", "fern", 175, 3, "blocks/double_plant_fern.png", 0xb43d5d34, false),
- B_175_4_DOUBLE_PLANT_ROSE("double_plant", "rose", 175, 4, "blocks/double_plant_rose.png", 0xb4d10609, false),
- B_175_5_DOUBLE_PLANT_PAEONIA("double_plant", "paeonia", 175, 5, "blocks/double_plant_paeonia.png", 0xb4d6c1df, false),
-
- B_176_0_BANNER("banner", null, 176, 0, "blocks/double_plant_paeonia.png", 0xff9aa1a1, false),
- B_176_8_BANNER("banner", null, 176, 8, "blocks/double_plant_paeonia.png", 0xff9aa1a1, false),
- B_176_12_BANNER("banner", null, 176, 12, "blocks/double_plant_paeonia.png", 0xff9aa1a1, false),
-
- B_178_0_DAYLIGHT_DETECTOR_INVERTED("daylight_detector_inverted", null, 178, 0, "blocks/daylight_detector_inverted.png", 0xffd8c9b5, false),
- B_179_0_RED_SANDSTONE_DEFAULT("red_sandstone", "default", 179, 0, "blocks/red_sandstone_default.png", 0xffaa561e, false),
- B_179_1_RED_SANDSTONE_CHISELED("red_sandstone", "chiseled", 179, 1, "blocks/red_sandstone_chiseled.png", 0xffa8551e, false),
- B_179_2_RED_SANDSTONE_SMOOTH("red_sandstone", "smooth", 179, 2, "blocks/red_sandstone_smooth.png", 0xffcc5e16, false),
- B_180_0_RED_SANDSTONE_STAIRS("red_sandstone_stairs", null, 180, 0, "blocks/red_sandstone_stairs.png", 0xffaa561e, false),
- B_181_0_DOUBLE_STONE_SLAB2_RED_SANDSTONE("double_stone_slab2", "red_sandstone", 181, 0, "blocks/double_stone_slab2_red_sandstone.png", 0xffaa561e, false),
- B_181_1_DOUBLE_STONE_SLAB2_PURPUR("double_stone_slab2", "purpur", 181, 1, "blocks/double_stone_slab2_purpur.png", 0xffa072a0, false),
- B_182_0_STONE_SLAB2_RED_SANDSTONE("stone_slab2", "red_sandstone", 182, 0, "blocks/stone_slab2_red_sandstone.png", 0xffaa561e, false),
- B_182_1_STONE_SLAB2_PURPUR("stone_slab2", "purpur", 182, 1, "blocks/stone_slab2_purpur.png", 0xffa072a0, false),
- B_183_0_SPRUCE_FENCE_GATE("spruce_fence_gate", null, 183, 0, "blocks/spruce_fence_gate.png", 0x00000000, false),
- B_184_0_BIRCH_FENCE_GATE("birch_fence_gate", null, 184, 0, "blocks/birch_fence_gate.png", 0x00000000, false),
- B_185_0_JUNGLE_FENCE_GATE("jungle_fence_gate", null, 185, 0, "blocks/jungle_fence_gate.png", 0x00000000, false),
- B_186_0_DARK_OAK_FENCE_GATE("dark_oak_fence_gate", null, 186, 0, "blocks/dark_oak_fence_gate.png", 0x00000000, false),
- B_187_0_ACACIA_FENCE_GATE("acacia_fence_gate", null, 187, 0, "blocks/acacia_fence_gate.png", 0x00000000, false),
- B_193_0_SPRUCE_DOOR("spruce_door", null, 193, 0, "blocks/spruce_door.png", 0x00000000, false),
- B_194_0_BIRCH_DOOR("birch_door", null, 194, 0, "blocks/birch_door.png", 0x00000000, false),
- B_195_0_JUNGLE_DOOR("jungle_door", null, 195, 0, "blocks/jungle_door.png", 0x00000000, false),
- B_196_0_ACACIA_DOOR("acacia_door", null, 196, 0, "blocks/acacia_door.png", 0x00000000, false),
- B_197_0_DARK_OAK_DOOR("dark_oak_door", null, 197, 0, "blocks/dark_oak_door.png", 0x00000000, false),
- B_198_0_GRASS_PATH("grass_path", null, 198, 0, "blocks/grass_path.png", 0x46a0a0a0, false),
- B_199_0_FRAME("frame", null, 199, 0, "blocks/frame.png", 0xa04f3e4f, false),
- B_200_0_CHORUS_FLOWER("chorus_flower", null, 200, 0, "blocks/chorus_flower.png", 0xa0c3b6c8, false),
- B_201_0_PURPUR_BLOCK_DEFAULT("purpur_block", "default", 201, 0, "blocks/purpur_block_default.png", 0xffa577a5, false),
- B_201_1_PURPUR_BLOCK_CHISELED("purpur_block", "chiseled", 201, 1, "blocks/purpur_block_chiseled.png", 0xffa570a5, false),
- B_201_2_PURPUR_BLOCK_LINES("purpur_block", "lines", 201, 2, "blocks/purpur_block_lines.png", 0xffa070a5, false),
- B_201_3_PURPUR_BLOCK_DEFAULT("purpur_block", "default", 201, 3, "blocks/purpur_block_default.png", 0xffa577a5, false),
- B_202_0_COLORED_TORCH_DEFAULT("colored_torch_rg", "default", 202, 0, "blocks/redstone_torch_on.png", 0xffa070a5, false),
- B_202_9_COLORED_TORCH_DEFAULT("colored_torch_rg", "default", 202, 9, "blocks/redstone_torch_on.png", 0xffa070a5, false),
- B_202_13_COLORED_TORCH_DEFAULT("colored_torch_rg", "default", 202, 13, "blocks/redstone_torch_on.png", 0xffa070a5, false),
- B_203_0_PURPUR_STAIRS("purpur_stairs", null, 203, 0, "blocks/purpur_stairs.png", 0xffa577a5, false),
- B_206_0_END_BRICKS("end_bricks", null, 206, 0, "blocks/end_bricks.png", 0xffe7f2af, false),
- B_208_0_END_ROD("end_rod", null, 208, 0, "blocks/end_rod.png", 0xff6e6e6e, true),
- B_209_0_END_GATEWAY("end_gateway", null, 209, 0, "blocks/end_gateway.png", 0xff171c27, false),
-
- B_205_0_SHULKERBOX("shulker_box", null, 205, 0, "blocks/observer.png", 0xffffffff, false),
- B_218_0_SHULKERBOX_WHITE("shulker_box", "white", 218, 0, "blocks/observer.png", 0xffffffff, false),
- B_218_1_SHULKERBOX_ORANGE("shulker_box", "orange", 218, 1, "blocks/observer.png", 0xffffd030, false),
- B_218_2_SHULKERBOX_MAGENTA("shulker_box", "magenta", 218, 2, "blocks/observer.png", 0xffef007f, false),
- B_218_3_SHULKERBOX_LIGHT_BLUE("shulker_box", "light_blue", 218, 3, "blocks/observer.png", 0xff5588ff, false),
- B_218_4_SHULKERBOX_YELLOW("shulker_box", "yellow", 218, 4, "blocks/observer.png", 0xffffff40, false),
- B_218_5_SHULKERBOX_LIME("shulker_box", "lime", 218, 5, "blocks/observer.png", 0xff0db60e, false),
- B_218_6_SHULKERBOX_PINK("shulker_box", "pink", 218, 6, "blocks/observer.png", 0xffff6076, false),
- B_218_7_SHULKERBOX_GRAY("shulker_box", "gray", 218, 7, "blocks/observer.png", 0xff565656, false),
- B_218_8_SHULKERBOX_SILVER("shulker_box", "silver", 218, 8, "blocks/observer.png", 0xffa6a6a6, false),
- B_218_9_SHULKERBOX_CYAN("shulker_box", "cyan", 218, 9, "blocks/observer.png", 0xff0d5656, false),
- B_218_10_SHULKERBOX_PURPLE("shulker_box", "purple", 218, 10, "blocks/observer.png", 0xff560d56, false),
- B_218_11_SHULKERBOX_BLUE("shulker_box", "blue", 218, 11, "blocks/observer.png", 0xff0d0e56, false),
- B_218_12_SHULKERBOX_BROWN("shulker_box", "brown", 218, 12, "blocks/observer.png", 0xff804530, false),
- B_218_13_SHULKERBOX_GREEN("shulker_box", "green", 218, 13, "blocks/observer.png", 0xff0d560e, false),
- B_218_14_SHULKERBOX_RED("shulker_box", "red", 218, 14, "blocks/observer.png", 0xffff2020, false),
- B_218_15_SHULKERBOX_BLACK("shulker_box", "black", 218, 15, "blocks/observer.png", 0xff000000, false),
-
-
- B_240_0_CHORUS_PLANT("chorus_plant", null, 240, 0, "blocks/chorus_plant.png", 0xaa3d6e86, false),
- B_241_0_STAINED_GLASS_WHITE("stained_glass", "white", 241, 0, "blocks/stained_glass_white.png", 0x50836f64, false),
- B_241_1_STAINED_GLASS_ORANGE("stained_glass", "orange", 241, 1, "blocks/stained_glass_orange.png", 0x509d5021, false),
- B_241_2_STAINED_GLASS_MAGENTA("stained_glass", "magenta", 241, 2, "blocks/stained_glass_magenta.png", 0x50915369, false),
- B_241_3_STAINED_GLASS_LIGHT_BLUE("stained_glass", "light_blue", 241, 3, "blocks/stained_glass_light_blue.png", 0x50706b87, false),
- B_241_4_STAINED_GLASS_YELLOW("stained_glass", "yellow", 241, 4, "blocks/stained_glass_yellow.png", 0x50b5801f, false),
- B_241_5_STAINED_GLASS_LIME("stained_glass", "lime", 241, 5, "blocks/stained_glass_lime.png", 0x50617030, false),
- B_241_6_STAINED_GLASS_PINK("stained_glass", "pink", 241, 6, "blocks/stained_glass_pink.png", 0x509c4848, false),
- B_241_7_STAINED_GLASS_GRAY("stained_glass", "gray", 241, 7, "blocks/stained_glass_gray.png", 0x50392721, false),
- B_241_8_STAINED_GLASS_SILVER("stained_glass", "silver", 241, 8, "blocks/stained_glass_silver.png", 0x5081655b, false),
- B_241_9_STAINED_GLASS_CYAN("stained_glass", "cyan", 241, 9, "blocks/stained_glass_cyan.png", 0x50565959, false),
- B_241_10_STAINED_GLASS_PURPLE("stained_glass", "purple", 241, 10, "blocks/stained_glass_purple.png", 0x50744555, false),
- B_241_11_STAINED_GLASS_BLUE("stained_glass", "blue", 241, 11, "blocks/stained_glass_blue.png", 0x50463857, false),
- B_241_12_STAINED_GLASS_BROWN("stained_glass", "brown", 241, 12, "blocks/stained_glass_brown.png", 0x50492e1f, false),
- B_241_13_STAINED_GLASS_GREEN("stained_glass", "green", 241, 13, "blocks/stained_glass_green.png", 0x50484f26, false),
- B_241_14_STAINED_GLASS_RED("stained_glass", "red", 241, 14, "blocks/stained_glass_red.png", 0x50ff382b, false),
- B_241_15_STAINED_GLASS_BLACK("stained_glass", "black", 241, 15, "blocks/stained_glass_black.png", 0x5021120d, false),
- B_243_0_PODZOL("podzol", null, 243, 0, "blocks/podzol.png", 0xff533a1b, true),
- B_244_0_BEETROOT("beetroot", null, 244, 0, "blocks/beetroot.png", 0x0901ab10, false),
- B_245_0_STONECUTTER("stonecutter", null, 245, 0, "blocks/stonecutter.png", 0xff515151, false),
- B_246_0_GLOWINGOBSIDIAN("glowingobsidian", null, 246, 0, "blocks/glowingobsidian.png", 0xff17060a, false),
- B_247_0_NETHERREACTOR_DEFAULT("netherreactor", "default", 247, 0, "blocks/netherreactor_default.png", 0xffd2d200, false),
- B_247_1_NETHERREACTOR_ACTIVE("netherreactor", "active", 247, 1, "blocks/netherreactor_active.png", 0xff3d6e86, false),
- B_247_2_NETHERREACTOR_COOLED("netherreactor", "cooled", 247, 2, "blocks/netherreactor_cooled.png", 0xff3d6e86, false),
- B_248_0_INFO_UPDATE("info_update", null, 248, 0, "blocks/info_update.png", 0xff2f3218, false),
- B_249_0_INFO_UPDATE2("info_update2", null, 249, 0, "blocks/info_update2.png", 0xff2f3218, false),
- B_250_0_MOVINGBLOCK("movingBlock", null, 250, 0, "blocks/movingBlock.png", 0, false),
- B_251_0_OBSERVER("observer", null, 251, 0, "blocks/observer.png", 0xff3d6e86, false),
-
-
-
- B_236_0_CONCRETE_WHITE("concrete", "orange", 236, 0, "blocks/observer.png", 0xffffffff, false),
- B_236_1_CONCRETE_ORANGE("concrete", "orange", 236, 1, "blocks/observer.png", 0xffffd030, false),
- B_236_2_CONCRETE_MAGENTA("concrete", "magenta", 236, 2, "blocks/observer.png", 0xffef007f, false),
- B_236_3_CONCRETE_LIGHT_BLUE("concrete", "light_blue", 236, 3, "blocks/observer.png", 0xff5588ff, false),
- B_236_4_CONCRETE_YELLOW("concrete", "yellow", 236, 4, "blocks/observer.png", 0xffffff40, false),
- B_236_5_CONCRETE_LIME("concrete", "lime", 236, 5, "blocks/observer.png", 0xff0db60e, false),
- B_236_6_CONCRETE_PINK("concrete", "pink", 236, 6, "blocks/observer.png", 0xffff6076, false),
- B_236_7_CONCRETE_GRAY("concrete", "gray", 236, 7, "blocks/observer.png", 0xff565656, false),
- B_236_8_CONCRETE_SILVER("concrete", "silver", 236, 8, "blocks/observer.png", 0xffa6a6a6, false),
- B_236_9_CONCRETE_CYAN("concrete", "cyan", 236, 9, "blocks/observer.png", 0xff0d5656, false),
- B_236_10_CONCRETE_PURPLE("concrete", "purple", 236, 10, "blocks/observer.png", 0xff560d56, false),
- B_236_11_CONCRETE_BLUE("concrete", "blue", 236, 11, "blocks/observer.png", 0xff0d0e56, false),
- B_236_12_CONCRETE_BROWN("concrete", "brown", 236, 12, "blocks/observer.png", 0xff804530, false),
- B_236_13_CONCRETE_GREEN("concrete", "green", 236, 13, "blocks/observer.png", 0xff0d560e, false),
- B_236_14_CONCRETE_RED("concrete", "red", 236, 14, "blocks/observer.png", 0xffff2020, false),
- B_236_15_CONCRETE_BLACK("concrete", "black", 236, 15, "blocks/observer.png", 0xff000000, false),
-
-
- B_237_0_CONCRETE_POWDER_WHITE("concrete_powder", "orange", 237, 0, "blocks/observer.png", 0xffffffff, false),
- B_237_1_CONCRETE_POWDER_ORANGE("concrete_powder", "orange", 237, 1, "blocks/observer.png", 0xffffd030, false),
- B_237_2_CONCRETE_POWDER_MAGENTA("concrete_powder", "magenta", 237, 2, "blocks/observer.png", 0xffef007f, false),
- B_237_3_CONCRETE_POWDER_LIGHT_BLUE("concrete_powder", "light_blue", 237, 3, "blocks/observer.png", 0xff5588ff, false),
- B_237_4_CONCRETE_POWDER_YELLOW("concrete_powder", "yellow", 237, 4, "blocks/observer.png", 0xffffff40, false),
- B_237_5_CONCRETE_POWDER_LIME("concrete_powder", "lime", 237, 5, "blocks/observer.png", 0xff0db60e, false),
- B_237_6_CONCRETE_POWDER_PINK("concrete_powder", "pink", 237, 6, "blocks/observer.png", 0xffff6076, false),
- B_237_7_CONCRETE_POWDER_GRAY("concrete_powder", "gray", 237, 7, "blocks/observer.png", 0xff565656, false),
- B_237_8_CONCRETE_POWDER_SILVER("concrete_powder", "silver", 237, 8, "blocks/observer.png", 0xffa6a6a6, false),
- B_237_9_CONCRETE_POWDER_CYAN("concrete_powder", "cyan", 237, 9, "blocks/observer.png", 0xff0d5656, false),
- B_237_10_CONCRETE_POWDER_PURPLE("concrete_powder", "purple", 237, 10, "blocks/observer.png", 0xff560d56, false),
- B_237_11_CONCRETE_POWDER_BLUE("concrete_powder", "blue", 237, 11, "blocks/observer.png", 0xff0d0e56, false),
- B_237_12_CONCRETE_POWDER_BROWN("concrete_powder", "brown", 237, 12, "blocks/observer.png", 0xff804530, false),
- B_237_13_CONCRETE_POWDER_GREEN("concrete_powder", "green", 237, 13, "blocks/observer.png", 0xff0d560e, false),
- B_237_14_CONCRETE_POWDER_RED("concrete_powder", "brown", 237, 14, "blocks/observer.png", 0xffff2020, false),
- B_237_15_CONCRETE_POWDER_BLACK("concrete_powder", "black", 237, 15, "blocks/observer.png", 0xff000000, false),
-
-
- B_219_2_GLAZED_TERRACOTTA_PURPLE("glazed_terracotta", "purple", 219, 2, "blocks/observer.png", 0xff762d76, false),
- B_219_3_GLAZED_TERRACOTTA_PURPLE("glazed_terracotta", "purple", 219, 3, "blocks/observer.png", 0xff762d76, false),
- B_219_4_GLAZED_TERRACOTTA_PURPLE("glazed_terracotta", "purple", 219, 4, "blocks/observer.png", 0xff762d76, false),
- B_219_5_GLAZED_TERRACOTTA_PURPLE("glazed_terracotta", "purple", 219, 5, "blocks/observer.png", 0xff762d76, false),
- B_220_2_GLAZED_TERRACOTTA_WHITE("glazed_terracotta", "white", 220, 2, "blocks/observer.png", 0xffffffff, false),
- B_220_3_GLAZED_TERRACOTTA_WHITE("glazed_terracotta", "white", 220, 3, "blocks/observer.png", 0xffffffff, false),
- B_220_4_GLAZED_TERRACOTTA_WHITE("glazed_terracotta", "white", 220, 4, "blocks/observer.png", 0xffffffff, false),
- B_220_5_GLAZED_TERRACOTTA_WHITE("glazed_terracotta", "white", 220, 5, "blocks/observer.png", 0xffffffff, false),
- B_221_2_GLAZED_TERRACOTTA_ORANGE("glazed_terracotta", "orange", 221, 2, "blocks/observer.png", 0xffff8030, false),
- B_221_3_GLAZED_TERRACOTTA_ORANGE("glazed_terracotta", "orange", 221, 3, "blocks/observer.png", 0xffff8030, false),
- B_221_4_GLAZED_TERRACOTTA_ORANGE("glazed_terracotta", "orange", 221, 4, "blocks/observer.png", 0xffff8030, false),
- B_221_5_GLAZED_TERRACOTTA_ORANGE("glazed_terracotta", "orange", 221, 5, "blocks/observer.png", 0xffff8030, false),
- B_222_2_GLAZED_TERRACOTTA_LIGHT_MAGENTA("glazed_terracotta", "magenta", 222, 2, "blocks/observer.png", 0xffff108f, false),
- B_222_3_GLAZED_TERRACOTTA_LIGHT_MAGENTA("glazed_terracotta", "magenta", 222, 3, "blocks/observer.png", 0xffff108f, false),
- B_222_4_GLAZED_TERRACOTTA_LIGHT_MAGENTA("glazed_terracotta", "magenta", 222, 4, "blocks/observer.png", 0xffff108f, false),
- B_222_5_GLAZED_TERRACOTTA_LIGHT_MAGENTA("glazed_terracotta", "magenta", 222, 5, "blocks/observer.png", 0xffff108f, false),
- B_223_2_GLAZED_TERRACOTTA_LIGHT_BLUE("glazed_terracotta", "light_blue", 223, 2, "blocks/observer.png", 0xff75a8ff, false),
- B_223_3_GLAZED_TERRACOTTA_LIGHT_BLUE("glazed_terracotta", "light_blue", 223, 3, "blocks/observer.png", 0xff75a8ff, false),
- B_223_4_GLAZED_TERRACOTTA_LIGHT_BLUE("glazed_terracotta", "light_blue", 223, 4, "blocks/observer.png", 0xff75a8ff, false),
- B_223_5_GLAZED_TERRACOTTA_LIGHT_BLUE("glazed_terracotta", "light_blue", 223, 5, "blocks/observer.png", 0xff75a8ff, false),
- B_224_0_GLAZED_TERRACOTTA_YELLOW("glazed_terracotta", "yellow", 224, 0, "blocks/observer.png", 0xffffff60, false),
- B_224_2_GLAZED_TERRACOTTA_YELLOW("glazed_terracotta", "yellow", 224, 2, "blocks/observer.png", 0xffffff60, false),
- B_224_3_GLAZED_TERRACOTTA_YELLOW("glazed_terracotta", "yellow", 224, 3, "blocks/observer.png", 0xffffff60, false),
- B_224_4_GLAZED_TERRACOTTA_YELLOW("glazed_terracotta", "yellow", 224, 4, "blocks/observer.png", 0xffffff60, false),
- B_224_5_GLAZED_TERRACOTTA_YELLOW("glazed_terracotta", "yellow", 224, 5, "blocks/observer.png", 0xffffff60, false),
- B_225_0_GLAZED_TERRACOTTA_LIME("glazed_terracotta", "lime", 225, 0, "blocks/observer.png", 0xff2dd62e, false),
- B_225_2_GLAZED_TERRACOTTA_LIME("glazed_terracotta", "lime", 225, 2, "blocks/observer.png", 0xff2dd62e, false),
- B_225_3_GLAZED_TERRACOTTA_LIME("glazed_terracotta", "lime", 225, 3, "blocks/observer.png", 0xff2dd62e, false),
- B_225_4_GLAZED_TERRACOTTA_LIME("glazed_terracotta", "lime", 225, 4, "blocks/observer.png", 0xff2dd62e, false),
- B_225_5_GLAZED_TERRACOTTA_LIME("glazed_terracotta", "lime", 225, 5, "blocks/observer.png", 0xff2dd62e, false),
- B_226_0_GLAZED_TERRACOTTA_PINK("glazed_terracotta", "pink", 226, 0, "blocks/observer.png", 0xffff8096, false),
- B_226_2_GLAZED_TERRACOTTA_PINK("glazed_terracotta", "pink", 226, 2, "blocks/observer.png", 0xffff8096, false),
- B_226_3_GLAZED_TERRACOTTA_PINK("glazed_terracotta", "pink", 226, 3, "blocks/observer.png", 0xffff8096, false),
- B_226_4_GLAZED_TERRACOTTA_PINK("glazed_terracotta", "pink", 226, 4, "blocks/observer.png", 0xffff8096, false),
- B_226_5_GLAZED_TERRACOTTA_PINK("glazed_terracotta", "pink", 226, 5, "blocks/observer.png", 0xffff8096, false),
- B_226_6_GLAZED_TERRACOTTA_PINK("glazed_terracotta", "pink", 226, 6, "blocks/observer.png", 0xffff8096, false),
- B_226_7_GLAZED_TERRACOTTA_PINK("glazed_terracotta", "pink", 226, 7, "blocks/observer.png", 0xffff8096, false),
- B_227_2_GLAZED_TERRACOTTA_GRAY("glazed_terracotta", "gray", 227, 2, "blocks/observer.png", 0xff767676, false),
- B_227_3_GLAZED_TERRACOTTA_GRAY("glazed_terracotta", "gray", 227, 3, "blocks/observer.png", 0xff767676, false),
- B_227_4_GLAZED_TERRACOTTA_GRAY("glazed_terracotta", "gray", 227, 4, "blocks/observer.png", 0xff767676, false),
- B_227_5_GLAZED_TERRACOTTA_GRAY("glazed_terracotta", "gray", 227, 5, "blocks/observer.png", 0xff767676, false),
- B_228_2_GLAZED_TERRACOTTA_LIGHT_GRAY("glazed_terracotta", "light_gray", 228, 2, "blocks/observer.png", 0xffc6c6c6, false),
- B_228_3_GLAZED_TERRACOTTA_LIGHT_GRAY("glazed_terracotta", "light_gray", 228, 3, "blocks/observer.png", 0xffc6c6c6, false),
- B_228_4_GLAZED_TERRACOTTA_LIGHT_GRAY("glazed_terracotta", "light_gray", 228, 4, "blocks/observer.png", 0xffc6c6c6, false),
- B_228_5_GLAZED_TERRACOTTA_LIGHT_GRAY("glazed_terracotta", "light_gray", 228, 5, "blocks/observer.png", 0xffc6c6c6, false),
- B_229_2_GLAZED_TERRACOTTA_CYAN("glazed_terracotta", "cyan", 229, 2, "blocks/observer.png", 0xff2d7676, false),
- B_229_3_GLAZED_TERRACOTTA_CYAN("glazed_terracotta", "cyan", 229, 3, "blocks/observer.png", 0xff2d7676, false),
- B_229_4_GLAZED_TERRACOTTA_CYAN("glazed_terracotta", "cyan", 229, 4, "blocks/observer.png", 0xff2d7676, false),
- B_229_5_GLAZED_TERRACOTTA_CYAN("glazed_terracotta", "cyan", 229, 5, "blocks/observer.png", 0xff2d7676, false),
- B_231_2_GLAZED_TERRACOTTA_BLUE("glazed_terracotta", "blue", 231, 2, "blocks/observer.png", 0xff2d2e76, false),
- B_231_3_GLAZED_TERRACOTTA_BLUE("glazed_terracotta", "blue", 231, 3, "blocks/observer.png", 0xff2d2e76, false),
- B_231_4_GLAZED_TERRACOTTA_BLUE("glazed_terracotta", "blue", 231, 4, "blocks/observer.png", 0xff2d2e76, false),
- B_231_5_GLAZED_TERRACOTTA_BLUE("glazed_terracotta", "blue", 231, 5, "blocks/observer.png", 0xff2d2e76, false),
- B_232_2_GLAZED_TERRACOTTA_BROWN("glazed_terracotta", "brown", 232, 2, "blocks/observer.png", 0xffa06550, false),
- B_232_3_GLAZED_TERRACOTTA_BROWN("glazed_terracotta", "brown", 232, 3, "blocks/observer.png", 0xffa06550, false),
- B_232_4_GLAZED_TERRACOTTA_BROWN("glazed_terracotta", "brown", 232, 4, "blocks/observer.png", 0xffa06550, false),
- B_232_5_GLAZED_TERRACOTTA_BROWN("glazed_terracotta", "brown", 232, 5, "blocks/observer.png", 0xffa06550, false),
- B_233_0_GLAZED_TERRACOTTA_GREEN("glazed_terracotta", "green", 233, 0, "blocks/observer.png", 0xff2d762e, false),
- B_233_2_GLAZED_TERRACOTTA_GREEN("glazed_terracotta", "green", 233, 2, "blocks/observer.png", 0xff2d762e, false),
- B_233_3_GLAZED_TERRACOTTA_GREEN("glazed_terracotta", "green", 233, 3, "blocks/observer.png", 0xff2d762e, false),
- B_233_4_GLAZED_TERRACOTTA_GREEN("glazed_terracotta", "green", 233, 4, "blocks/observer.png", 0xff2d762e, false),
- B_233_5_GLAZED_TERRACOTTA_GREEN("glazed_terracotta", "green", 233, 5, "blocks/observer.png", 0xff2d762e, false),
- B_234_2_GLAZED_TERRACOTTA_RED("glazed_terracotta", "red", 234, 2, "blocks/observer.png", 0xffff3030, false),
- B_234_3_GLAZED_TERRACOTTA_RED("glazed_terracotta", "red", 234, 3, "blocks/observer.png", 0xffff3030, false),
- B_234_4_GLAZED_TERRACOTTA_RED("glazed_terracotta", "red", 234, 4, "blocks/observer.png", 0xffff3030, false),
- B_234_5_GLAZED_TERRACOTTA_RED("glazed_terracotta", "red", 234, 5, "blocks/observer.png", 0xffff3030, false),
- B_235_2_GLAZED_TERRACOTTA_BLACK("glazed_terracotta", "black", 235, 2, "blocks/observer.png", 0xff050505, false),
- B_235_3_GLAZED_TERRACOTTA_BLACK("glazed_terracotta", "black", 235, 3, "blocks/observer.png", 0xff050505, false),
- B_235_4_GLAZED_TERRACOTTA_BLACK("glazed_terracotta", "black", 235, 4, "blocks/observer.png", 0xff050505, false),
- B_235_5_GLAZED_TERRACOTTA_BLACK("glazed_terracotta", "black", 235, 5, "blocks/observer.png", 0xff050505, false),
-
- B_213_0_MAGMA_BLOCK("magma_block", "default", 213, 0, "blocks/quartz_block_default.png", 0xffc45a12, false),
-
- B_214_0_NETHERWART_BLOCK("netherwart_block", "default", 214, 0, "blocks/quartz_block_default.png", 0xffbf2030, false),
-
- B_215_0_RED_NETHER_BRICK("red_nether_brick", "default", 215, 0, "blocks/quartz_block_default.png", 0xff7f1020, false),
-
- B_216_0_BONE("quartz_block", "default", 216, 0, "blocks/quartz_block_default.png", 0xffefe5d2, false),
-
- B_255_0_RESERVED6("reserved6", null, 255, 0, "blocks/reserved6.png", 0xff19171a, false),
- B_210_0_ALLOW("allow", null, 210, 0, "blocks/allow.png", 0xff634aba, false),
- B_211_0_DENY("deny", null, 211, 0, "blocks/deny.png", 0xff6ca28a, false),
- B_212_0_BORDER_BLOCK("border_block", null, 212, 0, "blocks/border_block.png", 0xff76a7fc, false),
- B_230_0_CHALKBOARD("chalkboard", null, 230, 0, "blocks/chalkboard.png", 0xff3d6e86, false),
- B_242_0_CAMERA("camera", null, 242, 0, "blocks/camera.png", 0xff3d6e86, false),
-
-
-
-
-
-
- /*
- * ==============================
- * Items
- * ==============================
- */
-
- I_256_0_IRON_SHOVEL("iron_shovel", null, 256, 0, "items/iron_shovel.png"),
- I_257_0_IRON_PICKAXE("iron_pickaxe", null, 257, 0, "items/iron_pickaxe.png"),
- I_258_0_IRON_AXE("iron_axe", null, 258, 0, "items/iron_axe.png"),
- I_259_0_FLINT_AND_STEEL("flint_and_steel", null, 259, 0, "items/flint_and_steel.png"),
- I_260_0_APPLE("apple", null, 260, 0, "items/apple.png"),
- I_261_0_BOW("bow", null, 261, 0, "items/bow.png"),
- I_262_0_ARROW("arrow", null, 262, 0, "items/arrow.png"),
- I_263_0_COAL_COAL("coal", "coal", 263, 0, "items/coal_coal.png"),
- I_263_1_COAL_CHARCOAL("coal", "charcoal", 263, 1, "items/coal_charcoal.png"),
- I_264_0_DIAMOND("diamond", null, 264, 0, "items/diamond.png"),
- I_265_0_IRON_INGOT("iron_ingot", null, 265, 0, "items/iron_ingot.png"),
- I_266_0_GOLD_INGOT("gold_ingot", null, 266, 0, "items/gold_ingot.png"),
- I_267_0_IRON_SWORD("iron_sword", null, 267, 0, "items/iron_sword.png"),
- I_268_0_WOODEN_SWORD("wooden_sword", null, 268, 0, "items/wooden_sword.png"),
- I_269_0_WOODEN_SHOVEL("wooden_shovel", null, 269, 0, "items/wooden_shovel.png"),
- I_270_0_WOODEN_PICKAXE("wooden_pickaxe", null, 270, 0, "items/wooden_pickaxe.png"),
- I_271_0_WOODEN_AXE("wooden_axe", null, 271, 0, "items/wooden_axe.png"),
- I_272_0_STONE_SWORD("stone_sword", null, 272, 0, "items/stone_sword.png"),
- I_273_0_STONE_SHOVEL("stone_shovel", null, 273, 0, "items/stone_shovel.png"),
- I_274_0_STONE_PICKAXE("stone_pickaxe", null, 274, 0, "items/stone_pickaxe.png"),
- I_275_0_STONE_AXE("stone_axe", null, 275, 0, "items/stone_axe.png"),
- I_276_0_DIAMOND_SWORD("diamond_sword", null, 276, 0, "items/diamond_sword.png"),
- I_277_0_DIAMOND_SHOVEL("diamond_shovel", null, 277, 0, "items/diamond_shovel.png"),
- I_278_0_DIAMOND_PICKAXE("diamond_pickaxe", null, 278, 0, "items/diamond_pickaxe.png"),
- I_279_0_DIAMOND_AXE("diamond_axe", null, 279, 0, "items/diamond_axe.png"),
- I_280_0_STICK("stick", null, 280, 0, "items/stick.png"),
- I_281_0_BOWL("bowl", null, 281, 0, "items/bowl.png"),
- I_282_0_MUSHROOM_STEW("mushroom_stew", null, 282, 0, "items/mushroom_stew.png"),
- I_283_0_GOLDEN_SWORD("golden_sword", null, 283, 0, "items/golden_sword.png"),
- I_284_0_GOLDEN_SHOVEL("golden_shovel", null, 284, 0, "items/golden_shovel.png"),
- I_285_0_GOLDEN_PICKAXE("golden_pickaxe", null, 285, 0, "items/golden_pickaxe.png"),
- I_286_0_GOLDEN_AXE("golden_axe", null, 286, 0, "items/golden_axe.png"),
- I_287_0_STRING("string", null, 287, 0, "items/string.png"),
- I_288_0_FEATHER("feather", null, 288, 0, "items/feather.png"),
- I_289_0_GUNPOWDER("gunpowder", null, 289, 0, "items/gunpowder.png"),
- I_290_0_WOODEN_HOE("wooden_hoe", null, 290, 0, "items/wooden_hoe.png"),
- I_291_0_STONE_HOE("stone_hoe", null, 291, 0, "items/stone_hoe.png"),
- I_292_0_IRON_HOE("iron_hoe", null, 292, 0, "items/iron_hoe.png"),
- I_293_0_DIAMOND_HOE("diamond_hoe", null, 293, 0, "items/diamond_hoe.png"),
- I_294_0_GOLDEN_HOE("golden_hoe", null, 294, 0, "items/golden_hoe.png"),
- I_295_0_WHEAT_SEEDS("wheat_seeds", null, 295, 0, "items/wheat_seeds.png"),
- I_296_0_WHEAT("wheat", null, 296, 0, "items/wheat.png"),
- I_297_0_BREAD("bread", null, 297, 0, "items/bread.png"),
- I_298_0_LEATHER_HELMET("leather_helmet", null, 298, 0, "items/leather_helmet.png"),
- I_299_0_LEATHER_CHESTPLATE("leather_chestplate", null, 299, 0, "items/leather_chestplate.png"),
- I_300_0_LEATHER_LEGGINGS("leather_leggings", null, 300, 0, "items/leather_leggings.png"),
- I_301_0_LEATHER_BOOTS("leather_boots", null, 301, 0, "items/leather_boots.png"),
- I_302_0_CHAINMAIL_HELMET("chainmail_helmet", null, 302, 0, "items/chainmail_helmet.png"),
- I_303_0_CHAINMAIL_CHESTPLATE("chainmail_chestplate", null, 303, 0, "items/chainmail_chestplate.png"),
- I_304_0_CHAINMAIL_LEGGINGS("chainmail_leggings", null, 304, 0, "items/chainmail_leggings.png"),
- I_305_0_CHAINMAIL_BOOTS("chainmail_boots", null, 305, 0, "items/chainmail_boots.png"),
- I_306_0_IRON_HELMET("iron_helmet", null, 306, 0, "items/iron_helmet.png"),
- I_307_0_IRON_CHESTPLATE("iron_chestplate", null, 307, 0, "items/iron_chestplate.png"),
- I_308_0_IRON_LEGGINGS("iron_leggings", null, 308, 0, "items/iron_leggings.png"),
- I_309_0_IRON_BOOTS("iron_boots", null, 309, 0, "items/iron_boots.png"),
- I_310_0_DIAMOND_HELMET("diamond_helmet", null, 310, 0, "items/diamond_helmet.png"),
- I_311_0_DIAMOND_CHESTPLATE("diamond_chestplate", null, 311, 0, "items/diamond_chestplate.png"),
- I_312_0_DIAMOND_LEGGINGS("diamond_leggings", null, 312, 0, "items/diamond_leggings.png"),
- I_313_0_DIAMOND_BOOTS("diamond_boots", null, 313, 0, "items/diamond_boots.png"),
- I_314_0_GOLDEN_HELMET("golden_helmet", null, 314, 0, "items/golden_helmet.png"),
- I_315_0_GOLDEN_CHESTPLATE("golden_chestplate", null, 315, 0, "items/golden_chestplate.png"),
- I_316_0_GOLDEN_LEGGINGS("golden_leggings", null, 316, 0, "items/golden_leggings.png"),
- I_317_0_GOLDEN_BOOTS("golden_boots", null, 317, 0, "items/golden_boots.png"),
- I_318_0_FLINT("flint", null, 318, 0, "items/flint.png"),
- I_319_0_PORKCHOP("porkchop", null, 319, 0, "items/porkchop.png"),
- I_320_0_COOKED_PORKCHOP("cooked_porkchop", null, 320, 0, "items/cooked_porkchop.png"),
- I_321_0_PAINTING("painting", null, 321, 0, "items/painting.png"),
- I_322_0_GOLDEN_APPLE("golden_apple", null, 322, 0, "items/golden_apple.png"),
- I_323_0_SIGN("sign", null, 323, 0, "items/sign.png"),
- I_324_0_WOODEN_DOOR("wooden_door", null, 324, 0, "items/wooden_door.png"),
- I_325_0_BUCKET_BUCKET("bucket", "bucket", 325, 0, "items/bucket_bucket.png"),
- I_325_1_BUCKET_MILK("bucket", "milk", 325, 1, "items/bucket_milk.png"),
- I_325_8_BUCKET_BUCKET_WATER("bucket", "bucket_water", 325, 8, "items/bucket_bucket_water.png"),
- I_325_10_BUCKET_BUCKET_LAVA("bucket", "bucket_lava", 325, 10, "items/bucket_bucket_lava.png"),
- I_328_0_MINECART("minecart", null, 328, 0, "items/minecart.png"),
- I_329_0_SADDLE("saddle", null, 329, 0, "items/saddle.png"),
- I_330_0_IRON_DOOR("iron_door", null, 330, 0, "items/iron_door.png"),
- I_331_0_REDSTONE("redstone", null, 331, 0, "items/redstone.png"),
- I_332_0_SNOWBALL("snowball", null, 332, 0, "items/snowball.png"),
- I_333_0_BOAT_OAK("boat", "oak", 333, 0, "items/boat_oak.png"),
- I_333_1_BOAT_SPRUCE("boat", "spruce", 333, 1, "items/boat_spruce.png"),
- I_333_2_BOAT_BIRCH("boat", "birch", 333, 2, "items/boat_birch.png"),
- I_333_3_BOAT_JUNGLE("boat", "jungle", 333, 3, "items/boat_jungle.png"),
- I_333_4_BOAT_ACACIA("boat", "acacia", 333, 4, "items/boat_acacia.png"),
- I_333_5_BOAT_BIG_OAK("boat", "big_oak", 333, 5, "items/boat_big_oak.png"),
- I_334_0_LEATHER("leather", null, 334, 0, "items/leather.png"),
- I_336_0_BRICK("brick", null, 336, 0, "items/brick.png"),
- I_337_0_CLAY_BALL("clay_ball", null, 337, 0, "items/clay_ball.png"),
- I_338_0_REEDS("reeds", null, 338, 0, "items/reeds.png"),
- I_339_0_PAPER("paper", null, 339, 0, "items/paper.png"),
- I_340_0_BOOK("book", null, 340, 0, "items/book.png"),
- I_341_0_SLIME_BALL("slime_ball", null, 341, 0, "items/slime_ball.png"),
- I_342_0_CHEST_MINECART("chest_minecart", null, 342, 0, "items/chest_minecart.png"),
- I_344_0_EGG("egg", null, 344, 0, "items/egg.png"),
- I_345_0_COMPASS("compass", null, 345, 0, "items/compass.png"),
- I_346_0_FISHING_ROD("fishing_rod", null, 346, 0, "items/fishing_rod.png"),
- I_347_0_CLOCK("clock", null, 347, 0, "items/clock.png"),
- I_348_0_GLOWSTONE_DUST("glowstone_dust", null, 348, 0, "items/glowstone_dust.png"),
- I_349_0_FISH("fish", null, 349, 0, "items/fish.png"),
- I_350_0_COOKED_FISH("cooked_fish", null, 350, 0, "items/cooked_fish.png"),
- I_351_0_DYE_BLACKINKSAC("dye", "black", 351, 0, "items/dye_powder_black.png"),
- I_351_1_DYE_RED("dye", "red", 351, 1, "items/dye_powder_red.png"),
- I_351_2_DYE_GREEN("dye", "green", 351, 2, "items/dye_powder_green.png"),
- I_351_3_DYE_BROWNCOCOABEANS("dye", "brown", 351, 3, "items/dye_powder_brown.png"),
- I_351_4_DYE_BLUE("dye", "blue", 351, 4, "items/dye_powder_blue.png"),
- I_351_5_DYE_PURPLE("dye", "purple", 351, 5, "items/dye_powder_purple.png"),
- I_351_6_DYE_CYAN("dye", "cyan", 351, 6, "items/dye_powder_cyan.png"),
- I_351_7_DYE_SILVER("dye", "silver", 351, 7, "items/dye_powder_silver.png"),
- I_351_8_DYE_GRAY("dye", "gray", 351, 8, "items/dye_powder_gray.png"),
- I_351_9_DYE_PINK("dye", "pink", 351, 9, "items/dye_powder_pink.png"),
- I_351_10_DYE_LIME("dye", "lime", 351, 10, "items/dye_powder_lime.png"),
- I_351_11_DYE_YELLOW("dye", "yellow", 351, 11, "items/dye_powder_yellow.png"),
- I_351_12_DYE_LIGHT_BLUE("dye", "light_blue", 351, 12, "items/dye_powder_light_blue.png"),
- I_351_13_DYE_MAGENTA("dye", "magenta", 351, 13, "items/dye_powder_magenta.png"),
- I_351_14_DYE_ORANGE("dye", "orange", 351, 14, "items/dye_powder_orange.png"),
- I_351_15_DYE_WHITEBONEMEAL("dye", "white", 351, 15, "items/dye_powder_white.png"),
- I_352_0_BONE("bone", null, 352, 0, "items/bone.png"),
- I_353_0_SUGAR("sugar", null, 353, 0, "items/sugar.png"),
- I_354_0_CAKE("cake", null, 354, 0, "items/cake.png"),
- I_355_0_BED("bed", null, 355, 0, "items/bed.png"),
- I_356_0_REPEATER("repeater", null, 356, 0, "items/repeater.png"),
- I_357_0_COOKIE("cookie", null, 357, 0, "items/cookie.png"),
- I_358_0_MAP_FILLED("map_filled", null, 358, 0, "items/map_filled.png"),
- I_359_0_SHEARS("shears", null, 359, 0, "items/shears.png"),
- I_360_0_MELON("melon", null, 360, 0, "items/melon.png"),
- I_361_0_PUMPKIN_SEEDS("pumpkin_seeds", null, 361, 0, "items/pumpkin_seeds.png"),
- I_362_0_MELON_SEEDS("melon_seeds", null, 362, 0, "items/melon_seeds.png"),
- I_363_0_BEEF("beef", null, 363, 0, "items/beef.png"),
- I_364_0_COOKED_BEEF("cooked_beef", null, 364, 0, "items/cooked_beef.png"),
- I_365_0_CHICKEN("chicken", null, 365, 0, "items/chicken.png"),
- I_366_0_COOKED_CHICKEN("cooked_chicken", null, 366, 0, "items/cooked_chicken.png"),
- I_367_0_ROTTEN_FLESH("rotten_flesh", null, 367, 0, "items/rotten_flesh.png"),
- I_368_0_ENDER_PEARL("ender_pearl", null, 368, 0, "items/ender_pearl.png"),
- I_369_0_BLAZE_ROD("blaze_rod", null, 369, 0, "items/blaze_rod.png"),
- I_370_0_GHAST_TEAR("ghast_tear", null, 370, 0, "items/ghast_tear.png"),
- I_371_0_GOLD_NUGGET("gold_nugget", null, 371, 0, "items/gold_nugget.png"),
- I_372_0_NETHER_WART("nether_wart", null, 372, 0, "items/nether_wart.png"),
- I_373_0_POTION("potion", null, 373, 0, "items/potion.png"),
- I_374_0_GLASS_BOTTLE("glass_bottle", null, 374, 0, "items/glass_bottle.png"),
- I_375_0_SPIDER_EYE("spider_eye", null, 375, 0, "items/spider_eye.png"),
- I_376_0_FERMENTED_SPIDER_EYE("fermented_spider_eye", null, 376, 0, "items/fermented_spider_eye.png"),
- I_377_0_BLAZE_POWDER("blaze_powder", null, 377, 0, "items/blaze_powder.png"),
- I_378_0_MAGMA_CREAM("magma_cream", null, 378, 0, "items/magma_cream.png"),
- I_379_0_BREWING_STAND("brewing_stand", null, 379, 0, "items/brewing_stand.png"),
- I_380_0_CAULDRON("cauldron", null, 380, 0, "items/cauldron.png"),
- I_381_0_ENDER_EYE("ender_eye", null, 381, 0, "items/ender_eye.png"),
- I_382_0_SPECKLED_MELON("speckled_melon", null, 382, 0, "items/speckled_melon.png"),
- I_383_0_SPAWN_EGG("spawn_egg", null, 383, 0, "items/spawn_egg.png"),
- I_384_0_EXPERIENCE_BOTTLE("experience_bottle", null, 384, 0, "items/experience_bottle.png"),
- I_385_0_FIREBALL("fireball", null, 385, 0, "items/fireball.png"),
- I_388_0_EMERALD("emerald", null, 388, 0, "items/emerald.png"),
- I_389_0_FRAME("frame", null, 389, 0, "items/frame.png"),
- I_390_0_FLOWER_POT("flower_pot", null, 390, 0, "items/flower_pot.png"),
- I_391_0_CARROT("carrot", null, 391, 0, "items/carrot.png"),
- I_392_0_POTATO("potato", null, 392, 0, "items/potato.png"),
- I_393_0_BAKED_POTATO("baked_potato", null, 393, 0, "items/baked_potato.png"),
- I_394_0_POISONOUS_POTATO("poisonous_potato", null, 394, 0, "items/poisonous_potato.png"),
- I_395_0_EMPTYMAP("emptyMap", null, 395, 0, "items/emptyMap.png"),
- I_396_0_GOLDEN_CARROT("golden_carrot", null, 396, 0, "items/golden_carrot.png"),
- I_397_0_SKULL_SKELETON("skull", "skeleton", 397, 0, "items/skull_skeleton.png"),
- I_397_1_SKULL_WITHER("skull", "wither", 397, 1, "items/skull_wither.png"),
- I_397_2_SKULL_ZOMBIE("skull", "zombie", 397, 2, "items/skull_zombie.png"),
- I_397_3_SKULL_PLAYER("skull", "player", 397, 3, "items/skull_player.png"),
- I_397_4_SKULL_CREEPER("skull", "creeper", 397, 4, "items/skull_creeper.png"),
- I_397_5_SKULL_DRAGON("skull", "dragon", 397, 5, "items/skull_dragon.png"),
- I_398_0_CARROTONASTICK("carrotOnAStick", null, 398, 0, "items/carrotOnAStick.png"),
- I_399_0_NETHERSTAR("netherStar", null, 399, 0, "items/netherStar.png"),
- I_400_0_PUMPKIN_PIE("pumpkin_pie", null, 400, 0, "items/pumpkin_pie.png"),
- I_403_0_ENCHANTED_BOOK("enchanted_book", null, 403, 0, "items/enchanted_book.png"),
- I_404_0_COMPARATOR("comparator", null, 404, 0, "items/comparator.png"),
- I_405_0_NETHERBRICK("netherbrick", null, 405, 0, "items/netherbrick.png"),
- I_406_0_QUARTZ("quartz", null, 406, 0, "items/quartz.png"),
- I_407_0_TNT_MINECART("tnt_minecart", null, 407, 0, "items/tnt_minecart.png"),
- I_408_0_HOPPER_MINECART("hopper_minecart", null, 408, 0, "items/hopper_minecart.png"),
- I_409_0_PRISMARINE_SHARD("prismarine_shard", null, 409, 0, "items/prismarine_shard.png"),
- I_410_0_HOPPER("hopper", null, 410, 0, "items/hopper.png"),
- I_411_0_RABBIT("rabbit", null, 411, 0, "items/rabbit.png"),
- I_412_0_COOKED_RABBIT("cooked_rabbit", null, 412, 0, "items/cooked_rabbit.png"),
- I_413_0_RABBIT_STEW("rabbit_stew", null, 413, 0, "items/rabbit_stew.png"),
- I_414_0_RABBIT_FOOT("rabbit_foot", null, 414, 0, "items/rabbit_foot.png"),
- I_415_0_RABBIT_HIDE("rabbit_hide", null, 415, 0, "items/rabbit_hide.png"),
- I_416_0_HORSEARMORLEATHER("horsearmorleather", null, 416, 0, "items/horsearmorleather.png"),
- I_417_0_HORSEARMORIRON("horsearmoriron", null, 417, 0, "items/horsearmoriron.png"),
- I_418_0_HORSEARMORGOLD("horsearmorgold", null, 418, 0, "items/horsearmorgold.png"),
- I_419_0_HORSEARMORDIAMOND("horsearmordiamond", null, 419, 0, "items/horsearmordiamond.png"),
- I_420_0_LEAD("lead", null, 420, 0, "items/lead.png"),
- I_421_0_NAMETAG("nameTag", null, 421, 0, "items/nameTag.png"),
- I_422_0_PRISMARINE_CRYSTALS("prismarine_crystals", null, 422, 0, "items/prismarine_crystals.png"),
- I_423_0_MUTTONRAW("muttonRaw", null, 423, 0, "items/muttonRaw.png"),
- I_424_0_MUTTONCOOKED("muttonCooked", null, 424, 0, "items/muttonCooked.png"),
- I_426_0_END_CRYSTAL("end_crystal", null, 426, 0, "items/end_crystal.png"),
- I_427_0_SPRUCE_DOOR("spruce_door", null, 427, 0, "items/spruce_door.png"),
- I_428_0_BIRCH_DOOR("birch_door", null, 428, 0, "items/birch_door.png"),
- I_429_0_JUNGLE_DOOR("jungle_door", null, 429, 0, "items/jungle_door.png"),
- I_430_0_ACACIA_DOOR("acacia_door", null, 430, 0, "items/acacia_door.png"),
- I_431_0_DARK_OAK_DOOR("dark_oak_door", null, 431, 0, "items/dark_oak_door.png"),
- I_432_0_CHORUS_FRUIT("chorus_fruit", null, 432, 0, "items/chorus_fruit.png"),
- I_433_0_CHORUS_FRUIT_POPPED("chorus_fruit_popped", null, 433, 0, "items/chorus_fruit_popped.png"),
- I_437_0_DRAGON_BREATH("dragon_breath", null, 437, 0, "items/dragon_breath.png"),
- I_438_0_SPLASH_POTION("splash_potion", null, 438, 0, "items/splash_potion.png"),
- I_441_0_LINGERING_POTION("lingering_potion", null, 441, 0, "items/lingering_potion.png"),
- I_444_0_ELYTRA("elytra", null, 444, 0, "items/elytra.png"),
- I_457_0_BEETROOT("beetroot", null, 457, 0, "items/beetroot.png"),
- I_458_0_BEETROOT_SEEDS("beetroot_seeds", null, 458, 0, "items/seeds_beetroot.png"),
- I_459_0_BEETROOT_SOUP("beetroot_soup", null, 459, 0, "items/beetroot_soup.png"),
- I_460_0_SALMON("salmon", null, 460, 0, "items/fish_salmon.png"),
- I_461_0_CLOWNFISH("clownfish", null, 461, 0, "items/fish_clownfish.png"),
- I_462_0_PUFFERFISH("pufferfish", null, 462, 0, "items/fish_pufferfish.png"),
- I_463_0_COOKED_SALMON("cooked_salmon", null, 463, 0, "items/fish_salmon_cooked.png"),
- I_466_0_APPLEENCHANTED("apple_enchanted", null, 466, 0, "items/apple_golden.png"),
- I_454_0_BOARD_ONE_BY_ONE("board", "one_by_one", 454, 0, "items/chalkboard_small.png"),
- I_454_1_BOARD_TWO_BY_ONE("board", "two_by_one", 454, 1, "items/chalkboard_medium.png"),
- I_454_2_BOARD_THREE_BY_TWO("board", "three_by_two", 454, 2, "items/chalkboard_large.png"),
- I_456_0_PORTFOLIO("portfolio", null, 456, 0, "items/portfolio.png"),
- I_498_0_CAMERA("camera", null, 498, 0, "items/camera.png");
-
-
- public final int id, subId;
-
- public final String name, subName, displayName, identifier;
-
- public final String texPath;
-
- public final Color color;
- public final boolean hasBiomeShading;
-
-
- public Bitmap bitmap;
-
- Block(String name, String subName, int id, int subId, String texPath, int color, boolean hasBiomeShading){
- this.id = id;
- this.subId = subId;
- this.name = name;
- this.subName = subName;
- this.displayName = name + " " + subName;
- this.texPath = texPath;
- this.color = Color.fromARGB(color);
- this.hasBiomeShading = hasBiomeShading;
- this.identifier = "minecraft:" + subName;
- }
-
- Block(String name, String subName, int id, int subId, String texPath){
- this.id = id;
- this.subId = subId;
- this.name = name;
- this.subName = subName;
- this.displayName = name + " " + subName;
- this.texPath = texPath;
- this.color = null;
- this.hasBiomeShading = false;
- this.identifier = "minecraft:" + subName;
- }
-
- @Override
- public Bitmap getBitmap(){
- return this.bitmap;
- }
-
- @NonNull
- @Override
- public NamedBitmapProvider getNamedBitmapProvider(){
- return this;
- }
-
- @NonNull
- @Override
- public String getBitmapDisplayName(){
- return this.displayName;
- }
-
- @NonNull
- @Override
- public String getBitmapDataName(){
- return name + "@" + subName;
- }
-
- private static final Map byDataName = new HashMap<>();
- private static final SparseArray> blockMap;
- static {
- blockMap = new SparseArray<>();
- SparseArray subMap;
- for(Block b : Block.values()){
- subMap = blockMap.get(b.id);
- if(subMap == null){
- subMap = new SparseArray<>();
- blockMap.put(b.id, subMap);
- }
- subMap.put(b.subId, b);
- if(b.subId == 0) byDataName.put(b.name, b);
- byDataName.put(b.name + "@" + b.subName, b);
- }
- }
-
- public static Block getByDataName(String dataName){
- return byDataName.get(dataName);
- }
-
- public static void loadBitmaps(AssetManager assetManager) throws IOException {
- for(Block b : Block.values()){
- if(b.bitmap == null && b.texPath != null){
- try {
- b.bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(assetManager.open(b.texPath)), 32, 32, false);
- } catch(FileNotFoundException e){
- //TODO file-paths were generated from block names; some do not actually exist...
- //Log.w("File not found! "+b.texPath);
- } catch (Exception e){
- e.printStackTrace();
- }
- }
- }
- }
-
- public static Block getBlock(int id, int meta){
- if(id < 0) return null;
- SparseArray subMap = blockMap.get(id);
- if(subMap == null) return null;
- else return subMap.get(meta);
- }
-
-}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/CustomIcon.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/CustomIcon.java
index 3a57176b..e2476334 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/CustomIcon.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/CustomIcon.java
@@ -3,7 +3,7 @@
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
import com.mithrilmania.blocktopograph.util.NamedBitmapProviderHandle;
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/Dimension.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/Dimension.java
index 2d5e2c13..c99e4562 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/Dimension.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/Dimension.java
@@ -1,6 +1,9 @@
package com.mithrilmania.blocktopograph.map;
+import androidx.annotation.StringRes;
+
+import com.mithrilmania.blocktopograph.R;
import com.mithrilmania.blocktopograph.map.renderer.MapType;
import java.util.HashMap;
@@ -9,7 +12,7 @@
public enum Dimension {
OVERWORLD(0, "overworld", "Overworld", 16, 16, 128, 1, MapType.OVERWORLD_SATELLITE),
- NETHER(1, "nether", "Nether", 16, 16, 128, 8, MapType.NETHER),
+ NETHER(1, "nether", "Nether", 16, 16, 128, 1, MapType.NETHER),
END(2, "end", "End", 16, 16, 128, 1, MapType.END_SATELLITE);//mcpe: SOON^TM /jk
public final int id;
@@ -18,7 +21,7 @@ public enum Dimension {
public final String dataName, name;
public final MapType defaultMapType;
- Dimension(int id, String dataName, String name, int chunkW, int chunkL, int chunkH, int dimensionScale, MapType defaultMapType){
+ Dimension(int id, String dataName, String name, int chunkW, int chunkL, int chunkH, int dimensionScale, MapType defaultMapType) {
this.id = id;
this.dataName = dataName;
this.name = name;
@@ -29,22 +32,37 @@ public enum Dimension {
this.defaultMapType = defaultMapType;
}
+ @StringRes
+
+ public int getName() {
+ switch (this) {
+ case OVERWORLD:
+ return R.string.overworld;
+ case NETHER:
+ return R.string.nether;
+ case END:
+ return R.string.the_end;
+ default:
+ return 0;
+ }
+ }
+
private static Map dimensionMap = new HashMap<>();
static {
- for(Dimension dimension : Dimension.values()){
+ for (Dimension dimension : Dimension.values()) {
dimensionMap.put(dimension.dataName, dimension);
}
}
- public static Dimension getDimension(String dataName){
- if(dataName == null) return null;
+ public static Dimension getDimension(String dataName) {
+ if (dataName == null) return null;
return dimensionMap.get(dataName.toLowerCase());
}
- public static Dimension getDimension(int id){
- for(Dimension dimension : values()){
- if(dimension.id == id) return dimension;
+ public static Dimension getDimension(int id) {
+ for (Dimension dimension : values()) {
+ if (dimension.id == id) return dimension;
}
return null;
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/Entity.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/Entity.java
index 2f250962..60db008d 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/Entity.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/Entity.java
@@ -3,123 +3,151 @@
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
import com.mithrilmania.blocktopograph.util.NamedBitmapProviderHandle;
import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
/*
-Entity enum for MCPE -- by @mithrilmania
+Entity enum for MCPE __ by @mithrilmania
+
+___ Please attribute @mithrilmania for generating+updating this enum
+
+ Format:
+
+ ENTITY(
+ numeric_id, deprecated!
+ Display Name,
+ DataName, not used?
+ wiki_name, as identifier, originally dumped as wiki-name cases.
+ icon
+ )
+
+ icon is from assets/entity_wiki.png which was download from
+ https://d1u5p3l4wpay3k.cloudfront.net/minecraft_gamepedia/4/40/EntityCSS.png
---- Please attribute @mithrilmania for generating+updating this enum
*/
public enum Entity implements NamedBitmapProviderHandle, NamedBitmapProvider {
-
- CHICKEN(10, "Chicken", new String[]{ "Chicken" }, "chicken", 4),
- COW(11, "Cow", new String[]{ "Cow" }, "cow", 3),
- PIG(12, "Pig", new String[]{ "Pig" }, "pig", 1),
- SHEEP(13, "Sheep", new String[]{ "Sheep" }, "sheep", 2),
- WOLF(14, "Wolf", new String[]{ "Wolf" }, "wolf", 18),
- VILLAGER(15, "Villager", new String[]{ "Villager" }, "villager", 7),
- MUSHROOM_COW(16, "Mooshroom", new String[]{ "MushroomCow" }, "mooshroom", 6),
- SQUID(17, "Squid", new String[]{ "Squid" }, "squid", 5),
- RABBIT(18, "Rabbit", new String[]{ "Rabbit" }, "rabbit", 89),
- BAT(19, "Bat", new String[]{ "Bat" }, "bat", 64),
- VILLAGER_GOLEM(20, "Iron Golem", new String[]{ "VillagerGolem", "IronGolem" }, "iron-golem", 48),
- SNOW_MAN(21, "Snow Golem", new String[]{ "SnowMan", "SnowGolem" }, "snow-golem", 31),
- OZELOT(22, "Ocelot", new String[]{ "Ozelot", "Ocelot" }, "ozelot", 37),
- HORSE(23, "Donkey", new String[]{ "EntityHorse", "Horse" }, "horse", 73),
- HORSE_DONKEY(24, "Donkey", new String[]{ "EntityHorse", "Donkey" }, "donkey", 74),
- HORSE_MULE(25, "Mule", new String[]{ "EntityHorse", "Mule" }, "mule", 75),
- HORSE_SKELETON(26, "Skeleten Horse", new String[]{ "EntityHorse", "SkeletonHorse" }, "skeleton-horse", 76),
- HORSE_ZOMBIE(27, "Zombie Horse", new String[]{ "EntityHorse", "ZombieHorse" }, "zombie-horse", 77),
+ CHICKEN(10, "Chicken", new String[]{"Chicken", "chicken"}, "chicken", 4),
+ COW(11, "Cow", new String[]{"Cow", "cow"}, "cow", 3),
+ PIG(12, "Pig", new String[]{"Pig", "pig"}, "pig", 1),
+ SHEEP(13, "Sheep", new String[]{"Sheep", "sheep"}, "sheep", 2),
+ WOLF(14, "Wolf", new String[]{"Wolf", "wolf"}, "wolf", 18),
+ VILLAGER(15, "Villager", new String[]{"Villager", "villager", "villager_v2"}, "villager", 7),
+ MUSHROOM_COW(16, "Mooshroom", new String[]{"MushroomCow", "mushroomcow", "mooshroom"}, "mooshroom", 6),
+ SQUID(17, "Squid", new String[]{"Squid", "squid"}, "squid", 5),
+ RABBIT(18, "Rabbit", new String[]{"Rabbit", "rabbit"}, "rabbit", 89),
+ BAT(19, "Bat", new String[]{"Bat", "bat"}, "bat", 64),
+ VILLAGER_GOLEM(20, "Iron Golem", new String[]{"VillagerGolem", "IronGolem", "villagergolem", "irongolem", "iron-golem", "iron_golem"}, "iron-golem", 48),
+ SNOW_MAN(21, "Snow Golem", new String[]{"SnowMan", "SnowGolem", "snowman", "snowgolem", "snow-golem"}, "snow-golem", 31),
+ OZELOT(22, "Ocelot", new String[]{"Ozelot", "Ocelot", "ozelot", "ocelot", "cat"}, "ozelot", 37),
+ HORSE(23, "Horse", new String[]{"EntityHorse", "Horse", "entityhorse", "horse"}, "horse", 73),
+ HORSE_DONKEY(24, "Donkey", new String[]{"EntityHorse", "Donkey", "donkey"}, "donkey", 74),
+ HORSE_MULE(25, "Mule", new String[]{"EntityHorse", "Mule", "mule"}, "mule", 75),
+ HORSE_SKELETON(26, "Skeleten Horse", new String[]{"skeleton_horse", "EntityHorse", "SkeletonHorse", "skeletonhorse", "skeleton-horse"}, "skeleton-horse", 76),
+ HORSE_ZOMBIE(27, "Zombie Horse", new String[]{"EntityHorse", "ZombieHorse", "zombiehorse", "zombie-horse"}, "zombie-horse", 77),
//28
//29
- ARMOR_STAND(30, "Armor Stand", new String[]{ "ArmorStand" }, "TODO", 106),//30 ; ArmorStand is not yet in the game
+ ARMOR_STAND(30, "Armor Stand", new String[]{"ArmorStand", "armorstand"}, "TODO", 106),
//31
- ZOMBIE(32, "Zombie", new String[]{ "Zombie" }, "zombie", 9),
- CREEPER(33, "Creeper", new String[]{ "Creeper" }, "creeper", 14),
- SKELETON(34, "Skeleton", new String[]{ "Skeleton" }, "skeleton", 10),
- SPIDER(35, "Spider", new String[]{ "Spider" }, "spider", 11),
- PIG_ZOMBIE(36, "Zombie Pigman", new String[]{ "PigZombie" }, "zombie-pigman", 17),
- SLIME(37, "Slime", new String[]{ "Slime" }, "slime", 15),
- ENDERMAN(38, "Enderman", new String[]{ "Enderman", "EnderMan" }, "enderman", 21),
- SILVERFISH(39, "Silverfish", new String[]{ "Silverfish" }, "silverfish", 22),
- CAVE_SPIDER(40, "Cave Spider", new String[]{ "CaveSpider" }, "cave-spider", 13),
- GHAST(41, "Ghast", new String[]{ "Ghast" }, "ghast", 16),
- LAVA_SLIME(42, "Magma Cube", new String[]{ "LavaSlime" }, "magma-cube", 24),
- BLAZE(43, "Blaze", new String[]{ "Blaze" }, "blaze", 32),
- ZOMBIE_VILLAGER(44, "Zombie Villager", new String[]{ "ZombieVillager" }, "zombie-villager", 62),
- WITCH(45, "Witch", new String[]{ "Witch" }, "witch", 54),
- SKELETON_STRAY(46, "Stray", new String[]{ "Skeleton", "StraySkeleton" }, "stray", 98),
- ZOMBIE_HUSK(47, "Husk", new String[]{ "Zombie", "HuskZombie" }, "husk", 99),
- SKELETON_WITHER(48, "Wither Skeleton", new String[]{ "Skeleton", "WitherSkeleton" }, "wither", 61),
- GUARDIAN(49, "Guardian", new String[]{ "Guardian" }, "guardian", 87),
- ELDER_GAURDIAN(50, "Elder Gaurdian", new String[]{ "ElderGaurdian" }, "elder-gaurdian", 88),
- NPC(51, "NPC", new String[]{ "Npc" }, "npc", 100),
- WITHER_BOSS(52, "Wither Boss", new String[]{ "WitherBoss" }, "blue-wither-skull", 72),
- ENDER_DRAGON(53, "Ender Dragon", new String[]{ "EnderDragon" }, "ender-dragon", 29),
- SHULKER(54, "Shulker", new String[]{ "Shulker" }, "shulker", 30),
- ENDERMITE(55, "Endermite", new String[]{ "Endermite" }, "endermite", 86),
- LEARN_TO_CODE_MASCOT(56, "Learn To Code Mascot", new String[]{ "LearnToCodeMascot" }, "learn-to-code-mascot", 108),
- GIANT(57, "Giant Zombie", new String[]{ "Giant" }, "giant", 9),//53 ; Giant is not yet in the game
+ ZOMBIE(32, "Zombie", new String[]{"Zombie", "zombie"}, "zombie", 9),
+ CREEPER(33, "Creeper", new String[]{"Creeper", "creeper"}, "creeper", 14),
+ SKELETON(34, "Skeleton", new String[]{"Skeleton", "skeleton"}, "skeleton", 10),
+ SPIDER(35, "Spider", new String[]{"Spider", "spider"}, "spider", 12),
+ PIG_ZOMBIE(36, "Zombie Pigman", new String[]{"PigZombie", "pigzombie", "zombie-pigman", "zombie_pigman"}, "zombie-pigman", 17),
+ SLIME(37, "Slime", new String[]{"Slime", "slime"}, "slime", 15),
+ ENDERMAN(38, "Enderman", new String[]{"Enderman", "EnderMan", "enderman"}, "enderman", 21),
+ SILVERFISH(39, "Silverfish", new String[]{"Silverfish", "silverfish"}, "silverfish", 22),
+ CAVE_SPIDER(40, "Cave Spider", new String[]{"CaveSpider", "cavespider", "cave-spider", "cave_spider"}, "cave-spider", 118),
+ GHAST(41, "Ghast", new String[]{"Ghast", "ghast"}, "ghast", 16),
+ LAVA_SLIME(42, "Magma Cube", new String[]{"LavaSlime", "lavaslime", "magma-cube", "magma_cube"}, "magma-cube", 24),
+ BLAZE(43, "Blaze", new String[]{"Blaze", "blaze"}, "blaze", 32),
+ ZOMBIE_VILLAGER(44, "Zombie Villager", new String[]{"ZombieVillager", "zombievillager", "zombie_villager_v2", "zombie_villager"}, "zombie-villager", 62),
+ WITCH(45, "Witch", new String[]{"Witch", "witch"}, "witch", 54),
+ SKELETON_STRAY(46, "Stray", new String[]{"Skeleton", "StraySkeleton", "strayskeleton", "stray"}, "stray", 98),
+ ZOMBIE_HUSK(47, "Husk", new String[]{"Zombie", "HuskZombie", "husk", "huskzombie"}, "husk", 99),
+ SKELETON_WITHER(48, "Wither Skeleton", new String[]{"Skeleton", "WitherSkeleton", "wither", "wither_skeleton"}, "wither", 61),
+ GUARDIAN(49, "Guardian", new String[]{"Guardian", "guardian"}, "guardian", 87),
+ ELDER_GAURDIAN(50, "Elder Gaurdian", new String[]{"ElderGaurdian", "elder-guardian", "elderguardian"}, "elder-gaurdian", 88),
+ NPC(51, "NPC", new String[]{"Npc", "npc"}, "npc", 100),
+ WITHER_BOSS(52, "Wither Boss", new String[]{"WitherBoss", "witherboss", "blue-wither-skull"}, "blue-wither-skull", 72),
+ ENDER_DRAGON(53, "Ender Dragon", new String[]{"EnderDragon", "ender-dragon", "enderdragon"}, "ender-dragon", 29),
+ SHULKER(54, "Shulker", new String[]{"Shulker", "shukler", "shulker"}, "shulker", 30),
+ ENDERMITE(55, "Endermite", new String[]{"Endermite", "endermite"}, "endermite", 86),
+ LEARN_TO_CODE_MASCOT(56, "Learn To Code Mascot", new String[]{"LearnToCodeMascot", "learntocodemascot", "learn-to-code-mascot"}, "learn-to-code-mascot", 108),
+ GIANT(57, "Giant Zombie", new String[]{"Giant", "giant"}, "giant", 9),//53 ; Giant is not yet in the game
//58
//59
//60
//61
//61
- CAMERA(62, "Tripod Camera", new String[]{ "TripodCamera" }, "camera", 144),
- PLAYER(63, "Player", new String[]{ "Player" }, "player", 8),
- ITEM(64, "Dropped Item", new String[]{ "ItemEntity" }, "item", -1),//do not render items
- PRIMED_TNT(65, "Primed TNT", new String[]{ "PrimedTnt" }, "primed-tnt", 49),
- FALLING_SAND(66, "Falling Block", new String[]{ "FallingBlock" }, "falling-sand", 50),
- ITEM_FRAME(67, "Item Frame", new String[]{ "ItemFrame" }, "empty-item-frame", 66),//67 ; ItemFrame is not yet in the game
- THROWN_EXP_BOTTLE(68, "Bottle o' Enchanting", new String[]{ "ThrownExpBottle", "ExperiencePotion" }, "ThrownExpBottle", 56),
- XP_ORB(69, "Experience Orb", new String[]{ "XPOrb", "ExperienceOrb" }, "experience-orb", 59),
- EYE_OF_ENDER_SIGNAL(70, "Eye of Ender", new String[]{ "EyeOfEnderSignal" }, "eye-of-ender", 47),
- ENDER_CRYSTAL(71, "Ender Crystal", new String[]{ "EnderCrystal" }, "ender-crystal", 52),
+ CAMERA(62, "Tripod Camera", new String[]{"TripodCamera", "camera"}, "camera", 144),
+ PLAYER(63, "Player", new String[]{"Player", "player"}, "player", 8),
+ ITEM(64, "Dropped Item", new String[]{"ItemEntity", "item"}, "item", -1),//do not render items
+ PRIMED_TNT(65, "Primed TNT", new String[]{"PrimedTnt", "primedtnt", "primed-tnt"}, "primed-tnt", 49),
+ FALLING_SAND(66, "Falling Block", new String[]{"FallingBlock", "falling-sand", "fallingblock"}, "falling-sand", 50),
+ ITEM_FRAME(67, "Item Frame", new String[]{"ItemFrame", "itemframe", "empty-item-frame"}, "empty-item-frame", 66),//67 ; ItemFrame is not yet in the game
+ THROWN_EXP_BOTTLE(68, "Bottle o' Enchanting", new String[]{"ThrownExpBottle", "ExperiencePotion", "thrownexpbottle"}, "ThrownExpBottle", 56),
+ XP_ORB(69, "Experience Orb", new String[]{"XPOrb", "ExperienceOrb", "experience-orb", "experienceorb", "xp_orb"}, "experience-orb", 59),
+ EYE_OF_ENDER_SIGNAL(70, "Eye of Ender", new String[]{"EyeOfEnderSignal", "eyeofendersignal", "eye-of-ender"}, "eye-of-ender", 47),
+ ENDER_CRYSTAL(71, "Ender Crystal", new String[]{"EnderCrystal", "endercrystal", "ender-crystal"}, "ender-crystal", 52),
//72
//73
- TURTLE(74, "Turtle", new String[]{ "Turtle" }, "turtle", 79),
+ //74
//75
- SHULKER_BULLET(76, "Shulker Bullet", new String[]{ "ShulkerBullet" }, "shulker-bullet", 79),
- FISHING_HOOK(77, "Fishing Hook", new String[]{ "FishingHook" }, "fishing-hook", 57),
- CHALKBOARD(78, "Chalkboard", new String[]{ "Chalkboard" }, "chalkboard", 144),
- DRAGON_FIREBALL(79, "Dragon Fireball", new String[]{ "DragonFireball" }, "dragon-fireball", 80),
- ARROW(80, "Arrow", new String[]{ "Arrow" }, "arrow", 41),
- SNOWBALL(81, "Snowball", new String[]{ "Snowball" }, "snowball", 42),
- THROWN_EGG(82, "Thrown Egg", new String[]{ "ThrownEgg" }, "thrown-egg", 43),
- PAINTING(83, "Painting", new String[]{ "Painting" }, "painting", 65),
- MINECART_RIDEABLE(84, "Minecart", new String[]{ "MinecartRideable", "Minecart" }, "minecart", 34),
- LARGE_FIREBALL(85, "Ghast Fireball", new String[]{ "Fireball", "LargeFireball" }, "fireball", 44),
- THROWN_POTION(86, "Splash Potion", new String[]{ "ThrownPotion" }, "ThrownPotion", 95),
- THROWN_ENDERPEARL(87, "Ender Pearl", new String[]{ "ThrownEnderpearl" }, "ender-pearl", 46),
- LEASH_KNOT(88, "Lead Knot", new String[]{ "LeashKnot", "LeashFenceKnotEntity" }, "lead-knot", 94),
- WITHER_SKULL(89, "Wither Skull", new String[]{ "WitherSkull" }, "wither-skull", 60),
- BOAT(90, "Boat", new String[]{ "Boat" }, "boat", 33),
+ SHULKER_BULLET(76, "Shulker Bullet", new String[]{"ShulkerBullet", "shulkerbullet", "shulker-bullet"}, "shulker-bullet", 79),
+ FISHING_HOOK(77, "Fishing Hook", new String[]{"FishingHook", "fishinghook", "fishing-hook"}, "fishing-hook", 57),
+ CHALKBOARD(78, "Chalkboard", new String[]{"Chalkboard", "chalkboard"}, "chalkboard", 144),
+ DRAGON_FIREBALL(79, "Dragon Fireball", new String[]{"DragonFireball", "dragonfireball", "dragon-fireball"}, "dragon-fireball", 80),
+ ARROW(80, "Arrow", new String[]{"Arrow", "arrow"}, "arrow", 41),
+ SNOWBALL(81, "Snowball", new String[]{"Snowball", "snowball"}, "snowball", 42),
+ THROWN_EGG(82, "Thrown Egg", new String[]{"ThrownEgg", "thrownegg", "thrown-egg"}, "thrown-egg", 43),
+ PAINTING(83, "Painting", new String[]{"Painting", "painting"}, "painting", 65),
+ MINECART_RIDEABLE(84, "Minecart", new String[]{"MinecartRideable", "Minecart", "minecart"}, "minecart", 34),
+ LARGE_FIREBALL(85, "Ghast Fireball", new String[]{"Fireball", "LargeFireball", "fireball", "largefireball"}, "fireball", 44),
+ THROWN_POTION(86, "Splash Potion", new String[]{"ThrownPotion", "thrownpotion"}, "ThrownPotion", 95),
+ THROWN_ENDERPEARL(87, "Ender Pearl", new String[]{"ThrownEnderpearl", "thrownenderpearl", "ender-pearl"}, "ender-pearl", 46),
+ LEASH_KNOT(88, "Lead Knot", new String[]{"LeashKnot", "LeashFenceKnotEntity", "lead-knot", "leashknot", "leashfenceknotentity", "leash_knot"}, "lead-knot", 94),
+ WITHER_SKULL(89, "Wither Skull", new String[]{"WitherSkull", "wither-skull", "witherskull"}, "wither-skull", 60),
+ BOAT(90, "Boat", new String[]{"Boat", "boat"}, "boat", 33),
//91
//92
- LIGHTNING(93, "Lightning Bolt", new String[]{ "LightningBolt" }, "lightning", 58),
- SMALL_FIREBALL(94, "Blaze Fireball", new String[]{ "SmallFireball" }, "fireball", 44),
- AREA_EFFECT_CLOUD(95, "Area effect cloud", new String[]{ "AreaEffectCloud" }, "area-effect-cloud", 144),
- MINECART_HOPPER(96, "Minecart with Hopper", new String[]{ "MinecartHopper" }, "minecart-with-hopper", 70),
- MINECART_TNT(97, "Minecart with TNT", new String[]{ "MinecartTNT" }, "minecart-with-tnt", 69),
- MINECART_CHEST(98, "Storage Minecart", new String[]{ "MinecartChest" }, "minecart-chest", 35),
- LINGERING_POTION(101, "Lingering potion", new String[]{ "LingeringPotion" }, "lingering-potion", 144),
-
- CAT(122, "Cat", new String[]{ "Cat" }, "cat", 144),//95 ; FireworksRocketEntity is not in the game yet
- PANDA(123, "Panda", new String[]{ "Panda" }, "panda", 144),//95 ; FireworksRocketEntity is not in the game yet
+ LIGHTNING(93, "Lightning Bolt", new String[]{"LightningBolt", "lightning", "lightningbolt"}, "lightning", 58),
+ SMALL_FIREBALL(94, "Blaze Fireball", new String[]{"SmallFireball", "smallfireball"}, "fireball", 44),
+ AREA_EFFECT_CLOUD(95, "Area effect cloud", new String[]{"AreaEffectCloud", "area-effect-cloud", "areaeffectcloud"}, "area-effect-cloud", 144),
+ MINECART_HOPPER(96, "Minecart with Hopper", new String[]{"MinecartHopper", "minecart-with-hopper", "minecarthopper"}, "minecart-with-hopper", 70),
+ MINECART_TNT(97, "Minecart with TNT", new String[]{"MinecartTNT", "minecart-with-tnt", "minecarttnt"}, "minecart-with-tnt", 69),
+ MINECART_CHEST(98, "Storage Minecart", new String[]{"MinecartChest", "minecart-chest", "minecartchest", "chest_minecart", "chestminecart"}, "minecart-chest", 35),
+ LINGERING_POTION(101, "Lingering potion", new String[]{"LingeringPotion", "lingeringpotion", "lingering-potion"}, "lingering-potion", 144),
//id 900+ is ignored for functions like map-filtering, these are placeholders for when the game adds more expected features.
- MINECART_SPAWNER(900, "Minecart with Spawner", new String[]{ "MinecartSpawner" }, "minecart-with-spawner", 71),//99 ; MinecartSpawner is not yet in the game
- MINECART_COMMAND_BLOCK(901, "Minecart with Command Block", new String[]{ "MinecartCommandBlock" }, "minecart-with-command-block", 78),//100 ; MinecartCommandBlock is not yet in the game
- MINECART_FURNACE(902, "Powered Minecart", new String[]{ "MinecartFurnace" }, "minecart-furnace", 36),//101 ; MinecartFurnace is not yet in the game
- FIREWORKS_ROCKET_ENTITY(903, "Firework Rocket", new String[]{ "FireworksRocketEntity" }, "fireworks-rocket", 144),//95 ; FireworksRocketEntity is not in the game yet
- UNKNOWN(999, "Unknown", new String[]{ "Unknown" }, "unknown", 144);
+ MINECART_SPAWNER(900, "Minecart with Spawner", new String[]{"MinecartSpawner", "minecart-with-spawner", "minecartspawner"}, "minecart-with-spawner", 71),//99 ; MinecartSpawner is not yet in the game
+ MINECART_COMMAND_BLOCK(901, "Minecart with Command Block", new String[]{"MinecartCommandBlock", "minecartcommandblock", "minecart-with-command-block"}, "minecart-with-command-block", 78),//100 ; MinecartCommandBlock is not yet in the game
+ MINECART_FURNACE(902, "Powered Minecart", new String[]{"MinecartFurnace", "minecartfurnace", "minecart-furnace"}, "minecart-furnace", 36),
+ FIREWORKS_ROCKET_ENTITY(903, "Firework Rocket", new String[]{"FireworksRocketEntity", "fireworksrocketentity", "fireworks-rocket"}, "fireworks-rocket", 144),//95 ; FireworksRocketEntity is not in the game yet
+ PILLAGER(102, "Pillager", new String[]{"pillager"}, "pillager", 102),
+ DROWNED(103, "Drowned", new String[]{"drowned"}, "drowned", 133),
+ PUFFERFISH(104, "Pufferfish", new String[]{"pufferfish"}, "pufferfish", 129),
+
+ LLAMA(105, "Llama", new String[]{"llama"}, "llama", 101),
+ TROPICALFISH(106, "TropicalFish", new String[]{"tropicalfish"}, "tropicalfish", 130),
+ PARROT(107, "Parrot", new String[]{"parrot"}, "parrot", 109),
+ COD(108, "Cod", new String[]{"cod"}, "cod", 126),
+ SALMON(109, "Salmon", new String[]{"salmon"}, "salmon", 128),
+ TURTLE(110, "Turtle", new String[]{"turtle"}, "turtle", 123),
+ DOLPHIN(111, "Dolphin", new String[]{"dolphin"}, "dolphin", 135),
+ WANDERINGTRADER(112, "WanderingTrader", new String[]{"wandering_trader"}, "wanderingtrader", 281),
+ PHANTOM(113, "Phantom", new String[]{"phantom"}, "phantom", 125),
+
+ THROWNTRIDENT(114, "ThrownTrident", new String[]{"thrown_trident"}, "throwntrident", 124),
+ UNKNOWN(999, "Unknown", new String[]{"Unknown", "unknown"}, "unknown", 144),
+
+ CAT(122, "Cat", new String[]{"Cat"}, "cat", 142),//95 ; FireworksRocketEntity is not in the game yet
+ PANDA(123, "Panda", new String[]{"Panda"}, "panda", 136);//95 ; FireworksRocketEntity is not in the game yet
+
public final int id, sheetPos;
public final String displayName, wikiName;
@@ -128,7 +156,7 @@ public enum Entity implements NamedBitmapProviderHandle, NamedBitmapProvider {
public Bitmap bitmap;
- Entity(int id, String displayName, String[] dataNames, String wikiName, int sheetPos){
+ Entity(int id, String displayName, String[] dataNames, String wikiName, int sheetPos) {
this.id = id;
this.displayName = displayName;
this.dataNames = dataNames;
@@ -137,20 +165,25 @@ public enum Entity implements NamedBitmapProviderHandle, NamedBitmapProvider {
this.identifier = "minecraft:" + wikiName;
}
+ @NonNull
@Override
- public Bitmap getBitmap(){
- return this.bitmap;
+ public Bitmap getBitmap() {
+ if (bitmap != null) return bitmap;
+ if (Entity.UNKNOWN.bitmap == null) {
+ Entity.UNKNOWN.bitmap = Bitmap.createBitmap(24, 24, Bitmap.Config.RGB_565);
+ }
+ return Entity.UNKNOWN.bitmap;
}
@NonNull
@Override
- public NamedBitmapProvider getNamedBitmapProvider(){
+ public NamedBitmapProvider getNamedBitmapProvider() {
return this;
}
@NonNull
@Override
- public String getBitmapDisplayName(){
+ public String getBitmapDisplayName() {
return this.displayName;
}
@@ -162,52 +195,40 @@ public String getBitmapDataName() {
return this.dataNames[0];
}
- private static final Map entityMap;
- private static final Map entityByID;
-
- static {
- entityMap = new HashMap<>();
- entityByID = new HashMap<>();
- for(Entity e : Entity.values()){
- for(String dataName : e.dataNames){
- entityMap.put(dataName, e);
- }
- entityByID.put(e.id, e);
+ public static Entity getEntity(@NonNull String identifier) {
+ int i = identifier.indexOf(':');
+ if (i != -1) {
+ if (!"minecraft".equals(identifier.substring(0, i))) return Entity.UNKNOWN;
+ identifier = identifier.substring(i + 1);
}
- }
-
- public static Entity getEntity(String dataName){
- try {
- return entityMap.get(dataName);
+ for (Entity e : Entity.values()) {
+ if (identifier.equals(e.wikiName)) return e;
}
- catch (Exception e)
- {
- android.util.Log.d("myTag","error finding id for: " + dataName);
- return entityMap.get(dataName);
+ identifier = identifier.replace("_", "");
+ for (Entity e : Entity.values()) {
+ for (String dataName : e.dataNames)
+ if (dataName.toLowerCase().equals(identifier))
+ return e;
}
+ return Entity.UNKNOWN;
}
- public static Entity getEntity(int id){
- try {
- return entityByID.get(id);
- }
- catch (Exception e )
- {
- android.util.Log.d("myTag","error finding id for: " + id);
- return entityByID.get(id);
+ public static Entity getEntity(int id) {
+ for (Entity e : Entity.values()) {
+ if (id == e.id) return e;
}
+ return Entity.UNKNOWN;
}
-
public static void loadEntityBitmaps(AssetManager assetManager) throws IOException {
Bitmap sheet = BitmapFactory.decodeStream(assetManager.open("entity_wiki.png"));
int w = sheet.getWidth();
int tileSize = 16;
- for(Entity e : Entity.values()){
- if(e.bitmap == null && e.sheetPos >= 0){
+ for (Entity e : Entity.values()) {
+ if (e.bitmap == null && e.sheetPos >= 0) {
//sheetpos; first sprite has pos 1.
- int p = (e.sheetPos-1) * tileSize;
+ int p = (e.sheetPos - 1) * tileSize;
int x = p % w;
int y = ((p - x) / w) * tileSize;
//read tile from sheet, scale to 32x32
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/FloatPaneFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/FloatPaneFragment.java
new file mode 100644
index 00000000..5fdfe797
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/FloatPaneFragment.java
@@ -0,0 +1,16 @@
+package com.mithrilmania.blocktopograph.map;
+
+import androidx.fragment.app.Fragment;
+
+public abstract class FloatPaneFragment extends Fragment {
+
+ protected FloatPaneFragment.OnCloseButtonClickListener mOnCloseButtonClickListener;
+
+ public void setOnCloseButtonClickListener(OnCloseButtonClickListener onCloseButtonClickListener) {
+ mOnCloseButtonClickListener = onCloseButtonClickListener;
+ }
+
+ public interface OnCloseButtonClickListener {
+ void onCloseButtonClick();
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/Item.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/Item.java
new file mode 100644
index 00000000..fe8b963f
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/Item.java
@@ -0,0 +1,343 @@
+package com.mithrilmania.blocktopograph.map;
+
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.util.ColorWrapper;
+import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
+import com.mithrilmania.blocktopograph.util.NamedBitmapProviderHandle;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public enum Item implements NamedBitmapProviderHandle, NamedBitmapProvider {
+
+ /*
+ * ==============================
+ * Blocks
+ * ==============================
+ */
+
+ I_256_0_IRON_SHOVEL("iron_shovel", null, 256, 0, "items/iron_shovel.png"),
+ I_257_0_IRON_PICKAXE("iron_pickaxe", null, 257, 0, "items/iron_pickaxe.png"),
+ I_258_0_IRON_AXE("iron_axe", null, 258, 0, "items/iron_axe.png"),
+ I_259_0_FLINT_AND_STEEL("flint_and_steel", null, 259, 0, "items/flint_and_steel.png"),
+ I_260_0_APPLE("apple", null, 260, 0, "items/apple.png"),
+ I_261_0_BOW("bow", null, 261, 0, "items/bow.png"),
+ I_262_0_ARROW("arrow", null, 262, 0, "items/arrow.png"),
+ I_263_0_COAL_COAL("coal", "coal", 263, 0, "items/coal_coal.png"),
+ I_263_1_COAL_CHARCOAL("coal", "charcoal", 263, 1, "items/coal_charcoal.png"),
+ I_264_0_DIAMOND("diamond", null, 264, 0, "items/diamond.png"),
+ I_265_0_IRON_INGOT("iron_ingot", null, 265, 0, "items/iron_ingot.png"),
+ I_266_0_GOLD_INGOT("gold_ingot", null, 266, 0, "items/gold_ingot.png"),
+ I_267_0_IRON_SWORD("iron_sword", null, 267, 0, "items/iron_sword.png"),
+ I_268_0_WOODEN_SWORD("wooden_sword", null, 268, 0, "items/wooden_sword.png"),
+ I_269_0_WOODEN_SHOVEL("wooden_shovel", null, 269, 0, "items/wooden_shovel.png"),
+ I_270_0_WOODEN_PICKAXE("wooden_pickaxe", null, 270, 0, "items/wooden_pickaxe.png"),
+ I_271_0_WOODEN_AXE("wooden_axe", null, 271, 0, "items/wooden_axe.png"),
+ I_272_0_STONE_SWORD("stone_sword", null, 272, 0, "items/stone_sword.png"),
+ I_273_0_STONE_SHOVEL("stone_shovel", null, 273, 0, "items/stone_shovel.png"),
+ I_274_0_STONE_PICKAXE("stone_pickaxe", null, 274, 0, "items/stone_pickaxe.png"),
+ I_275_0_STONE_AXE("stone_axe", null, 275, 0, "items/stone_axe.png"),
+ I_276_0_DIAMOND_SWORD("diamond_sword", null, 276, 0, "items/diamond_sword.png"),
+ I_277_0_DIAMOND_SHOVEL("diamond_shovel", null, 277, 0, "items/diamond_shovel.png"),
+ I_278_0_DIAMOND_PICKAXE("diamond_pickaxe", null, 278, 0, "items/diamond_pickaxe.png"),
+ I_279_0_DIAMOND_AXE("diamond_axe", null, 279, 0, "items/diamond_axe.png"),
+ I_280_0_STICK("stick", null, 280, 0, "items/stick.png"),
+ I_281_0_BOWL("bowl", null, 281, 0, "items/bowl.png"),
+ I_282_0_MUSHROOM_STEW("mushroom_stew", null, 282, 0, "items/mushroom_stew.png"),
+ I_283_0_GOLDEN_SWORD("golden_sword", null, 283, 0, "items/golden_sword.png"),
+ I_284_0_GOLDEN_SHOVEL("golden_shovel", null, 284, 0, "items/golden_shovel.png"),
+ I_285_0_GOLDEN_PICKAXE("golden_pickaxe", null, 285, 0, "items/golden_pickaxe.png"),
+ I_286_0_GOLDEN_AXE("golden_axe", null, 286, 0, "items/golden_axe.png"),
+ I_287_0_STRING("string", null, 287, 0, "items/string.png"),
+ I_288_0_FEATHER("feather", null, 288, 0, "items/feather.png"),
+ I_289_0_GUNPOWDER("gunpowder", null, 289, 0, "items/gunpowder.png"),
+ I_290_0_WOODEN_HOE("wooden_hoe", null, 290, 0, "items/wooden_hoe.png"),
+ I_291_0_STONE_HOE("stone_hoe", null, 291, 0, "items/stone_hoe.png"),
+ I_292_0_IRON_HOE("iron_hoe", null, 292, 0, "items/iron_hoe.png"),
+ I_293_0_DIAMOND_HOE("diamond_hoe", null, 293, 0, "items/diamond_hoe.png"),
+ I_294_0_GOLDEN_HOE("golden_hoe", null, 294, 0, "items/golden_hoe.png"),
+ I_295_0_WHEAT_SEEDS("wheat_seeds", null, 295, 0, "items/wheat_seeds.png"),
+ I_296_0_WHEAT("wheat", null, 296, 0, "items/wheat.png"),
+ I_297_0_BREAD("bread", null, 297, 0, "items/bread.png"),
+ I_298_0_LEATHER_HELMET("leather_helmet", null, 298, 0, "items/leather_helmet.png"),
+ I_299_0_LEATHER_CHESTPLATE("leather_chestplate", null, 299, 0, "items/leather_chestplate.png"),
+ I_300_0_LEATHER_LEGGINGS("leather_leggings", null, 300, 0, "items/leather_leggings.png"),
+ I_301_0_LEATHER_BOOTS("leather_boots", null, 301, 0, "items/leather_boots.png"),
+ I_302_0_CHAINMAIL_HELMET("chainmail_helmet", null, 302, 0, "items/chainmail_helmet.png"),
+ I_303_0_CHAINMAIL_CHESTPLATE("chainmail_chestplate", null, 303, 0, "items/chainmail_chestplate.png"),
+ I_304_0_CHAINMAIL_LEGGINGS("chainmail_leggings", null, 304, 0, "items/chainmail_leggings.png"),
+ I_305_0_CHAINMAIL_BOOTS("chainmail_boots", null, 305, 0, "items/chainmail_boots.png"),
+ I_306_0_IRON_HELMET("iron_helmet", null, 306, 0, "items/iron_helmet.png"),
+ I_307_0_IRON_CHESTPLATE("iron_chestplate", null, 307, 0, "items/iron_chestplate.png"),
+ I_308_0_IRON_LEGGINGS("iron_leggings", null, 308, 0, "items/iron_leggings.png"),
+ I_309_0_IRON_BOOTS("iron_boots", null, 309, 0, "items/iron_boots.png"),
+ I_310_0_DIAMOND_HELMET("diamond_helmet", null, 310, 0, "items/diamond_helmet.png"),
+ I_311_0_DIAMOND_CHESTPLATE("diamond_chestplate", null, 311, 0, "items/diamond_chestplate.png"),
+ I_312_0_DIAMOND_LEGGINGS("diamond_leggings", null, 312, 0, "items/diamond_leggings.png"),
+ I_313_0_DIAMOND_BOOTS("diamond_boots", null, 313, 0, "items/diamond_boots.png"),
+ I_314_0_GOLDEN_HELMET("golden_helmet", null, 314, 0, "items/golden_helmet.png"),
+ I_315_0_GOLDEN_CHESTPLATE("golden_chestplate", null, 315, 0, "items/golden_chestplate.png"),
+ I_316_0_GOLDEN_LEGGINGS("golden_leggings", null, 316, 0, "items/golden_leggings.png"),
+ I_317_0_GOLDEN_BOOTS("golden_boots", null, 317, 0, "items/golden_boots.png"),
+ I_318_0_FLINT("flint", null, 318, 0, "items/flint.png"),
+ I_319_0_PORKCHOP("porkchop", null, 319, 0, "items/porkchop.png"),
+ I_320_0_COOKED_PORKCHOP("cooked_porkchop", null, 320, 0, "items/cooked_porkchop.png"),
+ I_321_0_PAINTING("painting", null, 321, 0, "items/painting.png"),
+ I_322_0_GOLDEN_APPLE("golden_apple", null, 322, 0, "items/golden_apple.png"),
+ I_323_0_SIGN("sign", null, 323, 0, "items/sign.png"),
+ I_324_0_WOODEN_DOOR("wooden_door", null, 324, 0, "items/wooden_door.png"),
+ I_325_0_BUCKET_BUCKET("bucket", "bucket", 325, 0, "items/bucket_bucket.png"),
+ I_325_1_BUCKET_MILK("bucket", "milk", 325, 1, "items/bucket_milk.png"),
+ I_325_8_BUCKET_BUCKET_WATER("bucket", "bucket_water", 325, 8, "items/bucket_bucket_water.png"),
+ I_325_10_BUCKET_BUCKET_LAVA("bucket", "bucket_lava", 325, 10, "items/bucket_bucket_lava.png"),
+ I_328_0_MINECART("minecart", null, 328, 0, "items/minecart.png"),
+ I_329_0_SADDLE("saddle", null, 329, 0, "items/saddle.png"),
+ I_330_0_IRON_DOOR("iron_door", null, 330, 0, "items/iron_door.png"),
+ I_331_0_REDSTONE("redstone", null, 331, 0, "items/redstone.png"),
+ I_332_0_SNOWBALL("snowball", null, 332, 0, "items/snowball.png"),
+ I_333_0_BOAT_OAK("boat", "oak", 333, 0, "items/boat_oak.png"),
+ I_333_1_BOAT_SPRUCE("boat", "spruce", 333, 1, "items/boat_spruce.png"),
+ I_333_2_BOAT_BIRCH("boat", "birch", 333, 2, "items/boat_birch.png"),
+ I_333_3_BOAT_JUNGLE("boat", "jungle", 333, 3, "items/boat_jungle.png"),
+ I_333_4_BOAT_ACACIA("boat", "acacia", 333, 4, "items/boat_acacia.png"),
+ I_333_5_BOAT_BIG_OAK("boat", "big_oak", 333, 5, "items/boat_big_oak.png"),
+ I_334_0_LEATHER("leather", null, 334, 0, "items/leather.png"),
+ I_336_0_BRICK("brick", null, 336, 0, "items/brick.png"),
+ I_337_0_CLAY_BALL("clay_ball", null, 337, 0, "items/clay_ball.png"),
+ I_338_0_REEDS("reeds", null, 338, 0, "items/reeds.png"),
+ I_339_0_PAPER("paper", null, 339, 0, "items/paper.png"),
+ I_340_0_BOOK("book", null, 340, 0, "items/book.png"),
+ I_341_0_SLIME_BALL("slime_ball", null, 341, 0, "items/slime_ball.png"),
+ I_342_0_CHEST_MINECART("chest_minecart", null, 342, 0, "items/chest_minecart.png"),
+ I_344_0_EGG("egg", null, 344, 0, "items/egg.png"),
+ I_345_0_COMPASS("compass", null, 345, 0, "items/compass.png"),
+ I_346_0_FISHING_ROD("fishing_rod", null, 346, 0, "items/fishing_rod.png"),
+ I_347_0_CLOCK("clock", null, 347, 0, "items/clock.png"),
+ I_348_0_GLOWSTONE_DUST("glowstone_dust", null, 348, 0, "items/glowstone_dust.png"),
+ I_349_0_FISH("fish", null, 349, 0, "items/fish.png"),
+ I_350_0_COOKED_FISH("cooked_fish", null, 350, 0, "items/cooked_fish.png"),
+ I_351_0_DYE_BLACKINKSAC("dye", "black", 351, 0, "items/dye_powder_black.png"),
+ I_351_1_DYE_RED("dye", "red", 351, 1, "items/dye_powder_red.png"),
+ I_351_2_DYE_GREEN("dye", "green", 351, 2, "items/dye_powder_green.png"),
+ I_351_3_DYE_BROWNCOCOABEANS("dye", "brown", 351, 3, "items/dye_powder_brown.png"),
+ I_351_4_DYE_BLUE("dye", "blue", 351, 4, "items/dye_powder_blue.png"),
+ I_351_5_DYE_PURPLE("dye", "purple", 351, 5, "items/dye_powder_purple.png"),
+ I_351_6_DYE_CYAN("dye", "cyan", 351, 6, "items/dye_powder_cyan.png"),
+ I_351_7_DYE_SILVER("dye", "silver", 351, 7, "items/dye_powder_silver.png"),
+ I_351_8_DYE_GRAY("dye", "gray", 351, 8, "items/dye_powder_gray.png"),
+ I_351_9_DYE_PINK("dye", "pink", 351, 9, "items/dye_powder_pink.png"),
+ I_351_10_DYE_LIME("dye", "lime", 351, 10, "items/dye_powder_lime.png"),
+ I_351_11_DYE_YELLOW("dye", "yellow", 351, 11, "items/dye_powder_yellow.png"),
+ I_351_12_DYE_LIGHT_BLUE("dye", "light_blue", 351, 12, "items/dye_powder_light_blue.png"),
+ I_351_13_DYE_MAGENTA("dye", "magenta", 351, 13, "items/dye_powder_magenta.png"),
+ I_351_14_DYE_ORANGE("dye", "orange", 351, 14, "items/dye_powder_orange.png"),
+ I_351_15_DYE_WHITEBONEMEAL("dye", "white", 351, 15, "items/dye_powder_white.png"),
+ I_352_0_BONE("bone", null, 352, 0, "items/bone.png"),
+ I_353_0_SUGAR("sugar", null, 353, 0, "items/sugar.png"),
+ I_354_0_CAKE("cake", null, 354, 0, "items/cake.png"),
+ I_355_0_BED("bed", null, 355, 0, "items/bed.png"),
+ I_356_0_REPEATER("repeater", null, 356, 0, "items/repeater.png"),
+ I_357_0_COOKIE("cookie", null, 357, 0, "items/cookie.png"),
+ I_358_0_MAP_FILLED("map_filled", null, 358, 0, "items/map_filled.png"),
+ I_359_0_SHEARS("shears", null, 359, 0, "items/shears.png"),
+ I_360_0_MELON("melon", null, 360, 0, "items/melon.png"),
+ I_361_0_PUMPKIN_SEEDS("pumpkin_seeds", null, 361, 0, "items/pumpkin_seeds.png"),
+ I_362_0_MELON_SEEDS("melon_seeds", null, 362, 0, "items/melon_seeds.png"),
+ I_363_0_BEEF("beef", null, 363, 0, "items/beef.png"),
+ I_364_0_COOKED_BEEF("cooked_beef", null, 364, 0, "items/cooked_beef.png"),
+ I_365_0_CHICKEN("chicken", null, 365, 0, "items/chicken.png"),
+ I_366_0_COOKED_CHICKEN("cooked_chicken", null, 366, 0, "items/cooked_chicken.png"),
+ I_367_0_ROTTEN_FLESH("rotten_flesh", null, 367, 0, "items/rotten_flesh.png"),
+ I_368_0_ENDER_PEARL("ender_pearl", null, 368, 0, "items/ender_pearl.png"),
+ I_369_0_BLAZE_ROD("blaze_rod", null, 369, 0, "items/blaze_rod.png"),
+ I_370_0_GHAST_TEAR("ghast_tear", null, 370, 0, "items/ghast_tear.png"),
+ I_371_0_GOLD_NUGGET("gold_nugget", null, 371, 0, "items/gold_nugget.png"),
+ I_372_0_NETHER_WART("nether_wart", null, 372, 0, "items/nether_wart.png"),
+ I_373_0_POTION("potion", null, 373, 0, "items/potion.png"),
+ I_374_0_GLASS_BOTTLE("glass_bottle", null, 374, 0, "items/glass_bottle.png"),
+ I_375_0_SPIDER_EYE("spider_eye", null, 375, 0, "items/spider_eye.png"),
+ I_376_0_FERMENTED_SPIDER_EYE("fermented_spider_eye", null, 376, 0, "items/fermented_spider_eye.png"),
+ I_377_0_BLAZE_POWDER("blaze_powder", null, 377, 0, "items/blaze_powder.png"),
+ I_378_0_MAGMA_CREAM("magma_cream", null, 378, 0, "items/magma_cream.png"),
+ I_379_0_BREWING_STAND("brewing_stand", null, 379, 0, "items/brewing_stand.png"),
+ I_380_0_CAULDRON("cauldron", null, 380, 0, "items/cauldron.png"),
+ I_381_0_ENDER_EYE("ender_eye", null, 381, 0, "items/ender_eye.png"),
+ I_382_0_SPECKLED_MELON("speckled_melon", null, 382, 0, "items/speckled_melon.png"),
+ I_383_0_SPAWN_EGG("spawn_egg", null, 383, 0, "items/spawn_egg.png"),
+ I_384_0_EXPERIENCE_BOTTLE("experience_bottle", null, 384, 0, "items/experience_bottle.png"),
+ I_385_0_FIREBALL("fireball", null, 385, 0, "items/fireball.png"),
+ I_388_0_EMERALD("emerald", null, 388, 0, "items/emerald.png"),
+ I_389_0_FRAME("frame", null, 389, 0, "items/frame.png"),
+ I_390_0_FLOWER_POT("flower_pot", null, 390, 0, "items/flower_pot.png"),
+ I_391_0_CARROT("carrot", null, 391, 0, "items/carrot.png"),
+ I_392_0_POTATO("potato", null, 392, 0, "items/potato.png"),
+ I_393_0_BAKED_POTATO("baked_potato", null, 393, 0, "items/baked_potato.png"),
+ I_394_0_POISONOUS_POTATO("poisonous_potato", null, 394, 0, "items/poisonous_potato.png"),
+ I_395_0_EMPTYMAP("emptyMap", null, 395, 0, "items/emptyMap.png"),
+ I_396_0_GOLDEN_CARROT("golden_carrot", null, 396, 0, "items/golden_carrot.png"),
+ I_397_0_SKULL_SKELETON("skull", "skeleton", 397, 0, "items/skull_skeleton.png"),
+ I_397_1_SKULL_WITHER("skull", "wither", 397, 1, "items/skull_wither.png"),
+ I_397_2_SKULL_ZOMBIE("skull", "zombie", 397, 2, "items/skull_zombie.png"),
+ I_397_3_SKULL_PLAYER("skull", "player", 397, 3, "items/skull_player.png"),
+ I_397_4_SKULL_CREEPER("skull", "creeper", 397, 4, "items/skull_creeper.png"),
+ I_397_5_SKULL_DRAGON("skull", "dragon", 397, 5, "items/skull_dragon.png"),
+ I_398_0_CARROTONASTICK("carrotOnAStick", null, 398, 0, "items/carrotOnAStick.png"),
+ I_399_0_NETHERSTAR("netherStar", null, 399, 0, "items/netherStar.png"),
+ I_400_0_PUMPKIN_PIE("pumpkin_pie", null, 400, 0, "items/pumpkin_pie.png"),
+ I_403_0_ENCHANTED_BOOK("enchanted_book", null, 403, 0, "items/enchanted_book.png"),
+ I_404_0_COMPARATOR("comparator", null, 404, 0, "items/comparator.png"),
+ I_405_0_NETHERBRICK("netherbrick", null, 405, 0, "items/netherbrick.png"),
+ I_406_0_QUARTZ("quartz", null, 406, 0, "items/quartz.png"),
+ I_407_0_TNT_MINECART("tnt_minecart", null, 407, 0, "items/tnt_minecart.png"),
+ I_408_0_HOPPER_MINECART("hopper_minecart", null, 408, 0, "items/hopper_minecart.png"),
+ I_409_0_PRISMARINE_SHARD("prismarine_shard", null, 409, 0, "items/prismarine_shard.png"),
+ I_410_0_HOPPER("hopper", null, 410, 0, "items/hopper.png"),
+ I_411_0_RABBIT("rabbit", null, 411, 0, "items/rabbit.png"),
+ I_412_0_COOKED_RABBIT("cooked_rabbit", null, 412, 0, "items/cooked_rabbit.png"),
+ I_413_0_RABBIT_STEW("rabbit_stew", null, 413, 0, "items/rabbit_stew.png"),
+ I_414_0_RABBIT_FOOT("rabbit_foot", null, 414, 0, "items/rabbit_foot.png"),
+ I_415_0_RABBIT_HIDE("rabbit_hide", null, 415, 0, "items/rabbit_hide.png"),
+ I_416_0_HORSEARMORLEATHER("horsearmorleather", null, 416, 0, "items/horsearmorleather.png"),
+ I_417_0_HORSEARMORIRON("horsearmoriron", null, 417, 0, "items/horsearmoriron.png"),
+ I_418_0_HORSEARMORGOLD("horsearmorgold", null, 418, 0, "items/horsearmorgold.png"),
+ I_419_0_HORSEARMORDIAMOND("horsearmordiamond", null, 419, 0, "items/horsearmordiamond.png"),
+ I_420_0_LEAD("lead", null, 420, 0, "items/lead.png"),
+ I_421_0_NAMETAG("nameTag", null, 421, 0, "items/nameTag.png"),
+ I_422_0_PRISMARINE_CRYSTALS("prismarine_crystals", null, 422, 0, "items/prismarine_crystals.png"),
+ I_423_0_MUTTONRAW("muttonRaw", null, 423, 0, "items/muttonRaw.png"),
+ I_424_0_MUTTONCOOKED("muttonCooked", null, 424, 0, "items/muttonCooked.png"),
+ I_426_0_END_CRYSTAL("end_crystal", null, 426, 0, "items/end_crystal.png"),
+ I_427_0_SPRUCE_DOOR("spruce_door", null, 427, 0, "items/spruce_door.png"),
+ I_428_0_BIRCH_DOOR("birch_door", null, 428, 0, "items/birch_door.png"),
+ I_429_0_JUNGLE_DOOR("jungle_door", null, 429, 0, "items/jungle_door.png"),
+ I_430_0_ACACIA_DOOR("acacia_door", null, 430, 0, "items/acacia_door.png"),
+ I_431_0_DARK_OAK_DOOR("dark_oak_door", null, 431, 0, "items/dark_oak_door.png"),
+ I_432_0_CHORUS_FRUIT("chorus_fruit", null, 432, 0, "items/chorus_fruit.png"),
+ I_433_0_CHORUS_FRUIT_POPPED("chorus_fruit_popped", null, 433, 0, "items/chorus_fruit_popped.png"),
+ I_437_0_DRAGON_BREATH("dragon_breath", null, 437, 0, "items/dragon_breath.png"),
+ I_438_0_SPLASH_POTION("splash_potion", null, 438, 0, "items/splash_potion.png"),
+ I_441_0_LINGERING_POTION("lingering_potion", null, 441, 0, "items/lingering_potion.png"),
+ I_444_0_ELYTRA("elytra", null, 444, 0, "items/elytra.png"),
+ I_457_0_BEETROOT("beetroot", null, 457, 0, "items/beetroot.png"),
+ I_458_0_BEETROOT_SEEDS("beetroot_seeds", null, 458, 0, "items/seeds_beetroot.png"),
+ I_459_0_BEETROOT_SOUP("beetroot_soup", null, 459, 0, "items/beetroot_soup.png"),
+ I_460_0_SALMON("salmon", null, 460, 0, "items/fish_salmon.png"),
+ I_461_0_CLOWNFISH("clownfish", null, 461, 0, "items/fish_clownfish.png"),
+ I_462_0_PUFFERFISH("pufferfish", null, 462, 0, "items/fish_pufferfish.png"),
+ I_463_0_COOKED_SALMON("cooked_salmon", null, 463, 0, "items/fish_salmon_cooked.png"),
+ I_466_0_APPLEENCHANTED("apple_enchanted", null, 466, 0, "items/apple_golden.png"),
+ I_454_0_BOARD_ONE_BY_ONE("board", "one_by_one", 454, 0, "items/chalkboard_small.png"),
+ I_454_1_BOARD_TWO_BY_ONE("board", "two_by_one", 454, 1, "items/chalkboard_medium.png"),
+ I_454_2_BOARD_THREE_BY_TWO("board", "three_by_two", 454, 2, "items/chalkboard_large.png"),
+ I_456_0_PORTFOLIO("portfolio", null, 456, 0, "items/portfolio.png"),
+ I_498_0_CAMERA("camera", null, 498, 0, "items/camera.png");
+
+ private static final Map byDataName = new HashMap<>();
+ private static final SparseArray> itemMap;
+
+ static {
+ itemMap = new SparseArray<>();
+ SparseArray- subMap;
+ for (Item b : Item.values()) {
+ subMap = itemMap.get(b.id);
+ if (subMap == null) {
+ subMap = new SparseArray<>();
+ itemMap.put(b.id, subMap);
+ }
+ subMap.put(b.subId, b);
+ if (b.subId == 0) byDataName.put(b.str, b);
+ byDataName.put(b.str + "@" + b.subName, b);
+ }
+ }
+
+ public final int id, subId;
+ public final String str, subName, displayName, identifier;
+ public final String texPath;
+ public final ColorWrapper color;
+ public final boolean hasBiomeShading;
+ public Bitmap bitmap;
+
+ Item(String name, String subName, int id, int subId, String texPath) {
+ this.id = id;
+ this.subId = subId;
+ this.str = name;
+ this.subName = subName;
+ this.displayName = name + " " + subName;
+ this.texPath = texPath;
+ this.color = null;
+ this.hasBiomeShading = false;
+ this.identifier = "minecraft:" + subName;
+ }
+
+ public static Item getByDataName(String dataName) {
+ return byDataName.get(dataName);
+ }
+
+ public static void loadBitmaps(AssetManager assetManager) throws IOException {
+ for (Item b : Item.values()) {
+ if (b.bitmap == null && b.texPath != null) {
+ try {
+ b.bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(assetManager.open(b.texPath)), 32, 32, false);
+ } catch (FileNotFoundException e) {
+ //TODO file-paths were generated from item names; some do not actually exist...
+ //Log.w("File not found! "+b.texPath);
+ } catch (Exception e) {
+ Log.d(Item.class, e);
+ }
+ }
+ }
+ }
+
+ public static Item getItem(int id, int meta) {
+ if (id < 0) return null;
+ SparseArray
- subMap = itemMap.get(id);
+ if (subMap == null) return null;
+ else return subMap.get(meta);
+ }
+
+ public static Item getItemWithLegacyId(int id) {
+ if (id < 0) return null;
+ SparseArray
- subMap = itemMap.get(id);
+ if (subMap == null) return null;
+ return subMap.valueAt(0);
+ }
+
+ public static Item getItem(int runtimeId) {
+ int id = runtimeId >>> 8;
+ int data = runtimeId & 0xf;
+ return getItem(id, data);
+ }
+
+ @Override
+ public Bitmap getBitmap() {
+ return this.bitmap;
+ }
+
+ @NonNull
+ @Override
+ public NamedBitmapProvider getNamedBitmapProvider() {
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public String getBitmapDisplayName() {
+ return this.displayName;
+ }
+
+ @NonNull
+ @Override
+ public String getBitmapDataName() {
+ return str + "@" + subName;
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/MCTileProvider.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/MCTileProvider.java
index 0dd9dfb4..09b2628b 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/MCTileProvider.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/MCTileProvider.java
@@ -10,11 +10,14 @@
import android.text.TextPaint;
import com.mithrilmania.blocktopograph.WorldActivityInterface;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
import com.mithrilmania.blocktopograph.map.renderer.MapType;
import com.qozix.tileview.graphics.BitmapProvider;
import com.qozix.tileview.tiles.Tile;
+import java.lang.ref.WeakReference;
+
public class MCTileProvider implements BitmapProvider {
@@ -27,13 +30,41 @@ public class MCTileProvider implements BitmapProvider {
HALF_WORLDSIZE = 1 << 20;
public static int worldSizeInBlocks = 2 * HALF_WORLDSIZE,
- viewSizeW = worldSizeInBlocks * TILESIZE / Dimension.OVERWORLD.chunkW,
- viewSizeL = worldSizeInBlocks * TILESIZE / Dimension.OVERWORLD.chunkL;
+ viewSizeW = worldSizeInBlocks * TILESIZE / Dimension.OVERWORLD.chunkW,
+ viewSizeL = worldSizeInBlocks * TILESIZE / Dimension.OVERWORLD.chunkL;
- public final WorldActivityInterface worldProvider;
+ public final WeakReference
worldProvider;
- public MCTileProvider(WorldActivityInterface worldProvider){
- this.worldProvider = worldProvider;
+ public MCTileProvider(WorldActivityInterface worldProvider) {
+ this.worldProvider = new WeakReference<>(worldProvider);
+ }
+
+ public static Bitmap drawText(String text, Bitmap b, int textColor, int bgColor) {
+ // Get text dimensions
+ TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
+ textPaint.setStyle(Paint.Style.FILL);
+ textPaint.setColor(textColor);
+ textPaint.setTextSize(b.getHeight() / 16f);
+ StaticLayout mTextLayout = new StaticLayout(text, textPaint, b.getWidth() / 2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
+
+ // Create bitmap and canvas to draw to
+ Canvas c = new Canvas(b);
+
+ if (bgColor != 0) {
+ // Draw background
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(bgColor);
+ c.drawPaint(paint);
+ }
+
+ // Draw text
+ c.save();
+ c.translate(0, 0);
+ mTextLayout.draw(c);
+ c.restore();
+
+ return b;
}
@Override
@@ -43,14 +74,9 @@ public Bitmap getBitmap(Tile tile, Context context) {
try {
-
- // column and row range from 0 to (worldsize/tilesize) * scale
-
- Dimension dimension = worldProvider.getDimension();
-
// 1 chunk per tile on scale 1.0
- int pixelsPerBlockW_unscaled = TILESIZE / dimension.chunkW;
- int pixelsPerBlockL_unscaled = TILESIZE / dimension.chunkL;
+ int pixelsPerBlockW_unscaled = TILESIZE / 16;
+ int pixelsPerBlockL_unscaled = TILESIZE / 16;
float scale = tile.getDetailLevel().getScale();
@@ -64,27 +90,21 @@ public Bitmap getBitmap(Tile tile, Context context) {
// for translating to origin
// HALF_WORLDSIZE and TILESIZE must be a power of two
- int tilesInHalfWorldW = (HALF_WORLDSIZE * pixelsPerBlockW) / TILESIZE;
- int tilesInHalfWorldL = (HALF_WORLDSIZE * pixelsPerBlockL) / TILESIZE;
-
+ int tilesInHalfWorldW = (HALF_WORLDSIZE * pixelsPerBlockW) / TILESIZE;
+ int tilesInHalfWorldL = (HALF_WORLDSIZE * pixelsPerBlockL) / TILESIZE;
// translate tile coord to origin, multiply origin-relative-tile-coordinate with the chunks per tile
- int minChunkX = ( tile.getColumn() - tilesInHalfWorldW) * invScale;
- int minChunkZ = ( tile.getRow() - tilesInHalfWorldL) * invScale;
+ int minChunkX = (tile.getColumn() - tilesInHalfWorldW) * invScale;
+ int minChunkZ = (tile.getRow() - tilesInHalfWorldL) * invScale;
int maxChunkX = minChunkX + invScale;
int maxChunkZ = minChunkZ + invScale;
-
- //scale pixels to dimension scale (Nether 1 : 8 Overworld)
- pixelsPerBlockW *= dimension.dimensionScale;
- pixelsPerBlockL *= dimension.dimensionScale;
-
-
- ChunkManager cm = new ChunkManager(worldProvider.getWorld().getWorldData(), dimension);
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+ Dimension dimension = worldProvider.getDimension();
MapType mapType = (MapType) tile.getDetailLevel().getLevelType();
- if(mapType == null) return null;
+ if (mapType == null) return null;
int x, z, pX, pY;
@@ -92,93 +112,65 @@ public Bitmap getBitmap(Tile tile, Context context) {
//check if the tile is not aligned with its inner chunks
//hacky: it must be a single chunk that is to big for the tile, render just the visible part, easy.
- int alignment = invScale % dimension.dimensionScale;
- if(alignment > 0){
-
- int chunkX = minChunkX / dimension.dimensionScale;
- if(minChunkX % dimension.dimensionScale < 0) chunkX -= 1;
- int chunkZ = minChunkZ / dimension.dimensionScale;
- if(minChunkZ % dimension.dimensionScale < 0) chunkZ -= 1;
-
- int stepX = dimension.chunkW / dimension.dimensionScale;
- int stepZ = dimension.chunkL / dimension.dimensionScale;
- int minX = (minChunkX % dimension.dimensionScale) * stepX;
- if(minX < 0) minX += dimension.chunkW;
- int minZ = (minChunkZ % dimension.dimensionScale) * stepZ;
- if(minZ < 0) minZ += dimension.chunkL;
- int maxX = (maxChunkX % dimension.dimensionScale) * stepX;
- if(maxX <= 0) maxX += dimension.chunkW;
- int maxZ = (maxChunkZ % dimension.dimensionScale) * stepZ;
- if(maxZ <= 0) maxZ += dimension.chunkL;
-
-
- tileTxt = chunkX+";"+chunkZ+" ("+((chunkX*dimension.chunkW)+minX)+"; "+((chunkZ*dimension.chunkL)+minZ)+")";
-
-
- mapType.renderer.renderToBitmap(cm, bm, dimension,
- chunkX, chunkZ,
- minX, minZ ,
- maxX, maxZ,
- 0, 0,
- pixelsPerBlockW, pixelsPerBlockL);
-
- } else {
-
- minChunkX /= dimension.dimensionScale;
- minChunkZ /= dimension.dimensionScale;
- maxChunkX /= dimension.dimensionScale;
- maxChunkZ /= dimension.dimensionScale;
-
- tileTxt = "("+(minChunkX*dimension.chunkW)+"; "+(minChunkZ*dimension.chunkL)+")";
-
-
- int pixelsPerChunkW = pixelsPerBlockW * dimension.chunkW;
- int pixelsPerChunkL = pixelsPerBlockL * dimension.chunkL;
-
- for(z = minChunkZ, pY = 0; z < maxChunkZ; z++, pY += pixelsPerChunkL){
-
- for(x = minChunkX, pX = 0; x < maxChunkX; x++, pX += pixelsPerChunkW){
-
- try {
- mapType.renderer.renderToBitmap(cm, bm, dimension,
- x, z,
- 0, 0,
- dimension.chunkW, dimension.chunkL,
- pX, pY,
- pixelsPerBlockW, pixelsPerBlockL);
- } catch (Exception e){
- MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension,
- x, z,
- 0, 0,
- dimension.chunkW, dimension.chunkL,
- pX, pY,
- pixelsPerBlockW, pixelsPerBlockL);
- e.printStackTrace();
- }
+
+ tileTxt = "(" + (minChunkX * 16) + "; " + (minChunkZ * 16) + ")";
+
+
+ int pixelsPerChunkW = pixelsPerBlockW * 16;
+ int pixelsPerChunkL = pixelsPerBlockL * 16;
+
+ Canvas canvas = new Canvas(bm);
+ Paint paint = new Paint();
+
+ WorldData worldData = worldProvider.getWorld().getWorldData();
+
+ for (z = minChunkZ, pY = 0; z < maxChunkZ; z++, pY += pixelsPerChunkL)
+ for (x = minChunkX, pX = 0; x < maxChunkX; x++, pX += pixelsPerChunkW) {
+
+ Chunk chunk = worldData.getChunk(x, z, dimension);
+ if (chunk.isError()) {
+ MapType.ERROR.renderer.renderToBitmap(chunk, canvas, dimension,
+ x, z, pX, pY, pixelsPerBlockW, pixelsPerBlockL, paint, worldData);
+ continue;
}
+ MapType.CHESS.renderer.renderToBitmap(chunk, canvas, dimension,
+ x, z, pX, pY, pixelsPerBlockW, pixelsPerBlockL, paint, worldData);
+ if (chunk.isVoid()) continue;
+ try {
+ mapType.renderer.renderToBitmap(chunk, canvas, dimension, x, z,
+ pX, pY, pixelsPerBlockW, pixelsPerBlockL, paint, worldData);
+
+ } catch (Exception e) {
+
+ MapType.ERROR.renderer.renderToBitmap(chunk, canvas, dimension,
+ x, z, pX, pY, pixelsPerBlockW, pixelsPerBlockL, paint, worldData);
+ e.printStackTrace();
+
+ }
+
}
- }
//load all those markers with an async task, this task publishes its progress,
// the UI thread picks it up and renders the markers
- new MarkerAsyncTask(worldProvider, cm, minChunkX, minChunkZ, maxChunkX, maxChunkZ).execute();
+ if (worldProvider.getShowMarkers())
+ new MarkerAsyncTask(worldProvider, minChunkX, minChunkZ, maxChunkX, maxChunkZ, dimension).execute();
//draw the grid
- if(worldProvider.getShowGrid()){
+ if (worldProvider.getShowGrid()) {
//draw tile-edges white
- for(int i = 0; i < TILESIZE; i++){
+ for (int i = 0; i < TILESIZE; i++) {
//horizontal edges
bm.setPixel(i, 0, Color.WHITE);
- bm.setPixel(i, TILESIZE-1, Color.WHITE);
+ bm.setPixel(i, TILESIZE - 1, Color.WHITE);
//vertical edges
bm.setPixel(0, i, Color.WHITE);
- bm.setPixel(TILESIZE-1, i, Color.WHITE);
+ bm.setPixel(TILESIZE - 1, i, Color.WHITE);
}
@@ -186,7 +178,7 @@ public Bitmap getBitmap(Tile tile, Context context) {
drawText(tileTxt, bm, Color.WHITE, 0);
}
- } catch(Exception e) {
+ } catch (Exception e) {
e.printStackTrace();
}
@@ -195,33 +187,4 @@ public Bitmap getBitmap(Tile tile, Context context) {
}
- public static Bitmap drawText(String text, Bitmap b, int textColor, int bgColor) {
- // Get text dimensions
- TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
- textPaint.setStyle(Paint.Style.FILL);
- textPaint.setColor(textColor);
- textPaint.setTextSize(b.getHeight() / 16f);
- StaticLayout mTextLayout = new StaticLayout(text, textPaint, b.getWidth() / 2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
-
- // Create bitmap and canvas to draw to
- Canvas c = new Canvas(b);
-
- if(bgColor != 0){
- // Draw background
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
- paint.setStyle(Paint.Style.FILL);
- paint.setColor(bgColor);
- c.drawPaint(paint);
- }
-
- // Draw text
- c.save();
- c.translate(0, 0);
- mTextLayout.draw(c);
- c.restore();
-
- return b;
- }
-
-
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/MapFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/MapFragment.java
index 8ab1368f..2c369ef2 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/MapFragment.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/MapFragment.java
@@ -1,25 +1,21 @@
package com.mithrilmania.blocktopograph.map;
-import android.annotation.SuppressLint;
import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.widget.Snackbar;
-import com.mithrilmania.blocktopograph.Log;
-
-import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.util.DisplayMetrics;
+import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@@ -30,22 +26,40 @@
import android.widget.TextView;
import android.widget.Toast;
-import com.github.clans.fab.FloatingActionButton;
-import com.github.clans.fab.FloatingActionMenu;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.view.ContextThemeWrapper;
+import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
+
+import com.google.android.material.snackbar.Snackbar;
+import com.mithrilmania.blocktopograph.Log;
import com.mithrilmania.blocktopograph.R;
import com.mithrilmania.blocktopograph.World;
-import com.mithrilmania.blocktopograph.WorldActivity;
import com.mithrilmania.blocktopograph.WorldActivityInterface;
-import com.mithrilmania.blocktopograph.WorldData;
-import com.mithrilmania.blocktopograph.chunk.*;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+import com.mithrilmania.blocktopograph.chunk.ChunkTag;
+import com.mithrilmania.blocktopograph.chunk.NBTChunkData;
+import com.mithrilmania.blocktopograph.databinding.MapFragmentBinding;
+import com.mithrilmania.blocktopograph.map.edit.EditFunction;
+import com.mithrilmania.blocktopograph.map.edit.RectEditTarget;
+import com.mithrilmania.blocktopograph.map.edit.SelectionBasedContextFreeEditTask;
+import com.mithrilmania.blocktopograph.map.locator.AdvancedLocatorFragment;
import com.mithrilmania.blocktopograph.map.marker.AbstractMarker;
import com.mithrilmania.blocktopograph.map.marker.CustomNamedBitmapProvider;
import com.mithrilmania.blocktopograph.map.marker.MarkerImageView;
+import com.mithrilmania.blocktopograph.map.picer.PicerFragment;
import com.mithrilmania.blocktopograph.map.renderer.MapType;
+import com.mithrilmania.blocktopograph.map.selection.SelectionMenuFragment;
import com.mithrilmania.blocktopograph.nbt.EditableNBT;
-import com.mithrilmania.blocktopograph.nbt.convert.DataConverter;
-import com.mithrilmania.blocktopograph.nbt.convert.NBTConstants;
import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
import com.mithrilmania.blocktopograph.nbt.tags.FloatTag;
import com.mithrilmania.blocktopograph.nbt.tags.IntTag;
@@ -53,17 +67,14 @@
import com.mithrilmania.blocktopograph.nbt.tags.Tag;
import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
import com.mithrilmania.blocktopograph.util.NamedBitmapProviderHandle;
-import com.mithrilmania.blocktopograph.util.ViewID;
import com.mithrilmania.blocktopograph.util.math.DimensionVector3;
-import com.qozix.tileview.TileView;
import com.qozix.tileview.detail.DetailLevelManager;
import com.qozix.tileview.markers.MarkerLayout;
import java.io.IOException;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -76,39 +87,72 @@
public class MapFragment extends Fragment {
- private WorldActivityInterface worldProvider;
+ private final static int MARKER_INTERVAL_CHECK = 50;
+ private static final String TAG_PICER = "picer";
+ private static final int MARKERS_ON_SCREEN_TOO_MANY = 100;
+ private static final String PREF_KEY_HAS_NOTIFIED_MARKERS_TOO_MANY = "has_notified_markers_too_many";
+ private static final String PREF_KEY_HAS_USED_SELECTION = "hasUsedSelection";
+ private static final String KEY_HAS_DOUBLE_TAP = "hasDoubleTap";
+ //static, remember choice while app is open.
+ private static Map markerFilter = new HashMap<>();
- private MCTileProvider minecraftTileProvider;
+ static {
+ //entities are enabled by default
+ for (Entity v : Entity.values()) {
+ //skip things without a bitmap (dropped items etc.)
+ //skip entities with placeholder ids (900+)
+ if (v.sheetPos < 0 || v.id >= 900) continue;
+ markerFilter.put(v.getNamedBitmapProvider(),
+ new BitmapChoiceListAdapter.NamedBitmapChoice(v, true));
+ }
+ //tile-entities are disabled by default
+ for (TileEntity v : TileEntity.values()) {
+ markerFilter.put(v.getNamedBitmapProvider(),
+ new BitmapChoiceListAdapter.NamedBitmapChoice(v, false));
+ }
- private TileView tileView;
+ }
//procedural markers can be iterated while other threads add things to it;
// iterating performance is not really affected because of the small size;
- public CopyOnWriteArraySet proceduralMarkers = new CopyOnWriteArraySet<>();
+ private CopyOnWriteArraySet proceduralMarkers = new CopyOnWriteArraySet<>();
- public Set staticMarkers = new HashSet<>();
-
- public AbstractMarker spawnMarker;
- public AbstractMarker localPlayerMarker;
+ private Set staticMarkers = new HashSet<>();
+ private AbstractMarker spawnMarker;
+ private AbstractMarker localPlayerMarker;
+ private WeakReference worldProvider;
+ public World world;
+ private MCTileProvider minecraftTileProvider;
+ private int proceduralMarkersInterval = 0;
+ private volatile AsyncTask shrinkProceduralMarkersTask;
+ /**
+ * Only one floating fragment is allowed at the same time.
+ * We use one to display locator.
+ */
+ private Fragment mFloatingFragment;
+ /**
+ * Data binding of this fragment view.
+ */
+ private MapFragmentBinding mBinding;
@Override
public void onPause() {
super.onPause();
//pause drawing the map
- this.tileView.pause();
+ mBinding.tileView.pause();
}
@Override
public void onStart() {
super.onStart();
-
- getActivity().setTitle(this.worldProvider.getWorld().getWorldDisplayName());
-
- worldProvider.logFirebaseEvent(WorldActivity.CustomFirebaseEvent.MAPFRAGMENT_OPEN);
+ FragmentActivity activity = getActivity();
+ if (activity == null) return;
+ activity.setTitle(world.getWorldDisplayName());
+ Log.logFirebaseEvent(activity, Log.CustomFirebaseEvent.MAPFRAGMENT_OPEN);
}
@Override
@@ -116,9 +160,18 @@ public void onResume() {
super.onResume();
//resume drawing the map
- this.tileView.resume();
+ mBinding.tileView.resume();
+ FragmentActivity activity = getActivity();
+ if (activity == null) return;
+
+// Toast toast = new Toast(activity);
+// toast.setView(getLayoutInflater().inflate(R.layout.toast_warn, (ViewGroup) activity.getWindow().getDecorView(), false));
+// toast.setDuration(Toast.LENGTH_LONG);
+// toast.show();
+ }
- worldProvider.logFirebaseEvent(WorldActivity.CustomFirebaseEvent.MAPFRAGMENT_RESUME);
+ public void closeChunks() {
+ world.getWorldData().resetCache();
}
@Override
@@ -126,684 +179,450 @@ public void onDestroyView() {
super.onDestroyView();
}
-
- public DimensionVector3 getMultiPlayerPos(String dbKey) throws Exception {
- try {
- WorldData wData = worldProvider.getWorld().getWorldData();
- wData.openDB();
- byte[] data = wData.db.get(dbKey.getBytes(NBTConstants.CHARSET));
- if(data == null) throw new Exception("no data!");
- final CompoundTag player = (CompoundTag) DataConverter.read(data).get(0);
-
- ListTag posVec = (ListTag) player.getChildTagByKey("Pos");
- if (posVec == null || posVec.getValue() == null)
- throw new Exception("No \"Pos\" specified");
- if (posVec.getValue().size() != 3)
- throw new Exception("\"Pos\" value is invalid. value: " + posVec.getValue().toString());
-
- IntTag dimensionId = (IntTag) player.getChildTagByKey("DimensionId");
- if(dimensionId == null || dimensionId.getValue() == null)
- throw new Exception("No \"DimensionId\" specified");
- Dimension dimension = Dimension.getDimension(dimensionId.getValue());
- if(dimension == null) dimension = Dimension.OVERWORLD;
-
- return new DimensionVector3<>(
- (float) posVec.getValue().get(0).getValue(),
- (float) posVec.getValue().get(1).getValue(),
- (float) posVec.getValue().get(2).getValue(),
- dimension);
-
- } catch (Exception e) {
- Log.e(e.getMessage());
-
- Exception e2 = new Exception("Could not find "+dbKey);
- e2.setStackTrace(e.getStackTrace());
- throw e2;
+ private String[] getMarkerTapOptions() {
+ MarkerTapOption[] values = MarkerTapOption.values();
+ int len = values.length;
+ String[] options = new String[len];
+ for (int i = 0; i < len; i++) {
+ options[i] = getString(values[i].stringId);
}
+ return options;
}
- public DimensionVector3 getPlayerPos() throws Exception {
+ /**
+ * Move map viewer camera to local player's position.
+ *
+ *
+ * Triggered by fab click action.
+ *
+ *
+ * @param view no use. Yes we pass it to snack maker, but we can just use root view instead.
+ */
+ @UiThread
+ private void moveCameraToPlayer(View view) {
+// if (Math.random() < 2) {
+// try {
+// Chunk chunk = world.getWorldData().getChunk(0, 0, Dimension.OVERWORLD);
+// //byte[] arr = world.getWorldData().getChunkData(0, 0, ChunkTag.TERRAIN, Dimension.OVERWORLD, (byte) 0, true);
+// //V1d2d13TerrainSubChunk subChunk = new V1d2d13TerrainSubChunk(ByteBuffer.wrap(arr));
+// for (int z = 0; z < 16; z++)
+// chunk.setBlock(0, 6, z, 0, KnownBlockRepr.B_5_0_PLANKS_OAK.getRuntimeId());
+// chunk.save();//world.getWorldData(), 0, 0, Dimension.OVERWORLD, 1);
+// Log.d(this, "ok");
+// } catch (Exception e) {
+// Log.d(this, e);
+// }
+// return;
+// }
try {
- WorldData wData = worldProvider.getWorld().getWorldData();
- wData.openDB();
- byte[] data = wData.db.get(World.SpecialDBEntryType.LOCAL_PLAYER.keyBytes);
- final CompoundTag player = data != null
- ? (CompoundTag) DataConverter.read(data).get(0)
- : (CompoundTag) worldProvider.getWorld().level.getChildTagByKey("Player");
+ Activity activity = getActivity();
+ if (activity == null) return;
- ListTag posVec = (ListTag) player.getChildTagByKey("Pos");
- if (posVec == null || posVec.getValue() == null)
- throw new Exception("No \"Pos\" specified");
- if (posVec.getValue().size() != 3)
- throw new Exception("\"Pos\" value is invalid. value: " + posVec.getValue().toString());
+ DimensionVector3 playerPos = world.getPlayerPos();
- IntTag dimensionId = (IntTag) player.getChildTagByKey("DimensionId");
- if(dimensionId == null || dimensionId.getValue() == null)
- throw new Exception("No \"DimensionId\" specified");
- Dimension dimension = Dimension.getDimension(dimensionId.getValue());
- if(dimension == null) dimension = Dimension.OVERWORLD;
+ assert playerPos != null;
+ Snackbar.make(mBinding.tileView,
+ getString(R.string.something_at_xyz_dim_float, getString(R.string.player),
+ playerPos.x, playerPos.y, playerPos.z),
+ Snackbar.LENGTH_SHORT)
+ .setAction("Action", null).show();
- return new DimensionVector3<>(
- (float) posVec.getValue().get(0).getValue(),
- (float) posVec.getValue().get(1).getValue(),
- (float) posVec.getValue().get(2).getValue(),
- dimension);
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+ if (playerPos.dimension != worldProvider.getDimension()) {
+ worldProvider.changeMapType(playerPos.dimension.defaultMapType, playerPos.dimension);
+ }
+ Log.logFirebaseEvent(activity, Log.CustomFirebaseEvent.GPS_LOCATE);
- } catch (Exception e) {
- Log.e(e.toString());
+ frameTo((double) playerPos.x, (double) playerPos.z);
- Exception e2 = new Exception("Could not find player.");
- e2.setStackTrace(e.getStackTrace());
- throw e2;
+ } catch (Exception e) {
+ Log.d(this, e);
+ Snackbar.make(view, R.string.failed_find_player, Snackbar.LENGTH_LONG)
+ .show();
}
}
- public DimensionVector3 getSpawnPos() throws Exception {
+ /**
+ * Move map viewer camera to world spawn position.
+ *
+ *
+ * Triggered by fab click action.
+ *
+ *
+ * @param view no use. Yes we pass it to snack maker, but we can just use root view instead.
+ */
+ @UiThread
+ private void moveCameraToSpawn(View view) {
try {
- CompoundTag level = this.worldProvider.getWorld().level;
- int spawnX = ((IntTag) level.getChildTagByKey("SpawnX")).getValue();
- int spawnY = ((IntTag) level.getChildTagByKey("SpawnY")).getValue();
- int spawnZ = ((IntTag) level.getChildTagByKey("SpawnZ")).getValue();
- if(spawnY == 256){
- TerrainChunkData data = new ChunkManager(
- this.worldProvider.getWorld().getWorldData(), Dimension.OVERWORLD)
- .getChunk(spawnX >> 4, spawnZ >> 4)
- .getTerrain((byte) 0);
- if(data.load2DData()) spawnY = data.getHeightMapValue(spawnX % 16, spawnZ % 16) + 1;
- }
- return new DimensionVector3<>( spawnX, spawnY, spawnZ, Dimension.OVERWORLD);
- } catch (Exception e){
- throw new Exception("Could not find spawn");
- }
- }
-
- public static class MarkerListAdapter extends ArrayAdapter {
-
- MarkerListAdapter(Context context, List objects) {
- super(context, 0, objects);
- }
+ Activity activity = getActivity();
+ if (activity == null) return;
- @NonNull
- @Override
- public View getView(int position, View convertView, @NonNull ViewGroup parent) {
+ DimensionVector3 spawnPos = world.getSpawnPos();
- RelativeLayout v = (RelativeLayout) convertView;
+ Snackbar.make(mBinding.tileView,
+ getString(R.string.something_at_xyz_dim_int, getString(R.string.spawn),
+ spawnPos.x, spawnPos.y, spawnPos.z),
+ Snackbar.LENGTH_SHORT)
+ .setAction("Action", null).show();
- if (v == null) {
- LayoutInflater vi;
- vi = LayoutInflater.from(getContext());
- v = (RelativeLayout) vi.inflate(R.layout.marker_list_entry, parent, false);
+ WorldActivityInterface worldProvider = MapFragment.this.worldProvider.get();
+ if (spawnPos.dimension != worldProvider.getDimension()) {
+ worldProvider.changeMapType(spawnPos.dimension.defaultMapType, spawnPos.dimension);
}
- AbstractMarker m = getItem(position);
-
- if (m != null) {
- TextView name = (TextView) v.findViewById(R.id.marker_name);
- TextView xz = (TextView) v.findViewById(R.id.marker_xz);
- ImageView icon = (ImageView) v.findViewById(R.id.marker_icon);
-
- name.setText(m.getNamedBitmapProvider().getBitmapDisplayName());
- String xzStr = String.format(Locale.ENGLISH, "x: %d, y: %d, z: %d", m.x, m.y, m.z);
- xz.setText(xzStr);
-
- m.loadIcon(icon);
+ Log.logFirebaseEvent(activity, Log.CustomFirebaseEvent.GPS_LOCATE);
- }
+ frameTo((double) spawnPos.x, (double) spawnPos.z);
- return v;
+ } catch (Exception e) {
+ e.printStackTrace();
+ Snackbar.make(view, R.string.failed_find_spawn, Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
}
-
}
- public enum MarkerTapOption {
+ /**
+ * Callback to close the ongoing floating pane.
+ */
+ @UiThread
+ private void closeFloatPane() {
+ if (mFloatingFragment != null) {
+ FragmentManager fm = getChildFragmentManager();
+ FragmentTransaction trans = fm.beginTransaction();
+ trans.remove(mFloatingFragment);
+
+ // If in selection mode, recover selection menu.
+ if (mBinding.selectionBoard.hasSelection()) {
+ SelectionMenuFragment fragment = SelectionMenuFragment
+ .newInstance(mBinding.selectionBoard.getSelection(),
+ world.getWorldData().mOldBlockRegistry, this::doSelectionBasedEdit);
+ trans.add(R.id.float_window_container, fragment);
+ mFloatingFragment = fragment;
+ setUpSelectionMenu();
+ } else mFloatingFragment = null;
+
+ trans.commit();
+ }
+ }
- TELEPORT_LOCAL_PLAYER(R.string.teleport_local_player),
- REMOVE_MARKER(R.string.remove_custom_marker);
+ @Override
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mFloatingFragment != null) {
+ FloatPaneFragment fragment;
+ if (mFloatingFragment instanceof AdvancedLocatorFragment) {
+ fragment = AdvancedLocatorFragment.create(world, this::frameTo);
+ } else if (mFloatingFragment instanceof SelectionMenuFragment) {
+ fragment = SelectionMenuFragment
+ .newInstance(mBinding.selectionBoard.getSelection(), world.getWorldData().mOldBlockRegistry,
+ this::doSelectionBasedEdit);
+ } else return;
+ closeFloatPane();
+ openFloatPane(fragment);
+ setUpSelectionMenu();
+ }
+ }
- public final int stringId;
+ /**
+ * Set up selection menu and connect it with selection board.
+ *
+ *
+ * Called when selection mode begins, or when another float pane that used to be opened and
+ * replaced selection menu, we have to recover selection menu when the pane was dead.
+ *
+ */
+ private void setUpSelectionMenu() {
+ if (mFloatingFragment instanceof SelectionMenuFragment) {
+ SelectionMenuFragment fragment = (SelectionMenuFragment) mFloatingFragment;
+ mBinding.selectionBoard.setSelectionChangedListener(fragment::onSelectionChangedOutsides);
+ fragment.setSelectionChangedListener(mBinding.selectionBoard::onSelectionChangedOutsides);
+ }
+ }
- MarkerTapOption(int id){
- this.stringId = id;
+ /**
+ * When another float pane was opened and replaced selection menu, we disconnect selection
+ * menu and selection board.
+ */
+ private void unsetSelectionMenu() {
+ if (mFloatingFragment instanceof SelectionMenuFragment) {
+ SelectionMenuFragment fragment = (SelectionMenuFragment) mFloatingFragment;
+ fragment.setSelectionChangedListener(null);
}
+ mBinding.selectionBoard.setSelectionChangedListener(null);
+ }
+ /**
+ * Show a floating pane fragment. Will remove already existing one.
+ *
+ * @param fragment pane fragment to be attached.
+ */
+ @UiThread
+ private void openFloatPane(@NonNull FloatPaneFragment fragment) {
+ FragmentManager fm = getChildFragmentManager();
+ fragment.setOnCloseButtonClickListener(this::closeFloatPane);
+ FragmentTransaction trans = fm.beginTransaction();
+ // Remove existing float pane.
+ if (mFloatingFragment instanceof SelectionMenuFragment) unsetSelectionMenu();
+ if (mFloatingFragment != null) trans.remove(mFloatingFragment);
+ trans.add(R.id.float_window_container, fragment).commit();
+ mFloatingFragment = fragment;
}
- public String[] getMarkerTapOptions(){
- MarkerTapOption[] values = MarkerTapOption.values();
- int len = values.length;
- String[] options = new String[len];
- for(int i = 0; i < len; i++){
- options[i] = getString(values[i].stringId);
+ private void onOpenFab(View view) {
+ if (mBinding.fabMenu.isOpened())
+ mBinding.fabMenu.close(true);
+ else {
+ mBinding.fabMenu.open(true);
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ SharedPreferences preferences = activity.getPreferences(Context.MODE_PRIVATE);
+ if (!preferences
+ .getBoolean(KEY_HAS_DOUBLE_TAP, false)) {
+ Toast.makeText(activity, getString(R.string.map_dblclick_notice), Toast.LENGTH_SHORT).show();
+ preferences.edit().putBoolean(KEY_HAS_DOUBLE_TAP, true).apply();
+ }
+ }
}
- return options;
}
@Nullable
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//TODO handle savedInstance...
-
- View rootView = inflater.inflate(R.layout.map_fragment, container, false);
- RelativeLayout worldContainer = (RelativeLayout) rootView.findViewById(R.id.world_tileview_container);
- assert worldContainer != null;
-
- /*
- GPS button: moves camera to player position
- */
- FloatingActionButton fabGPSPlayer = (FloatingActionButton) rootView.findViewById(R.id.fab_menu_gps_player);
- assert fabGPSPlayer != null;
- fabGPSPlayer.setOnClickListener(new View.OnClickListener() {
+ mBinding = DataBindingUtil.inflate(
+ inflater, R.layout.map_fragment, container, false);
+ mBinding.tileView.setSelectionView(mBinding.selectionBoard);
+ mBinding.selectionBoard.setTileView(mBinding.tileView);
+ mBinding.tileView.setOuterDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
@Override
- public void onClick(View view) {
- try {
- if(tileView == null) throw new Exception("No map available.");
-
- DimensionVector3 playerPos = getPlayerPos();
-
- Snackbar.make(tileView,
- getString(R.string.something_at_xyz_dim_float, getString(R.string.player),
- playerPos.x, playerPos.y, playerPos.z, playerPos.dimension.name),
- Snackbar.LENGTH_SHORT)
- .setAction("Action", null).show();
-
- if(playerPos.dimension != worldProvider.getDimension()){
- worldProvider.changeMapType(playerPos.dimension.defaultMapType, playerPos.dimension);
- }
-
- worldProvider.logFirebaseEvent(WorldActivity.CustomFirebaseEvent.GPS_PLAYER);
-
- frameTo((double) playerPos.x, (double) playerPos.z);
-
- } catch (Exception e){
- e.printStackTrace();
- Snackbar.make(view, R.string.failed_find_player, Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ return false;
}
- });
- /*
- GPS button: moves camera to spawn
- */
- FloatingActionButton fabGPSSpawn = (FloatingActionButton) rootView.findViewById(R.id.fab_menu_gps_spawn);
- assert fabGPSSpawn != null;
- fabGPSSpawn.setOnClickListener(new View.OnClickListener() {
@Override
- public void onClick(View view) {
- try {
- DimensionVector3 spawnPos = getSpawnPos();
-
- Snackbar.make(tileView,
- getString(R.string.something_at_xyz_dim_int, getString(R.string.spawn),
- spawnPos.x, spawnPos.y, spawnPos.z, spawnPos.dimension.name),
- Snackbar.LENGTH_SHORT)
- .setAction("Action", null).show();
-
- if(spawnPos.dimension != worldProvider.getDimension()){
- worldProvider.changeMapType(spawnPos.dimension.defaultMapType, spawnPos.dimension);
- }
-
- worldProvider.logFirebaseEvent(WorldActivity.CustomFirebaseEvent.GPS_SPAWN);
-
- frameTo((double) spawnPos.x, (double) spawnPos.z);
+ public boolean onDoubleTap(MotionEvent e) {
+ worldProvider.get().openDrawer();
+ FragmentActivity activity = getActivity();
+ if (activity != null)
+ activity.getPreferences(Context.MODE_PRIVATE)
+ .edit().putBoolean(KEY_HAS_DOUBLE_TAP, true).apply();
+ return false;
+ }
- } catch (Exception e){
- e.printStackTrace();
- Snackbar.make(view, R.string.failed_find_spawn, Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
+ @Override
+ public boolean onDoubleTapEvent(MotionEvent e) {
+ return false;
}
});
-
final Activity activity = getActivity();
- if(activity == null){
- new Exception("MapFragment: activity is null, cannot set worldProvider!").printStackTrace();
+ if (activity == null) {
+ Log.e(this, new Exception("MapFragment: activity is null, cannot set worldProvider!"));
return null;
}
- try {
- //noinspection ConstantConditions
- worldProvider = (WorldActivityInterface) activity;
- } catch (ClassCastException e){
- new Exception("MapFragment: activity is not an worldprovider, cannot set worldProvider!", e).printStackTrace();
- return null;
- }
-
- //show the toolbar if the fab menu is opened
- FloatingActionMenu fabMenu = (FloatingActionMenu) rootView.findViewById(R.id.fab_menu);
- fabMenu.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
- @Override
- public void onMenuToggle(boolean opened) {
- if(opened) worldProvider.showActionBar();
- else worldProvider.hideActionBar();
- }
+ WorldActivityInterface activityInterface = (WorldActivityInterface) activity;
+ worldProvider = new WeakReference<>(activityInterface);
+ world = activityInterface.getWorld();
+
+ mBinding.fabMenu.setOnMenuButtonClickListener(this::onOpenFab);
+
+ // GPS button: moves camera to player position
+ mBinding.fabMenuGpsPlayer.setOnClickListener(this::moveCameraToPlayer);
+ Resources resources = activity.getResources();
+ mBinding.fabMenuGpsPlayer.setImageDrawable(
+ VectorDrawableCompat.create(resources, R.drawable.ic_person, null));
+
+ // GPS button: moves camera to spawn
+ mBinding.fabMenuGpsSpawn.setOnClickListener(this::moveCameraToSpawn);
+ mBinding.fabMenuGpsSpawn.setImageDrawable(
+ VectorDrawableCompat.create(resources, R.drawable.ic_action_home, null));
+
+ // Display a menu allowing user to move camera to many places.
+ mBinding.fabMenuGpsOthers.setOnClickListener(unusedView ->
+ openFloatPane(AdvancedLocatorFragment.create(world, this::frameTo)));
+ mBinding.fabMenuGpsOthers.setImageDrawable(
+ VectorDrawableCompat.create(resources, R.drawable.ic_action_search, null));
+
+ mBinding.fabMenuGpsPicer.setOnClickListener(unusedView -> {
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+ if (worldProvider == null) return;
+ DialogFragment fragment = PicerFragment.create(world,
+ worldProvider.getDimension(), null, this::triggerLongPressAtCenter);
+ fragment.show(getChildFragmentManager(), TAG_PICER);
+ });
+ mBinding.fabMenuGpsPicer.setImageDrawable(
+ VectorDrawableCompat.create(resources, R.drawable.ic_menu_camera, null));
+
+ // Show the toolbar if the fab menu is opened
+ mBinding.fabMenu.setOnMenuToggleListener(opened -> {
+ WorldActivityInterface worldProvider = MapFragment.this.worldProvider.get();
+ if (opened) {
+ worldProvider.showActionBar();
+ //worldProvider.openDrawer();
+ } else worldProvider.hideActionBar();
});
+ try {
+ Entity.loadEntityBitmaps(activity.getAssets());
+ } catch (IOException e) {
+ Log.d(this, e);
+ }
- FloatingActionButton fabGPSMarker = (FloatingActionButton) rootView.findViewById(R.id.fab_menu_gps_marker);
- assert fabGPSMarker != null;
- fabGPSMarker.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- Collection markers = worldProvider.getWorld().getMarkerManager().getMarkers();
-
- if(markers.isEmpty()){
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- TextView msg = new TextView(activity);
- float dpi = activity.getResources().getDisplayMetrics().density;
- msg.setPadding((int)(19*dpi), (int)(5*dpi), (int)(14*dpi), (int)(5*dpi));
- msg.setMaxLines(20);
- msg.setText(R.string.no_custom_markers);
- builder.setView(msg)
- .setTitle(R.string.no_custom_markers_title)
- .setCancelable(true)
- .setNeutralButton(android.R.string.ok, null)
- .show();
- } else {
-
- AlertDialog.Builder markerDialogBuilder = new AlertDialog.Builder(activity);
- markerDialogBuilder.setIcon(R.drawable.ic_place);
- markerDialogBuilder.setTitle(R.string.go_to_a_marker_list);
-
- final MarkerListAdapter arrayAdapter = new MarkerListAdapter(activity, new ArrayList<>(markers));
-
- markerDialogBuilder.setNegativeButton(android.R.string.cancel, null);
-
- markerDialogBuilder.setAdapter(
- arrayAdapter,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- AbstractMarker m = arrayAdapter.getItem(which);
- if(m == null) return;
-
- Snackbar.make(tileView,
- activity.getString(R.string.something_at_xyz_dim_int,
- m.getNamedBitmapProvider().getBitmapDisplayName(),
- m.x, m.y, m.z, m.dimension.name),
- Snackbar.LENGTH_SHORT)
- .setAction("Action", null).show();
-
- if(m.dimension != worldProvider.getDimension()){
- worldProvider.changeMapType(m.dimension.defaultMapType, m.dimension);
- }
-
- frameTo((double) m.x, (double) m.z);
-
- worldProvider.logFirebaseEvent(WorldActivity.CustomFirebaseEvent.GPS_MARKER);
- }
- });
- markerDialogBuilder.show();
- }
+ try {
+ KnownBlockRepr.loadBitmaps(activity.getAssets());
+ } catch (IOException e) {
+ Log.d(this, e);
+ }
+ try {
+ CustomIcon.loadCustomBitmaps(activity.getAssets());
+ } catch (IOException e) {
+ Log.d(this, e);
+ }
- } catch (Exception e){
- Snackbar.make(view, e.getMessage(), Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
- }
- });
+ //set the map-type
+ MapTileView tileView = mBinding.tileView;
+ tileView.getDetailLevelManager().setLevelType(worldProvider.get().getMapType());
+ tileView.setOnLongPressListener(this::onLongPressed);
/*
- GPS button: moves camera to player position
+ Create tile(=bitmap) provider
*/
- FloatingActionButton fabGPSMultiplayer = (FloatingActionButton) rootView.findViewById(R.id.fab_menu_gps_multiplayer);
- assert fabGPSMultiplayer != null;
- fabGPSMultiplayer.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(final View view) {
-
- if (tileView == null){
- Snackbar.make(view, R.string.no_map_available, Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- return;
- }
+ this.minecraftTileProvider = new MCTileProvider(worldProvider.get());
- Snackbar.make(tileView,
- R.string.searching_for_players,
- Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- //this can take some time... ...do it in the background
- (new AsyncTask(){
- @Override
- protected String[] doInBackground(Void... arg0) {
- try {
- return worldProvider.getWorld().getWorldData().getPlayers();
- } catch (Exception e){
- return null;
- }
- }
+ /*
+ Set the bitmap-provider of the tile view
+ */
+ tileView.setBitmapProvider(this.minecraftTileProvider);
- protected void onPostExecute(final String[] players) {
- getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if(players == null){
- Snackbar.make(view, R.string.failed_to_retrieve_player_data, Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- return;
- }
+ /*
+ Change tile view settings
+ */
- if(players.length == 0){
- Snackbar.make(view, R.string.no_multiplayer_data_found, Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- return;
- }
+ tileView.setBackgroundColor(0xFF494E8E);
+ // markers should align to the coordinate along the horizontal center and vertical bottom
+ tileView.setMarkerAnchorPoints(-0.5f, -1.0f);
+ tileView.defineBounds(
+ -1.0,
+ -1.0,
+ 1.0,
+ 1.0
+ );
- //NBT tag type spinner
- final Spinner spinner = new Spinner(activity);
- ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(activity,
- android.R.layout.simple_spinner_item, players);
+ tileView.setSize(MCTileProvider.viewSizeW, MCTileProvider.viewSizeL);
- spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- spinner.setAdapter(spinnerArrayAdapter);
+ for (MapType mapType : MapType.values()) {
+ tileView.addDetailLevel(0.0625f, "0.0625", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);// 1/(1/16)=16 chunks per tile
+ tileView.addDetailLevel(0.125f, "0.125", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);
+ tileView.addDetailLevel(0.25f, "0.25", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);
+ tileView.addDetailLevel(0.5f, "0.5", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);
+ tileView.addDetailLevel(1f, "1", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);// 1/1=1 chunk per tile
+ }
+ tileView.setScale(0.5f);
+
+ // Notify user to try using selection.
+ if (!activity.getPreferences(Context.MODE_PRIVATE).getBoolean(PREF_KEY_HAS_USED_SELECTION, false)) {
+ if (System.currentTimeMillis() % 25 == 0) tileView.postDelayed(() -> {
+ FragmentActivity activity1 = getActivity();
+ if (activity1 == null) return;
+ new AlertDialog.Builder(activity1)
+ .setMessage(R.string.map_notice_try_selection)
+ .setPositiveButton(android.R.string.ok, null)
+ .create()
+ .show();
+ activity1.getPreferences(Context.MODE_PRIVATE)
+ .edit()
+ .putBoolean(PREF_KEY_HAS_USED_SELECTION, true)
+ .apply();
+ }, 1000);
+ }
- //wrap layout in alert
- new AlertDialog.Builder(activity)
- .setTitle(R.string.go_to_player)
- .setView(spinner)
- .setPositiveButton(R.string.go_loud, new DialogInterface.OnClickListener() {
+ boolean framedToPlayer = false;
- public void onClick(DialogInterface dialog, int whichButton) {
+ //TODO multi-thread this
+ try {
- //new tag type
- int spinnerIndex = spinner.getSelectedItemPosition();
- String playerKey = players[spinnerIndex];
+ DimensionVector3 playerPos = world.getPlayerPos();
+ float x = playerPos.x, y = playerPos.y, z = playerPos.z;
+ Log.d(this, "Placed player marker at: " + x + ";" + y + ";" + z + " [" + playerPos.dimension.name + "]");
+ localPlayerMarker = new AbstractMarker((int) x, (int) y, (int) z,
+ playerPos.dimension, new CustomNamedBitmapProvider(Entity.PLAYER, "~local_player"), false);
+ this.staticMarkers.add(localPlayerMarker);
+ addMarker(localPlayerMarker);
- try {
- DimensionVector3 playerPos = getMultiPlayerPos(playerKey);
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+ if (localPlayerMarker.dimension != worldProvider.getDimension()) {
+ worldProvider.changeMapType(localPlayerMarker.dimension.defaultMapType, localPlayerMarker.dimension);
+ }
- Snackbar.make(tileView,
- getString(R.string.something_at_xyz_dim_float,
- playerKey,
- playerPos.x,
- playerPos.y,
- playerPos.z,
- playerPos.dimension.name),
- Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
+ frameTo((double) x, (double) z);
+ framedToPlayer = true;
- worldProvider.logFirebaseEvent(WorldActivity.CustomFirebaseEvent.GPS_MULTIPLAYER);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.d(this, "Failed to place player marker. " + e.toString());
+ }
- if(playerPos.dimension != worldProvider.getDimension()){
- worldProvider.changeMapType(playerPos.dimension.defaultMapType, playerPos.dimension);
- }
- frameTo((double) playerPos.x, (double) playerPos.z);
+ try {
+ DimensionVector3 spawnPos = world.getSpawnPos();
- } catch (Exception e){
- Snackbar.make(view, e.getMessage(), Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
+ spawnMarker = new AbstractMarker(spawnPos.x, spawnPos.y, spawnPos.z, spawnPos.dimension,
+ new CustomNamedBitmapProvider(CustomIcon.SPAWN_MARKER, "Spawn"), false);
+ this.staticMarkers.add(spawnMarker);
+ addMarker(spawnMarker);
- }
- })
- //or alert is cancelled
- .setNegativeButton(android.R.string.cancel, null)
- .show();
- }
- });
- }
+ if (!framedToPlayer) {
- }).execute();
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+ if (spawnMarker.dimension != worldProvider.getDimension()) {
+ worldProvider.changeMapType(spawnMarker.dimension.defaultMapType, spawnMarker.dimension);
+ }
+ frameTo((double) spawnPos.x, (double) spawnPos.z);
}
- });
+ } catch (Exception e) {
+ //no spawn defined...
+ if (!framedToPlayer) frameTo(0.0, 0.0);
- /*
- GPS button: moves camera to player position
- */
- FloatingActionButton fabGPSCoord = (FloatingActionButton) rootView.findViewById(R.id.fab_menu_gps_coord);
- assert fabGPSCoord != null;
- fabGPSCoord.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- if(tileView == null) throw new Exception("No map available.");
-
- View xzForm = LayoutInflater.from(activity).inflate(R.layout.xz_coord_form, null);
- final EditText xInput = (EditText) xzForm.findViewById(R.id.x_input);
- xInput.setText("0");
- final EditText zInput = (EditText) xzForm.findViewById(R.id.z_input);
- zInput.setText("0");
-
- //wrap layout in alert
- new AlertDialog.Builder(activity)
- .setTitle(R.string.go_to_coordinate)
- .setView(xzForm)
- .setPositiveButton(R.string.go_loud, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
+ }
- int inX, inZ;
- try{
- inX = Integer.parseInt(xInput.getText().toString());
- } catch (NullPointerException | NumberFormatException e){
- Toast.makeText(activity, R.string.invalid_x_coordinate,Toast.LENGTH_LONG).show();
- return;
- }
- try{
- inZ = Integer.parseInt(zInput.getText().toString());
- } catch (NullPointerException | NumberFormatException e){
- Toast.makeText(activity, R.string.invalid_z_coordinate,Toast.LENGTH_LONG).show();
- return;
- }
- worldProvider.logFirebaseEvent(WorldActivity.CustomFirebaseEvent.GPS_COORD);
-
- frameTo((double) inX, (double) inZ);
- }
- })
- .setCancelable(true)
- .setNegativeButton(android.R.string.cancel, null)
- .show();
-
- } catch (Exception e){
- Snackbar.make(view, e.getMessage(), Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
- }
- });
-
-
-
- try {
- Entity.loadEntityBitmaps(activity.getAssets());
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- try {
- Block.loadBitmaps(activity.getAssets());
- } catch (IOException e) {
- e.printStackTrace();
- }
- try{
- CustomIcon.loadCustomBitmaps(activity.getAssets());
- } catch (IOException e){
- e.printStackTrace();
- }
-
-
-
-
- /*
- Create tile view
- */
- this.tileView = new TileView(activity) {
-
- @Override
- public void onLongPress(MotionEvent event) {
-
- Dimension dimension = worldProvider.getDimension();
-
- // 1 chunk per tile on scale 1.0
- int pixelsPerBlockW_unscaled = MCTileProvider.TILESIZE / dimension.chunkW;
- int pixelsPerBlockL_unscaled = MCTileProvider.TILESIZE / dimension.chunkL;
-
- float pixelsPerBlockScaledW = pixelsPerBlockW_unscaled * this.getScale();
- float pixelsPerBlockScaledL = pixelsPerBlockL_unscaled * this.getScale();
-
-
- double worldX = ((( this.getScrollX() + event.getX()) / pixelsPerBlockScaledW) - MCTileProvider.HALF_WORLDSIZE) / dimension.dimensionScale;
- double worldZ = ((( this.getScrollY() + event.getY()) / pixelsPerBlockScaledL) - MCTileProvider.HALF_WORLDSIZE) / dimension.dimensionScale;
-
- MapFragment.this.onLongClick(worldX, worldZ);
- }
- };
-
- this.tileView.setId(ViewID.generateViewId());
-
- //set the map-type
- tileView.getDetailLevelManager().setLevelType(worldProvider.getMapType());
-
- /*
- Add tile view to main layout
- */
-
- //add world view to its container in the main layout
- worldContainer.addView(tileView);
-
-
- /*
- Create tile(=bitmap) provider
- */
- this.minecraftTileProvider = new MCTileProvider(worldProvider);
-
-
-
- /*
- Set the bitmap-provider of the tile view
- */
- this.tileView.setBitmapProvider(this.minecraftTileProvider);
-
-
- /*
- Change tile view settings
- */
-
- this.tileView.setBackgroundColor(0xFF494E8E);
-
- // markers should align to the coordinate along the horizontal center and vertical bottom
- tileView.setMarkerAnchorPoints(-0.5f, -1.0f);
-
- this.tileView.defineBounds(
- -1.0,
- -1.0,
- 1.0,
- 1.0
- );
-
- this.tileView.setSize(MCTileProvider.viewSizeW, MCTileProvider.viewSizeL);
-
- for(MapType mapType : MapType.values()){
- this.tileView.addDetailLevel(0.0625f, "0.0625", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);// 1/(1/16)=16 chunks per tile
- this.tileView.addDetailLevel(0.125f, "0.125", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);
- this.tileView.addDetailLevel(0.25f, "0.25", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);
- this.tileView.addDetailLevel(0.5f, "0.5", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);
- this.tileView.addDetailLevel(1f, "1", MCTileProvider.TILESIZE, MCTileProvider.TILESIZE, mapType);// 1/1=1 chunk per tile
-
- }
-
- this.tileView.setScale(0.5f);
-
-
- boolean framedToPlayer = false;
-
- //TODO multi-thread this
- try {
-
- DimensionVector3 playerPos = getPlayerPos();
- float x = playerPos.x, y = playerPos.y, z = playerPos.z;
- Log.d("Placed player marker at: "+x+";"+y+";"+z+" ["+playerPos.dimension.name+"]");
- localPlayerMarker = new AbstractMarker((int) x, (int) y, (int) z,
- playerPos.dimension, new CustomNamedBitmapProvider(Entity.PLAYER, "~local_player"), false);
- this.staticMarkers.add(localPlayerMarker);
- addMarker(localPlayerMarker);
-
- if(localPlayerMarker.dimension != worldProvider.getDimension()){
- worldProvider.changeMapType(localPlayerMarker.dimension.defaultMapType, localPlayerMarker.dimension);
- }
-
- frameTo((double) x, (double) z);
- framedToPlayer = true;
-
- } catch (Exception e){
- e.printStackTrace();
- Log.d("Failed to place player marker. "+e.toString());
- }
-
-
- try {
- DimensionVector3 spawnPos = getSpawnPos();
-
- spawnMarker = new AbstractMarker(spawnPos.x, spawnPos.y, spawnPos.z, spawnPos.dimension,
- new CustomNamedBitmapProvider(CustomIcon.SPAWN_MARKER, "Spawn"), false);
- this.staticMarkers.add(spawnMarker);
- addMarker(spawnMarker);
-
- if(!framedToPlayer){
-
- if(spawnMarker.dimension != worldProvider.getDimension()){
- worldProvider.changeMapType(spawnMarker.dimension.defaultMapType, spawnMarker.dimension);
- }
-
- frameTo((double) spawnPos.x, (double) spawnPos.z);
- }
-
- } catch (Exception e){
- //no spawn defined...
- if(!framedToPlayer) frameTo(0.0, 0.0);
-
- }
-
-
-
-
-
-
- tileView.getMarkerLayout().setMarkerTapListener(new MarkerLayout.MarkerTapListener() {
- @Override
- public void onMarkerTap(View view, int tapX, int tapY) {
- if(!(view instanceof MarkerImageView)){
- Log.d("Markertaplistener found a marker that is not a MarkerImageView! "+view.toString());
- return;
- }
+ tileView.getMarkerLayout().setMarkerTapListener(new MarkerLayout.MarkerTapListener() {
+ @Override
+ public void onMarkerTap(View view, int tapX, int tapY) {
+ if (!(view instanceof MarkerImageView)) return;
final AbstractMarker marker = ((MarkerImageView) view).getMarkerHook();
- if(marker == null){
- Log.d("abstract marker is null! "+view.toString());
- return;
- }
+ if (marker == null) return;
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder
- .setTitle(String.format(getString(R.string.marker_info), marker.getNamedBitmapProvider().getBitmapDisplayName(), marker.getNamedBitmapProvider().getBitmapDataName(), marker.x, marker.y, marker.z, marker.dimension))
+ .setTitle(String.format(getString(R.string.marker_info), marker.getNamedBitmapProvider().getBitmapDisplayName(), marker.x, marker.y, marker.z))
.setItems(getMarkerTapOptions(), new DialogInterface.OnClickListener() {
@SuppressWarnings("RedundantCast")
- @SuppressLint("SetTextI18n")
public void onClick(DialogInterface dialog, int which) {
final MarkerTapOption chosen = MarkerTapOption.values()[which];
- switch (chosen){
+ switch (chosen) {
case TELEPORT_LOCAL_PLAYER: {
try {
- final EditableNBT playerEditable = worldProvider.getEditablePlayer();
+ final EditableNBT playerEditable = worldProvider.get().getEditablePlayer();
if (playerEditable == null)
throw new Exception("Player is null");
@@ -816,7 +635,8 @@ public void onClick(DialogInterface dialog, int which) {
ListTag posVec = (ListTag) playerTag.getChildTagByKey("Pos");
- if (posVec == null) throw new Exception("No \"Pos\" specified");
+ if (posVec == null)
+ throw new Exception("No \"Pos\" specified");
final List playerPos = posVec.getValue();
if (playerPos == null)
@@ -825,7 +645,7 @@ public void onClick(DialogInterface dialog, int which) {
throw new Exception("\"Pos\" value is invalid. value: " + posVec.getValue().toString());
IntTag dimensionId = (IntTag) playerTag.getChildTagByKey("DimensionId");
- if(dimensionId == null || dimensionId.getValue() == null)
+ if (dimensionId == null || dimensionId.getValue() == null)
throw new Exception("No \"DimensionId\" specified");
@@ -840,38 +660,38 @@ public void onClick(DialogInterface dialog, int which) {
dimensionId.setValue(newDimension.id);
- if(playerEditable.save()){
+ if (playerEditable.save()) {
- localPlayerMarker = moveMarker(localPlayerMarker,newX, newY, newZ, newDimension);
+ localPlayerMarker = moveMarker(localPlayerMarker, newX, newY, newZ, newDimension);
//TODO could be improved for translation friendliness
- Snackbar.make(tileView,
- activity.getString(R.string.teleported_player_to_xyz_dimension)+newX+";"+newY+";"+newZ+" ["+newDimension.name+"] ("+marker.getNamedBitmapProvider().getBitmapDisplayName()+")",
+ Snackbar.make(mBinding.tileView,
+ activity.getString(R.string.teleported_player_to_xyz_dimension) + newX + ";" + newY + ";" + newZ + " [" + newDimension.name + "] (" + marker.getNamedBitmapProvider().getBitmapDisplayName() + ")",
Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
} else throw new Exception("Failed saving player");
- } catch (Exception e){
- Log.w(e.toString());
+ } catch (Exception e) {
+ Log.d(this, e.toString());
- Snackbar.make(tileView, R.string.failed_teleporting_player,
+ Snackbar.make(mBinding.tileView, R.string.failed_teleporting_player,
Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
return;
}
case REMOVE_MARKER: {
- if(marker.isCustom){
+ if (marker.isCustom) {
MapFragment.this.removeMarker(marker);
- MarkerManager mng = MapFragment.this.worldProvider.getWorld().getMarkerManager();
+ MarkerManager mng = world.getMarkerManager();
mng.removeMarker(marker, true);
mng.save();
} else {
//only custom markers are meant to be removable
- Snackbar.make(tileView, R.string.marker_is_not_removable,
+ Snackbar.make(mBinding.tileView, R.string.marker_is_not_removable,
Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
@@ -879,49 +699,47 @@ public void onClick(DialogInterface dialog, int which) {
}
}
})
- .setCancelable(true)
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ .setCancelable(true)
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
}
});
-
//do not loop the scale
tileView.setShouldLoopScale(false);
//prevents flickering
- this.tileView.setTransitionsEnabled(false);
+ tileView.setTransitionsEnabled(false);
//more responsive rendering
- this.tileView.setShouldRenderWhilePanning(true);
-
- this.tileView.setSaveEnabled(true);
+ tileView.setShouldRenderWhilePanning(false);
+ tileView.setSaveEnabled(true);
-
- return rootView;
+ return mBinding.getRoot();
}
/**
* Creates a new marker (looking exactly the same as the old one) on the new position,
- * while removing the old marker.
- * @param marker Marker to be recreated
- * @param x new pos X
- * @param y new pos Y
- * @param z new pos Z
+ * while removing the old marker.
+ *
+ * @param marker Marker to be recreated
+ * @param x new pos X
+ * @param y new pos Y
+ * @param z new pos Z
* @param dimension new pos Dimension
* @return the newly created marker, which should replace the old one.
*/
- public AbstractMarker moveMarker(AbstractMarker marker, int x, int y, int z, Dimension dimension){
+ private AbstractMarker moveMarker(AbstractMarker marker, int x, int y, int z, Dimension dimension) {
AbstractMarker newMarker = marker.copy(x, y, z, dimension);
- if(staticMarkers.remove(marker)) staticMarkers.add(newMarker);
+ if (staticMarkers.remove(marker)) staticMarkers.add(newMarker);
this.removeMarker(marker);
this.addMarker(newMarker);
- if(marker.isCustom){
- MarkerManager mng = this.worldProvider.getWorld().getMarkerManager();
+ if (marker.isCustom) {
+ MarkerManager mng = world.getMarkerManager();
mng.removeMarker(marker, true);
mng.addMarker(newMarker, true);
}
@@ -929,176 +747,203 @@ public AbstractMarker moveMarker(AbstractMarker marker, int x, int y, int z, Dim
return newMarker;
}
- private final static int MARKER_INTERVAL_CHECK = 50;
- private int proceduralMarkersInterval = 0;
- private volatile AsyncTask shrinkProceduralMarkersTask;
-
+ private void doSelectionBasedEdit(@NonNull EditFunction func, @Nullable Bundle args) {
+ WorldActivityInterface worldActivityInterface = worldProvider.get();
+ FragmentActivity activity = getActivity();
+ if (worldActivityInterface == null || activity == null) return;
+ switch (func) {
+ case SNR:
+ case LAMPSHADE:
+ case CHBIOME:
+ case DCHUNK:
+ new SelectionBasedContextFreeEditTask(func, args, this, world.getWorldData().mOldBlockRegistry).execute(
+ new RectEditTarget(
+ world.getWorldData(),
+ mBinding.selectionBoard.getSelection(),
+ worldActivityInterface.getDimension())
+ );
+ break;
+ case PICER: {
+ PicerFragment fragment = PicerFragment.create(
+ world, worldActivityInterface.getDimension(),
+ mBinding.selectionBoard.getSelection(), null
+ );
+ fragment.show(activity.getSupportFragmentManager(), TAG_PICER);
+ }
+ }
+ }
/**
* Calculates viewport of tileview, expressed in blocks.
+ *
* @param marginX horizontal viewport-margin, in pixels
* @param marginZ vertical viewport-margin, in pixels
* @return minimum_X, maximum_X, minimum_Z, maximum_Z, dimension. (min and max are expressed in blocks!)
*/
- public Object[] calculateViewPort(int marginX, int marginZ){
+ public Object[] calculateViewPort(int marginX, int marginZ) {
- Dimension dimension = this.worldProvider.getDimension();
+ Dimension dimension = this.worldProvider.get().getDimension();
// 1 chunk per tile on scale 1.0
- int pixelsPerBlockW_unscaled = MCTileProvider.TILESIZE / dimension.chunkW;
- int pixelsPerBlockL_unscaled = MCTileProvider.TILESIZE / dimension.chunkL;
+ int pixelsPerBlockW_unscaled = MCTileProvider.TILESIZE / 16;
+ int pixelsPerBlockL_unscaled = MCTileProvider.TILESIZE / 16;
+ MapTileView tileView = mBinding.tileView;
float scale = tileView.getScale();
- //scale the amount of pixels, less pixels per block if zoomed out
+ //scale the amount of pixels, less pixels per oldBlock if zoomed out
double pixelsPerBlockW = pixelsPerBlockW_unscaled * scale;
double pixelsPerBlockL = pixelsPerBlockL_unscaled * scale;
- long blockX = Math.round( (tileView.getScrollX() - marginX) / pixelsPerBlockW ) - MCTileProvider.HALF_WORLDSIZE;
- long blockZ = Math.round( (tileView.getScrollY() - marginZ) / pixelsPerBlockL ) - MCTileProvider.HALF_WORLDSIZE;
- long blockW = Math.round( (tileView.getWidth() + marginX + marginX) / pixelsPerBlockW );
- long blockH = Math.round( (tileView.getHeight() + marginZ + marginZ) / pixelsPerBlockL );
-
- return new Object[]{ blockX, blockX + blockW, blockZ, blockH, dimension };
- }
-
- public AsyncTask retainViewPortMarkers(final Runnable callback){
-
- DisplayMetrics displayMetrics = this.getActivity().getResources().getDisplayMetrics();
- return new AsyncTask(){
- @Override
- protected Void doInBackground(Object... params) {
- long minX = (long) params[0],
- maxX = (long) params[1],
- minY = (long) params[2],
- maxY = (long) params[3];
- Dimension reqDim = (Dimension) params[4];
-
- for (AbstractMarker p : MapFragment.this.proceduralMarkers){
-
- // do not remove static markers
- if(MapFragment.this.staticMarkers.contains(p)) continue;
-
- if(p.x < minX || p.x > maxX || p.y < minY || p.y > maxY || p.dimension != reqDim){
- this.publishProgress(p);
- }
- }
- return null;
- }
-
- @Override
- protected void onProgressUpdate(final AbstractMarker... values) {
- for(AbstractMarker v : values) {
- MapFragment.this.removeMarker(v);
- }
- }
-
- @Override
- protected void onPostExecute(Void aVoid) {
- callback.run();
- }
+ long blockX = Math.round((tileView.getScrollX() - marginX) / pixelsPerBlockW) - MCTileProvider.HALF_WORLDSIZE;
+ long blockZ = Math.round((tileView.getScrollY() - marginZ) / pixelsPerBlockL) - MCTileProvider.HALF_WORLDSIZE;
+ long blockW = Math.round((tileView.getWidth() + marginX + marginX) / pixelsPerBlockW);
+ long blockH = Math.round((tileView.getHeight() + marginZ + marginZ) / pixelsPerBlockL);
- }.execute(this.calculateViewPort(
- displayMetrics.widthPixels / 2,
- displayMetrics.heightPixels / 2)
- );
+ return new Object[]{blockX, blockX + blockW, blockZ, blockH, dimension};
}
/**
* Important: this method should be run from the UI thread.
+ *
* @param marker The marker to remove from the tile view.
*/
- public void removeMarker(AbstractMarker marker){
+ public void removeMarker(AbstractMarker marker) {
staticMarkers.remove(marker);
proceduralMarkers.remove(marker);
- if(marker.view != null) tileView.removeMarker(marker.view);
+ if (marker.view != null && mBinding.tileView != null)
+ mBinding.tileView.removeMarker(marker.view);
}
/**
* Important: this method should be run from the UI thread.
+ *
* @param marker The marker to add to the tile view.
*/
- public void addMarker(AbstractMarker marker){
+ public synchronized void addMarker(AbstractMarker marker) {
+
+ Activity act = getActivity();
+ if (act == null) return;
+
+ TileEntity.loadIcons(act.getAssets());
- if(proceduralMarkers.contains(marker)) return;
+ for (AbstractMarker abstractMarker : proceduralMarkers) {
+ if (abstractMarker.equals(marker)) {
+ removeMarker(abstractMarker);
+ }
+ }
- if(shrinkProceduralMarkersTask == null
- && ++proceduralMarkersInterval > MARKER_INTERVAL_CHECK){
+ if (shrinkProceduralMarkersTask == null
+ && ++proceduralMarkersInterval > MARKER_INTERVAL_CHECK) {
//shrink set of markers to viewport every so often
- shrinkProceduralMarkersTask = retainViewPortMarkers(new Runnable() {
- @Override
- public void run() {
- //reset this to start accepting viewport update requests again.
- shrinkProceduralMarkersTask = null;
- }
- });
+
+ DisplayMetrics displayMetrics = act.getResources().getDisplayMetrics();
+ //reset this to start accepting viewport update requests again.
+ shrinkProceduralMarkersTask = new RetainViewPortMarkersTask(this, () -> {
+ //reset this to start accepting viewport update requests again.
+ shrinkProceduralMarkersTask = null;
+ }).execute(calculateViewPort(
+ displayMetrics.widthPixels / 2,
+ displayMetrics.heightPixels / 2)
+ );
proceduralMarkersInterval = 0;
}
-
proceduralMarkers.add(marker);
+ if (proceduralMarkers.size() > MARKERS_ON_SCREEN_TOO_MANY) {
+ SharedPreferences pref = act.getPreferences(Context.MODE_PRIVATE);
+ if (!pref.getBoolean(PREF_KEY_HAS_NOTIFIED_MARKERS_TOO_MANY, false)) {
+ pref.edit().putBoolean(PREF_KEY_HAS_NOTIFIED_MARKERS_TOO_MANY, true).apply();
+ AlertDialog dialog = new AlertDialog.Builder(act)
+ .setTitle(R.string.map_smart_notice_too_many_markers)
+ .setMessage(R.string.map_smart_notice_too_many_markers_message)
+ .setPositiveButton(R.string.map_uioption_open_drawer, (dialogInterface, i) -> worldProvider.get().openDrawer())
+ .setNegativeButton(R.string.general_got_it, null)
+ .create();
+ dialog.setCanceledOnTouchOutside(false);
+ dialog.show();
+ }
+ }
- Activity act = getActivity();
- if (act == null) return;
MarkerImageView markerView = marker.getView(act);
this.filterMarker(marker);
- if(tileView.getMarkerLayout().indexOfChild(markerView) >= 0){
- tileView.getMarkerLayout().removeMarker(markerView);
+ if (mBinding.tileView.getMarkerLayout().indexOfChild(markerView) >= 0) {
+ mBinding.tileView.getMarkerLayout().removeMarker(markerView);
}
- tileView.addMarker(markerView,
+ mBinding.tileView.addMarker(markerView,
marker.dimension.dimensionScale * (double) marker.x / (double) MCTileProvider.HALF_WORLDSIZE,
marker.dimension.dimensionScale * (double) marker.z / (double) MCTileProvider.HALF_WORLDSIZE,
-0.5f, -0.5f);
}
- public void toggleMarkers(){
- int visibility = tileView.getMarkerLayout().getVisibility();
- tileView.getMarkerLayout().setVisibility( visibility == View.VISIBLE ? View.GONE : View.VISIBLE);
+ public void toggleMarkers() {
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+ if (worldProvider == null) return;
+ if (worldProvider.getShowMarkers()) {
+ resetTileView();
+ } else {
+ for (AbstractMarker marker : proceduralMarkers) {
+ if (staticMarkers.contains(marker)) continue;
+ removeMarker(marker);
+ }
+ //resetTileView();
+ }
}
+ private String[] getLongClickOptions() {
+ String[] values = new String[]{
+ getString(R.string.teleport_local_player),
+ getString(R.string.create_custom_marker),
+ getString(R.string.open_chunk_entity_nbt),
+ getString(R.string.open_chunk_tile_entity_nbt),
+ null
+ };
+ values[4] = getString(mBinding.selectionBoard.hasSelection() ?
+ R.string.func_cancel_selection : R.string.func_begin_selection);
+ return values;
+ }
- public enum LongClickOption {
-
- TELEPORT_LOCAL_PLAYER(R.string.teleport_local_player, null),
- CREATE_MARKER(R.string.create_custom_marker, null),
- //TODO TELEPORT_MULTI_PLAYER("Teleport other player", null),
- ENTITY(R.string.open_chunk_entity_nbt, ChunkTag.ENTITY),
- TILE_ENTITY(R.string.open_chunk_tile_entity_nbt, ChunkTag.BLOCK_ENTITY);
-
- public final int stringId;
- public final ChunkTag dataType;
+ private void triggerLongPressAtCenter() {
+ MotionEvent event = MotionEvent.obtain(0L, 0L, 0,
+ (float) (mBinding.tileView.getMeasuredWidth() / 2),
+ (float) (mBinding.tileView.getMeasuredHeight() / 2), 0);
+ onLongPressed(event);
+ // ...
+ }
- LongClickOption(int id, ChunkTag dataType){
- this.stringId = id;
- this.dataType = dataType;
- }
+ /**
+ * Map long press handler, shows a list of options.
+ *
+ * @param event long press event.
+ */
+ private void onLongPressed(@NonNull MotionEvent event) {
+ Dimension dimension = worldProvider.get().getDimension();
- }
+ // 1 chunk per tile on scale 1.0
+ int pixelsPerBlockW_unscaled = MCTileProvider.TILESIZE / dimension.chunkW;
+ int pixelsPerBlockL_unscaled = MCTileProvider.TILESIZE / dimension.chunkL;
- public String[] getLongClickOptions(){
- LongClickOption[] values = LongClickOption.values();
- int len = values.length;
- String[] options = new String[len];
- for(int i = 0; i < len; i++){
- options[i] = getString(values[i].stringId);
- }
- return options;
- }
+ float scale = mBinding.tileView.getScale();
+ float pixelsPerBlockScaledW = pixelsPerBlockW_unscaled * scale;
+ float pixelsPerBlockScaledL = pixelsPerBlockL_unscaled * scale;
- public void onLongClick(final double worldX, final double worldZ){
+ double worldX = (((mBinding.tileView.getScrollX() + event.getX()) / pixelsPerBlockScaledW) - MCTileProvider.HALF_WORLDSIZE) / dimension.dimensionScale;
+ double worldZ = (((mBinding.tileView.getScrollY() + event.getY()) / pixelsPerBlockScaledL) - MCTileProvider.HALF_WORLDSIZE) / dimension.dimensionScale;
+ //MapFragment.this.onLongClick(worldX, worldZ);
- final Activity activity = MapFragment.this.getActivity();
+ final Activity activity = getActivity();
+ if (activity == null) return;
- final Dimension dim = this.worldProvider.getDimension();
+ final Dimension dim = this.worldProvider.get().getDimension();
double chunkX = worldX / dim.chunkW;
double chunkZ = worldZ / dim.chunkL;
@@ -1108,245 +953,276 @@ public void onLongClick(final double worldX, final double worldZ){
final int chunkZint = chunkZ < 0 ? (((int) chunkZ) - 1) : ((int) chunkZ);
-
final View container = activity.findViewById(R.id.world_content);
- if(container == null){
- Log.w("CANNOT FIND MAIN CONTAINER, WTF");
+ if (container == null) {
+ Log.d(this, "CANNOT FIND MAIN CONTAINER, WTF");
return;
}
- new AlertDialog.Builder(activity)
- .setTitle(getString(R.string.postion_2D_floats_with_chunkpos, worldX, worldZ, chunkXint, chunkZint, dim.name))
- .setItems(getLongClickOptions(), new DialogInterface.OnClickListener() {
- @SuppressLint("SetTextI18n")
- public void onClick(DialogInterface dialog, int which) {
-
- final LongClickOption chosen = LongClickOption.values()[which];
-
+ AlertDialog alertDialog = new AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.AppTheme_Floating))
+ .setTitle(getString(R.string.postion_2D_floats_with_chunkpos, worldX, worldZ, chunkXint, chunkZint))
+ .setItems(getLongClickOptions(), (dialog, which) -> {
+
+
+ switch (which) {
+ case 0:
+ onChooseTeleportPlayer((float) worldX, (float) worldZ, dim, container);
+ break;
+ case 1:
+ onChooseAddMarker((int) worldX, (int) worldZ, activity, dim, container);
+ break;
+ case 2:
+ onChooseEditEntitiesOrTileEntities(dim, chunkXint, chunkZint, container, true);
+ break;
+ case 3:
+ onChooseEditEntitiesOrTileEntities(dim, chunkXint, chunkZint, container, false);
+ break;
+ case 4:
+ beginOrEndSelection((int) worldX, (int) worldZ);
+ }
- switch (chosen){
- case TELEPORT_LOCAL_PLAYER:{
- try {
- final EditableNBT playerEditable = MapFragment.this.worldProvider.getEditablePlayer();
- if(playerEditable == null) throw new Exception("Player is null");
-
- Iterator playerIter = playerEditable.getTags().iterator();
- if(!playerIter.hasNext()) throw new Exception("Player DB entry is empty!");
-
- //db entry consists of one compound tag
- final CompoundTag playerTag = (CompoundTag) playerIter.next();
-
- ListTag posVec = (ListTag) playerTag.getChildTagByKey("Pos");
-
- if (posVec == null) throw new Exception("No \"Pos\" specified");
-
- final List playerPos = posVec.getValue();
- if(playerPos == null)
- throw new Exception("No \"Pos\" specified");
- if (playerPos.size() != 3)
- throw new Exception("\"Pos\" value is invalid. value: " + posVec.getValue().toString());
-
- final IntTag dimensionId = (IntTag) playerTag.getChildTagByKey("DimensionId");
- if(dimensionId == null || dimensionId.getValue() == null)
- throw new Exception("No \"DimensionId\" specified");
-
-
- float playerY = (float) playerPos.get(1).getValue();
-
-
- View yForm = LayoutInflater.from(activity).inflate(R.layout.y_coord_form, null);
- final EditText yInput = (EditText) yForm.findViewById(R.id.y_input);
- yInput.setText(String.valueOf(playerY));
-
- final float newX = (float) worldX;
- final float newZ = (float) worldZ;
-
- new AlertDialog.Builder(activity)
- .setTitle(chosen.stringId)
- .setView(yForm)
- .setPositiveButton(R.string.action_teleport, new DialogInterface.OnClickListener() {
- @SuppressWarnings("RedundantCast")
- @Override
- public void onClick(DialogInterface dialog, int which) {
-
- float newY;
- Editable value = yInput.getText();
- if(value == null) newY = 64f;
- else {
- try {
- newY = (float) Float.parseFloat(value.toString());//removes excessive precision
- } catch (Exception e){
- newY = 64f;
- }
- }
-
- ((FloatTag) playerPos.get(0)).setValue(newX);
- ((FloatTag) playerPos.get(1)).setValue(newY);
- ((FloatTag) playerPos.get(2)).setValue(newZ);
- dimensionId.setValue(dim.id);
-
- if(playerEditable.save()){
-
- MapFragment.this.localPlayerMarker = MapFragment.this.moveMarker(
- MapFragment.this.localPlayerMarker,
- (int) newX, (int) newY, (int) newZ, dim);
-
- Snackbar.make(container,
- String.format(getString(R.string.teleported_player_to_xyz_dim), newX, newY, newZ, dim.name),
- Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- } else {
- Snackbar.make(container,
- R.string.failed_teleporting_player,
- Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
- }
- })
- .setCancelable(true)
- .setNegativeButton(android.R.string.cancel, null)
- .show();
- return;
-
- } catch (Exception e){
- e.printStackTrace();
- Snackbar.make(container, R.string.failed_to_find_or_edit_local_player_data,
- Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- return;
- }
- }
- case CREATE_MARKER:{
+ })
+ .setCancelable(true)
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ alertDialog.getListView().post(() ->
+ alertDialog.getListView().smoothScrollToPositionFromTop(4, 40));
+ Window window = alertDialog.getWindow();
+ if (window != null) {
+ window.setBackgroundDrawable(getResources().getDrawable(R.drawable.bg_dialog_transparent));
+ window.setDimAmount(0.3f);
+ }
- View createMarkerForm = LayoutInflater.from(activity).inflate(R.layout.create_marker_form, null);
+ }
- final EditText markerNameInput = (EditText) createMarkerForm.findViewById(R.id.marker_displayname_input);
- markerNameInput.setText(R.string.default_custom_marker_name);
- final EditText markerIconNameInput = (EditText) createMarkerForm.findViewById(R.id.marker_iconname_input);
- markerIconNameInput.setText("blue_marker");
- final EditText xInput = (EditText) createMarkerForm.findViewById(R.id.x_input);
- xInput.setText(String.valueOf((int) worldX));
- final EditText yInput = (EditText) createMarkerForm.findViewById(R.id.y_input);
- yInput.setText(String.valueOf(64));
- final EditText zInput = (EditText) createMarkerForm.findViewById(R.id.z_input);
- zInput.setText(String.valueOf((int) worldZ));
+ private void beginOrEndSelection(int worldX, int worldZ) {
+ if (mBinding.selectionBoard.hasSelection()) {
+ mBinding.selectionBoard.endSelection();
+ // If it's already replaced don't kill the wrong pig.
+ if (mFloatingFragment instanceof SelectionMenuFragment) closeFloatPane();
+ } else {
+ mBinding.selectionBoard.beginSelection(worldX, worldZ);
+ SelectionMenuFragment fragment = SelectionMenuFragment
+ .newInstance(mBinding.selectionBoard.getSelection(), world.getWorldData().mOldBlockRegistry, this::doSelectionBasedEdit);
+ openFloatPane(fragment);
+ setUpSelectionMenu();
+ Activity activity = getActivity();
+ if (activity != null) {
+ Log.logFirebaseEvent(activity, Log.CustomFirebaseEvent.SELECTION);
+ activity.getPreferences(Context.MODE_PRIVATE).edit()
+ .putBoolean(PREF_KEY_HAS_USED_SELECTION, true).apply();
+ }
+ }
+ }
+ private void onChooseEditEntitiesOrTileEntities(Dimension dim, int chunkXint, int chunkZint, View container, boolean isEntity) {
+ final Chunk chunk;
+ try {
+ chunk = world.getWorldData()
+ .getChunk(chunkXint, chunkZint, dim);
+ } catch (Exception e) {
+ Log.d(this, e);
+ Toast.makeText(getContext(), R.string.error_could_not_open_world, Toast.LENGTH_SHORT).show();
+ return;
+ }
- new AlertDialog.Builder(activity)
- .setTitle(chosen.stringId)
- .setView(createMarkerForm)
- .setPositiveButton("Create marker", new DialogInterface.OnClickListener() {
+ if (!chunkDataNBT(chunk, isEntity)) {
+ Snackbar.make(container, String.format(getString(R.string.failed_to_load_x),
+ getString(isEntity ?
+ R.string.open_chunk_entity_nbt : R.string.open_chunk_tile_entity_nbt)),
+ Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ }
+ }
- public void failParseSnackbarReport(int msg){
- Snackbar.make(container, msg,
- Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
-
- try {
- String displayName = markerNameInput.getText().toString();
- if (displayName.equals("") || displayName.contains("\"")) {
- failParseSnackbarReport(R.string.marker_invalid_name);
- return;
- }
- String iconName = markerIconNameInput.getText().toString();
- if (iconName.equals("") || iconName.contains("\"")) {
- failParseSnackbarReport(R.string.invalid_icon_name);
- return;
- }
-
- int xM, yM, zM;
-
- String xStr = xInput.getText().toString();
- try {
- xM = Integer.parseInt(xStr);
- } catch (NumberFormatException e) {
- failParseSnackbarReport(R.string.invalid_x_coordinate);
- return;
- }
- String yStr = yInput.getText().toString();
- try {
- yM = Integer.parseInt(yStr);
- } catch (NumberFormatException e) {
- failParseSnackbarReport(R.string.invalid_y_coordinate);
- return;
- }
-
- String zStr = zInput.getText().toString();
- try {
- zM = Integer.parseInt(zStr);
- } catch (NumberFormatException e) {
- failParseSnackbarReport(R.string.invalid_z_coordinate);
- return;
- }
-
- AbstractMarker marker = MarkerManager.markerFromData(displayName, iconName, xM, yM, zM, dim);
- MarkerManager mng = MapFragment.this.worldProvider.getWorld().getMarkerManager();
- mng.addMarker(marker, true);
-
- MapFragment.this.addMarker(marker);
-
- mng.save();
-
- } catch (Exception e){
- e.printStackTrace();
- failParseSnackbarReport(R.string.failed_to_create_marker);
- }
- }
- })
- .setCancelable(true)
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ private void onChooseAddMarker(int worldX, int worldZ, Activity activity, Dimension dim, View container) {
+ View createMarkerForm = LayoutInflater.from(activity).inflate(R.layout.create_marker_form, null);
+ final EditText markerNameInput = createMarkerForm.findViewById(R.id.marker_displayname_input);
+ markerNameInput.setText(R.string.default_custom_marker_name);
+ final EditText markerIconNameInput = createMarkerForm.findViewById(R.id.marker_iconname_input);
+ markerIconNameInput.setText("blue_marker");
+ final EditText xInput = createMarkerForm.findViewById(R.id.x_input);
+ xInput.setText(String.valueOf(worldX));
+ final EditText yInput = createMarkerForm.findViewById(R.id.y_input);
+ yInput.setText(String.valueOf(64));
+ final EditText zInput = createMarkerForm.findViewById(R.id.z_input);
+ zInput.setText(String.valueOf(worldZ));
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.create_custom_marker)
+ .setView(createMarkerForm)
+ .setPositiveButton("Create marker", new DialogInterface.OnClickListener() {
+
+ void failParseSnackbarReport(int msg) {
+ Snackbar.make(container, msg,
+ Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ }
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ try {
+ String displayName = markerNameInput.getText().toString();
+ if (displayName.equals("") || displayName.contains("\"")) {
+ failParseSnackbarReport(R.string.marker_invalid_name);
+ return;
+ }
+ String iconName = markerIconNameInput.getText().toString();
+ if (iconName.equals("") || iconName.contains("\"")) {
+ failParseSnackbarReport(R.string.invalid_icon_name);
return;
}
- /* TODO multi player teleporting
- case TELEPORT_MULTI_PLAYER:{
-
- break;
- }*/
- case ENTITY:
- case TILE_ENTITY:{
- final World world = MapFragment.this.worldProvider.getWorld();
- final ChunkManager chunkManager = new ChunkManager(world.getWorldData(), dim);
- final Chunk chunk = chunkManager.getChunk(chunkXint, chunkZint);
-
- if(!chunkDataNBT(chunk, chosen == LongClickOption.ENTITY)){
- Snackbar.make(container, String.format(getString(R.string.failed_to_load_x), getString(chosen.stringId)),
- Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
+ int xM, yM, zM;
+ String xStr = xInput.getText().toString();
+ try {
+ xM = Integer.parseInt(xStr);
+ } catch (NumberFormatException e) {
+ failParseSnackbarReport(R.string.invalid_x_coordinate);
+ return;
+ }
+ String yStr = yInput.getText().toString();
+ try {
+ yM = Integer.parseInt(yStr);
+ } catch (NumberFormatException e) {
+ failParseSnackbarReport(R.string.invalid_y_coordinate);
+ return;
+ }
+ String zStr = zInput.getText().toString();
+ try {
+ zM = Integer.parseInt(zStr);
+ } catch (NumberFormatException e) {
+ failParseSnackbarReport(R.string.invalid_z_coordinate);
+ return;
}
- }
+ AbstractMarker marker = MarkerManager.markerFromData(displayName, iconName, xM, yM, zM, dim);
+ MarkerManager mng = world.getMarkerManager();
+ mng.addMarker(marker, true);
+
+ MapFragment.this.addMarker(marker);
+
+ mng.save();
+ } catch (Exception e) {
+ e.printStackTrace();
+ failParseSnackbarReport(R.string.failed_to_create_marker);
+ }
}
})
.setCancelable(true)
.setNegativeButton(android.R.string.cancel, null)
.show();
+
+ return;
+ }
+
+ private void onChooseTeleportPlayer(float worldX, float worldZ, Dimension dim, View container) {
+ try {
+ Activity activity = getActivity();
+ assert activity != null;
+
+ final EditableNBT playerEditable = worldProvider.get().getEditablePlayer();
+ if (playerEditable == null)
+ throw new Exception("Player is null");
+
+ Iterator playerIter = playerEditable.getTags().iterator();
+ if (!playerIter.hasNext())
+ throw new Exception("Player DB entry is empty!");
+
+ //db entry consists of one compound tag
+ final CompoundTag playerTag = (CompoundTag) playerIter.next();
+
+ ListTag posVec = (ListTag) playerTag.getChildTagByKey("Pos");
+
+ if (posVec == null) throw new Exception("No \"Pos\" specified");
+
+ final List playerPos = posVec.getValue();
+ if (playerPos == null)
+ throw new Exception("No \"Pos\" specified");
+ if (playerPos.size() != 3)
+ throw new Exception("\"Pos\" value is invalid. value: " + posVec.getValue().toString());
+
+ final IntTag dimensionId = (IntTag) playerTag.getChildTagByKey("DimensionId");
+ if (dimensionId == null || dimensionId.getValue() == null)
+ throw new Exception("No \"DimensionId\" specified");
+
+
+ float playerY = (float) playerPos.get(1).getValue();
+
+
+ View yForm = LayoutInflater.from(activity).inflate(R.layout.y_coord_form, null);
+ final EditText yInput = yForm.findViewById(R.id.y_input);
+ yInput.setText(String.valueOf(playerY));
+
+ final float newX = worldX;
+ final float newZ = worldZ;
+
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.teleport_local_player)
+ .setView(yForm)
+ .setPositiveButton(R.string.action_teleport, (dialog1, which1) -> {
+
+ float newY;
+ Editable value = yInput.getText();
+ if (value == null) newY = 64f;
+ else {
+ try {
+ newY = Float.parseFloat(value.toString());//removes excessive precision
+ } catch (Exception e) {
+ newY = 64f;
+ }
+ }
+
+ ((FloatTag) playerPos.get(0)).setValue(newX);
+ ((FloatTag) playerPos.get(1)).setValue(newY);
+ ((FloatTag) playerPos.get(2)).setValue(newZ);
+ dimensionId.setValue(dim.id);
+
+ if (playerEditable.save()) {
+
+ MapFragment.this.localPlayerMarker = MapFragment.this.moveMarker(
+ MapFragment.this.localPlayerMarker,
+ (int) newX, (int) newY, (int) newZ, dim);
+
+ Snackbar.make(container,
+ getString(R.string.teleported_player_to_xyz_dim, newX, newY, newZ),
+ Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ } else {
+ Snackbar.make(container,
+ R.string.failed_teleporting_player,
+ Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ }
+ })
+ .setCancelable(true)
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ Snackbar.make(container, R.string.failed_to_find_or_edit_local_player_data,
+ Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ }
}
/**
* Opens the chunk data nbt editor.
*
- * @param chunk the chunk to edit
- * @param entity if it is entity data (True) or block-entity data (False)
+ * @param chunk the chunk to edit
+ * @param entity if it is entity data (True) or oldBlock-entity data (False)
* @return false when the chunk data could not be loaded.
*/
- private boolean chunkDataNBT(Chunk chunk, boolean entity){
+ private boolean chunkDataNBT(Chunk chunk, boolean entity) {
NBTChunkData chunkData;
try {
chunkData = entity ? chunk.getEntity() : chunk.getBlockEntity();
@@ -1356,38 +1232,223 @@ private boolean chunkDataNBT(Chunk chunk, boolean entity){
}
//just open the editor if the data is there for us to edit it
- this.worldProvider.openChunkNBTEditor(chunk.x, chunk.z, chunkData, this.tileView);
+ this.worldProvider.get().openChunkNBTEditor(chunk.mChunkX, chunk.mChunkZ, chunkData, mBinding.tileView);
return true;
}
-
@Override
public void onDestroy() {
super.onDestroy();
+ if (mBinding != null) {
+ mBinding.tileView.destroy();
+ }
+ // TODO: should we...👇
+ //mBinding.tileView = null;
+ minecraftTileProvider = null;
+ }
+ public void openMarkerFilter() {
+
+ final Activity activity = this.getActivity();
- tileView.destroy();
- tileView = null;
- minecraftTileProvider = null;
+ final List choices = new ArrayList<>(markerFilter.values());
+
+ //sort on names, nice for the user.
+ Collections.sort(choices, (a, b) -> a.namedBitmap.getNamedBitmapProvider().getBitmapDisplayName().compareTo(b.namedBitmap.getNamedBitmapProvider().getBitmapDisplayName()));
+
+
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.filter_markers)
+ .setAdapter(new BitmapChoiceListAdapter(activity, choices), null)
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
+ //save all the temporary states.
+ for (BitmapChoiceListAdapter.NamedBitmapChoice choice : choices) {
+ choice.enabled = choice.enabledTemp;
+ }
+ MapFragment.this.updateMarkerFilter();
+ })
+ .setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> {
+ //reset all the temporary states.
+ for (BitmapChoiceListAdapter.NamedBitmapChoice choice : choices) {
+ choice.enabledTemp = choice.enabled;
+ }
+ })
+ .setOnCancelListener(dialogInterface -> {
+ //reset all the temporary states.
+ for (BitmapChoiceListAdapter.NamedBitmapChoice choice : choices) {
+ choice.enabledTemp = choice.enabled;
+ }
+ })
+ .show();
}
- public static class BitmapChoiceListAdapter extends ArrayAdapter {
+ public void updateMarkerFilter() {
+ for (AbstractMarker marker : this.proceduralMarkers) {
+ filterMarker(marker);
+ }
+ }
- public static class NamedBitmapChoice {
+ public void filterMarker(AbstractMarker marker) {
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+ BitmapChoiceListAdapter.NamedBitmapChoice choice = markerFilter.get(marker.getNamedBitmapProvider());
+ if (choice != null) {
+ marker.getView(this.getActivity()).setVisibility(
+ (choice.enabled && marker.dimension == worldProvider.getDimension())
+ ? View.VISIBLE : View.INVISIBLE);
+ } else {
+ marker.getView(this.getActivity())
+ .setVisibility(marker.dimension == worldProvider.getDimension()
+ ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
- //Using a handle to facilitate bitmap swapping without breaking the filter.
- final NamedBitmapProviderHandle namedBitmap;
- boolean enabledTemp;
- boolean enabled;
+ public void refreshAfterEdit() {
+ mBinding.tileView.getTileCanvasViewGroup().clear();
+ mBinding.tileView.getTileCanvasViewGroup().requiredBeginRenderTask();
+ }
+
+ public void resetTileView() {
+ if (mBinding.tileView != null) {
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+
+ updateMarkerFilter();
+
+ mBinding.tileView.getDetailLevelManager().setLevelType(worldProvider.getMapType());
+
+ invalidateTileView();
+ }
+ }
+
+ public void invalidateTileView() {
+ WorldActivityInterface worldProvider = this.worldProvider.get();
+ MapType redo = worldProvider.getMapType();
+ DetailLevelManager manager = mBinding.tileView.getDetailLevelManager();
+ //just swap mapType twice; it is not rendered, but it invalidates all tiles.
+ manager.setLevelType(MapType.CHESS);
+ manager.setLevelType(redo);
+ //all tiles will now reload as soon as the tileView is drawn (user scrolls -> redraw)
+ }
+
+ /**
+ * This is a convenience method to scrollToAndCenter after layout (which won't happen if called directly in onCreate
+ * see https://github.com/moagrius/TileView/wiki/FAQ
+ */
+ public void frameTo(final double worldX, final double worldZ) {
+ mBinding.tileView.post(() -> {
+ Dimension dimension = worldProvider.get().getDimension();
+ if (mBinding.tileView != null) mBinding.tileView.scrollToAndCenter(
+ dimension.dimensionScale * worldX / (double) MCTileProvider.HALF_WORLDSIZE,
+ dimension.dimensionScale * worldZ / (double) MCTileProvider.HALF_WORLDSIZE);
+ });
+ }
+
+ public enum MarkerTapOption {
+
+ TELEPORT_LOCAL_PLAYER(R.string.teleport_local_player),
+ REMOVE_MARKER(R.string.remove_custom_marker);
+
+ public final int stringId;
+
+ MarkerTapOption(int id) {
+ this.stringId = id;
+ }
+
+ }
+
+ public enum LongClickOption {
+
+ TELEPORT_LOCAL_PLAYER(R.string.teleport_local_player, null),
+ CREATE_MARKER(R.string.create_custom_marker, null),
+ //TODO TELEPORT_MULTI_PLAYER("Teleport other player", null),
+ ENTITY(R.string.open_chunk_entity_nbt, ChunkTag.ENTITY),
+ TILE_ENTITY(R.string.open_chunk_tile_entity_nbt, ChunkTag.BLOCK_ENTITY),
+ BEGIN_SELECTION(R.string.func_begin_selection, null);
+
+ public final int stringId;
+ public final ChunkTag dataType;
+
+ LongClickOption(int id, ChunkTag dataType) {
+ this.stringId = id;
+ this.dataType = dataType;
+ }
+
+ }
+
+// private class MapTileView extends TileView{@Override
+// public void onLongPress(MotionEvent event) {
+//
+// Dimension dimension = worldProvider.get().getDimension();
+//
+// // 1 chunk per tile on scale 1.0
+// int pixelsPerBlockW_unscaled = MCTileProvider.TILESIZE / dimension.chunkW;
+// int pixelsPerBlockL_unscaled = MCTileProvider.TILESIZE / dimension.chunkL;
+//
+// float pixelsPerBlockScaledW = pixelsPerBlockW_unscaled * this.getScale();
+// float pixelsPerBlockScaledL = pixelsPerBlockL_unscaled * this.getScale();
+//
+//
+// double worldX = (((this.getScrollX() + event.getX()) / pixelsPerBlockScaledW) - MCTileProvider.HALF_WORLDSIZE) / dimension.dimensionScale;
+// double worldZ = (((this.getScrollY() + event.getY()) / pixelsPerBlockScaledL) - MCTileProvider.HALF_WORLDSIZE) / dimension.dimensionScale;
+//
+// MapFragment.this.onLongClick(worldX, worldZ);
+// }}
+
+ public static class MarkerListAdapter extends ArrayAdapter {
+
+
+ MarkerListAdapter(Context context, List objects) {
+ super(context, 0, objects);
+ }
+
+ @NonNull
+ @Override
+ public View getView(int position, View convertView, @NonNull ViewGroup parent) {
+
+ RelativeLayout v = (RelativeLayout) convertView;
+
+ if (v == null) {
+ LayoutInflater vi;
+ vi = LayoutInflater.from(getContext());
+ v = (RelativeLayout) vi.inflate(R.layout.marker_list_entry, parent, false);
+ }
+
+ AbstractMarker m = getItem(position);
+
+ if (m != null) {
+ TextView name = v.findViewById(R.id.marker_name);
+ TextView xz = v.findViewById(R.id.marker_xz);
+ ImageView icon = v.findViewById(R.id.marker_icon);
+
+ name.setText(m.getNamedBitmapProvider().getBitmapDisplayName());
+ String xzStr = String.format(Locale.ENGLISH, "x: %d, y: %d, z: %d", m.x, m.y, m.z);
+ xz.setText(xzStr);
+
+ m.loadIcon(icon);
- public NamedBitmapChoice(NamedBitmapProviderHandle namedBitmap, boolean enabled){
- this.namedBitmap = namedBitmap;
- this.enabled = this.enabledTemp = enabled;
}
+
+ return v;
}
- public BitmapChoiceListAdapter(Context context, List objects) {
+ }
+
+ public static class BitmapChoiceListAdapter extends ArrayAdapter {
+
+ private CompoundButton.OnCheckedChangeListener changeListener = new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
+ Object tag = compoundButton.getTag();
+ if (tag == null) return;
+ int position = (int) tag;
+ final NamedBitmapChoice m = getItem(position);
+ if (m == null) return;
+ m.enabledTemp = b;
+ }
+ };
+
+ BitmapChoiceListAdapter(Context context, List objects) {
super(context, 0, objects);
}
@@ -1396,16 +1457,16 @@ public BitmapChoiceListAdapter(Context context, List objects)
public View getView(final int position, View v, @NonNull ViewGroup parent) {
final NamedBitmapChoice m = getItem(position);
- if(m == null) return new RelativeLayout(getContext());
+ if (m == null) return new RelativeLayout(getContext());
if (v == null) v = LayoutInflater
- .from(getContext())
- .inflate(R.layout.img_name_check_list_entry, parent, false);
+ .from(getContext())
+ .inflate(R.layout.img_name_check_list_entry, parent, false);
- ImageView img = (ImageView) v.findViewById(R.id.entry_img);
- TextView text = (TextView) v.findViewById(R.id.entry_text);
- final CheckBox check = (CheckBox) v.findViewById(R.id.entry_check);
+ ImageView img = v.findViewById(R.id.entry_img);
+ TextView text = v.findViewById(R.id.entry_text);
+ final CheckBox check = v.findViewById(R.id.entry_check);
img.setImageBitmap(m.namedBitmap.getNamedBitmapProvider().getBitmap());
text.setText(m.namedBitmap.getNamedBitmapProvider().getBitmapDisplayName());
@@ -1416,150 +1477,159 @@ public View getView(final int position, View v, @NonNull ViewGroup parent) {
return v;
}
- private CompoundButton.OnCheckedChangeListener changeListener = new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
- Object tag = compoundButton.getTag();
- if(tag == null) return;
- int position = (int) tag;
- final NamedBitmapChoice m = getItem(position);
- if(m == null) return;
- m.enabledTemp = b;
+ static class NamedBitmapChoice {
+
+ //Using a handle to facilitate bitmap swapping without breaking the filter.
+ final NamedBitmapProviderHandle namedBitmap;
+ boolean enabledTemp;
+ boolean enabled;
+
+ NamedBitmapChoice(NamedBitmapProviderHandle namedBitmap, boolean enabled) {
+ this.namedBitmap = namedBitmap;
+ this.enabled = this.enabledTemp = enabled;
}
- };
+ }
}
+ private static class GetPlayerTask extends AsyncTask {
- //static, remember choice while app is open.
- static Map markerFilter = new HashMap<>();
+ private final WeakReference owner;
+ private final WeakReference view;
+ private final WeakReference activity;
- static {
- //entities are enabled by default
- for (Entity v : Entity.values()) {
- //skip things without a bitmap (dropped items etc.)
- //skip entities with placeholder ids (900+)
- if(v.sheetPos < 0 || v.id >= 900) continue;
- markerFilter.put(v.getNamedBitmapProvider(),
- new BitmapChoiceListAdapter.NamedBitmapChoice(v, true));
+ private GetPlayerTask(MapFragment owner, View view, Activity activity) {
+ this.owner = new WeakReference<>(owner);
+ this.view = new WeakReference<>(view);
+ this.activity = new WeakReference<>(activity);
}
- //tile-entities are disabled by default
- for (TileEntity v : TileEntity.values()) {
- markerFilter.put(v.getNamedBitmapProvider(),
- new BitmapChoiceListAdapter.NamedBitmapChoice(v, false));
+
+ @Override
+ protected String[] doInBackground(Void... arg0) {
+ try {
+ return owner.get().world.getWorldData().getNetworkPlayerNames();
+ } catch (Exception e) {
+ return null;
+ }
}
- }
+ protected void onPostExecute(final String[] players) {
+ owner.get().getActivity().runOnUiThread(() -> {
- public void openMarkerFilter() {
+ if (players == null) {
+ Snackbar.make(view.get(), R.string.failed_to_retrieve_player_data, Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ return;
+ }
- final Activity activity = this.getActivity();
+ if (players.length == 0) {
+ Snackbar.make(view.get(), R.string.no_multiplayer_data_found, Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ return;
+ }
- final List choices = new ArrayList<>();
- choices.addAll(markerFilter.values());
+ //NBT tag type spinner
+ final Spinner spinner = new Spinner(activity.get());
+ ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(activity.get(),
+ android.R.layout.simple_spinner_item, players);
- //sort on names, nice for the user.
- Collections.sort(choices, new Comparator() {
- @Override
- public int compare(BitmapChoiceListAdapter.NamedBitmapChoice a, BitmapChoiceListAdapter.NamedBitmapChoice b) {
- return a.namedBitmap.getNamedBitmapProvider().getBitmapDisplayName().compareTo(b.namedBitmap.getNamedBitmapProvider().getBitmapDisplayName());
- }
- });
+ spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(spinnerArrayAdapter);
+ //wrap layout in alert
+ new AlertDialog.Builder(activity.get())
+ .setTitle(R.string.go_to_player)
+ .setView(spinner)
+ .setPositiveButton(R.string.go_loud, new DialogInterface.OnClickListener() {
- new AlertDialog.Builder(activity)
- .setTitle(R.string.filter_markers)
- .setAdapter(new BitmapChoiceListAdapter(activity, choices), null)
- .setCancelable(true)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- //save all the temporary states.
- for(BitmapChoiceListAdapter.NamedBitmapChoice choice : choices){
- choice.enabled = choice.enabledTemp;
- }
- MapFragment.this.updateMarkerFilter();
- }
- })
- .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- //reset all the temporary states.
- for(BitmapChoiceListAdapter.NamedBitmapChoice choice : choices){
- choice.enabledTemp = choice.enabled;
- }
- }
- })
- .setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- //reset all the temporary states.
- for(BitmapChoiceListAdapter.NamedBitmapChoice choice : choices){
- choice.enabledTemp = choice.enabled;
- }
- }
- })
- .show();
- }
+ public void onClick(DialogInterface dialog, int whichButton) {
- public void updateMarkerFilter(){
- for(AbstractMarker marker : this.proceduralMarkers){
- filterMarker(marker);
- }
- }
+ //new tag type
+ int spinnerIndex = spinner.getSelectedItemPosition();
+ String playerKey = players[spinnerIndex];
- public void filterMarker(AbstractMarker marker){
- BitmapChoiceListAdapter.NamedBitmapChoice choice = markerFilter.get(marker.getNamedBitmapProvider());
- if(choice != null){
- marker.getView(this.getActivity()).setVisibility(
- (choice.enabled && marker.dimension == worldProvider.getDimension())
- ? View.VISIBLE : View.INVISIBLE);
- } else {
- marker.getView(this.getActivity())
- .setVisibility(marker.dimension == worldProvider.getDimension()
- ? View.VISIBLE : View.INVISIBLE);
- }
- }
+ try {
+ DimensionVector3 playerPos = owner.get().world.getMultiPlayerPos(playerKey);
+
+ Snackbar.make(owner.get().mBinding.tileView,
+ owner.get().getString(R.string.something_at_xyz_dim_float,
+ playerKey,
+ playerPos.x,
+ playerPos.y,
+ playerPos.z),
+ Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
- public void resetTileView(){
- if(this.tileView != null){
- worldProvider.logFirebaseEvent(WorldActivity.CustomFirebaseEvent.MAPFRAGMENT_RESET);
+ WorldActivityInterface worldProvider = owner.get().worldProvider.get();
+ Log.logFirebaseEvent(activity.get(), Log.CustomFirebaseEvent.GPS_LOCATE);
- updateMarkerFilter();
+ if (playerPos.dimension != worldProvider.getDimension()) {
+ worldProvider.changeMapType(playerPos.dimension.defaultMapType, playerPos.dimension);
+ }
- tileView.getDetailLevelManager().setLevelType(worldProvider.getMapType());
+ owner.get().frameTo((double) playerPos.x, (double) playerPos.z);
- invalidateTileView();
+ } catch (Exception e) {
+ Snackbar.make(view.get(), e.getMessage(), Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ }
+
+ }
+ })
+ //or alert is cancelled
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ });
}
- }
- public void invalidateTileView(){
- MapType redo = worldProvider.getMapType();
- DetailLevelManager manager = tileView.getDetailLevelManager();
- //just swap mapType twice; it is not rendered, but it invalidates all tiles.
- manager.setLevelType(MapType.CHESS);
- manager.setLevelType(redo);
- //all tiles will now reload as soon as the tileView is drawn (user scrolls -> redraw)
}
+ private static class RetainViewPortMarkersTask extends AsyncTask {
+ private final WeakReference owner;
+ private final Runnable callback;
- /**
- * This is a convenience method to scrollToAndCenter after layout (which won't happen if called directly in onCreate
- * see https://github.com/moagrius/TileView/wiki/FAQ
- */
- public void frameTo( final double worldX, final double worldZ ) {
- this.tileView.post(new Runnable() {
- @Override
- public void run() {
- Dimension dimension = worldProvider.getDimension();
- if(tileView != null) tileView.scrollToAndCenter(
- dimension.dimensionScale * worldX / (double) MCTileProvider.HALF_WORLDSIZE,
- dimension.dimensionScale * worldZ / (double) MCTileProvider.HALF_WORLDSIZE);
+ private RetainViewPortMarkersTask(MapFragment owner, Runnable callback) {
+ this.owner = new WeakReference<>(owner);
+ this.callback = callback;
+ }
+
+ @Override
+ protected Void doInBackground(Object... params) {
+ long minX = (long) params[0],
+ maxX = (long) params[1],
+ minY = (long) params[2],
+ maxY = (long) params[3];
+ Dimension reqDim = (Dimension) params[4];
+
+ CopyOnWriteArraySet proceduralMarkers = owner.get().proceduralMarkers;
+
+ for (AbstractMarker p : proceduralMarkers) {
+
+ // do not remove static markers
+ if (owner.get().staticMarkers.contains(p)) continue;
+
+ if (p.x < minX || p.x > maxX || p.y < minY || p.y > maxY || p.dimension != reqDim) {
+ this.publishProgress(p);
+ }
}
- });
+ return null;
+ }
+
+ @Override
+ protected void onProgressUpdate(final AbstractMarker... values) {
+ for (AbstractMarker v : values) {
+ owner.get().removeMarker(v);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ callback.run();
+ }
+
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/MapTileView.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/MapTileView.java
new file mode 100644
index 00000000..eb4cd759
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/MapTileView.java
@@ -0,0 +1,109 @@
+package com.mithrilmania.blocktopograph.map;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+
+import com.mithrilmania.blocktopograph.map.selection.SelectionView;
+import com.qozix.tileview.TileView;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A wrapper of TileView in order to handle some of its events.
+ */
+public class MapTileView extends TileView {
+
+ /**
+ * Long press callback.
+ */
+ private OnLongPressListener mOnLongPressListener;
+ private WeakReference mSelectionView;
+ private GestureDetector.OnDoubleTapListener mOuterDoubleTapListener;
+
+ private boolean mTouchable = true;
+
+ public MapTileView(Context context) {
+ super(context);
+ }
+
+ public MapTileView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MapTileView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public void onLongPress(MotionEvent event) {
+ if (mOnLongPressListener != null) mOnLongPressListener.onLongPressed(event);
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ updateSelection();
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent event) {
+ if (mOuterDoubleTapListener != null) mOuterDoubleTapListener.onDoubleTap(event);
+ return true;
+ }
+
+ public void setOuterDoubleTapListener(GestureDetector.OnDoubleTapListener outerDoubleTapListener) {
+ mOuterDoubleTapListener = outerDoubleTapListener;
+ }
+
+ public void updateSelection() {
+ SelectionView selectionView;
+ if (mSelectionView != null && (selectionView = mSelectionView.get()) != null
+ && selectionView.hasSelection()) {
+ //selectionView.invalidate();
+ selectionView.requestLayout();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mTouchable)
+ return super.onTouchEvent(event);
+ return false;
+ }
+
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent event) {
+ if (super.onSingleTapConfirmed(event)) return true;
+ if (mOnLongPressListener != null) {
+ mOnLongPressListener.onLongPressed(event);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the long press callback.
+ *
+ * @param mOnLongPressListener long press callback.
+ */
+ public void setOnLongPressListener(OnLongPressListener mOnLongPressListener) {
+ this.mOnLongPressListener = mOnLongPressListener;
+ }
+
+ public void setSelectionView(SelectionView selectionView) {
+ mSelectionView = new WeakReference<>(selectionView);
+ }
+
+ public void setTouchable(boolean touchable) {
+ mTouchable = touchable;
+ }
+
+ /**
+ * Interface for long press callback.
+ */
+ public interface OnLongPressListener {
+ void onLongPressed(MotionEvent event);
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/MarkerAsyncTask.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/MarkerAsyncTask.java
index eed95f97..48e0154c 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/MarkerAsyncTask.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/MarkerAsyncTask.java
@@ -1,10 +1,13 @@
package com.mithrilmania.blocktopograph.map;
import android.os.AsyncTask;
-import com.mithrilmania.blocktopograph.Log;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import com.mithrilmania.blocktopograph.Log;
import com.mithrilmania.blocktopograph.WorldActivityInterface;
-import com.mithrilmania.blocktopograph.chunk.*;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+import com.mithrilmania.blocktopograph.chunk.NBTChunkData;
import com.mithrilmania.blocktopograph.map.marker.AbstractMarker;
import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
import com.mithrilmania.blocktopograph.nbt.tags.FloatTag;
@@ -13,6 +16,7 @@
import com.mithrilmania.blocktopograph.nbt.tags.StringTag;
import com.mithrilmania.blocktopograph.nbt.tags.Tag;
+import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.List;
@@ -21,28 +25,29 @@
*/
public class MarkerAsyncTask extends AsyncTask {
- private final WorldActivityInterface worldProvider;
- private final ChunkManager chunkManager;
+ private final WeakReference worldProvider;
private final int minChunkX, minChunkZ, maxChunkX, maxChunkZ;
+ private final Dimension dimension;
- public MarkerAsyncTask(WorldActivityInterface worldProvider, ChunkManager chunkManager, int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ){
+ public MarkerAsyncTask(WorldActivityInterface worldProvider, int minChunkX, int minChunkZ,
+ int maxChunkX, int maxChunkZ, Dimension dimension) {
this.minChunkX = minChunkX;
this.minChunkZ = minChunkZ;
this.maxChunkX = maxChunkX;
this.maxChunkZ = maxChunkZ;
+ this.dimension = dimension;
- this.worldProvider = worldProvider;
- this.chunkManager = chunkManager;
+ this.worldProvider = new WeakReference<>(worldProvider);
}
@Override
protected Void doInBackground(Void... v) {
int cX, cZ;
- for(cZ = minChunkZ; cZ < maxChunkZ; cZ++){
- for(cX = minChunkX; cX < maxChunkX; cX++){
+ for (cZ = minChunkZ; cZ < maxChunkZ; cZ++) {
+ for (cX = minChunkX; cX < maxChunkX; cX++) {
loadEntityMarkers(cX, cZ);
loadTileEntityMarkers(cX, cZ);
loadCustomMarkers(cX, cZ);
@@ -52,9 +57,10 @@ protected Void doInBackground(Void... v) {
return null;
}
- private void loadEntityMarkers(int chunkX, int chunkZ){
+ private void loadEntityMarkers(int chunkX, int chunkZ) {
try {
- Chunk chunk = chunkManager.getChunk(chunkX, chunkZ);
+ Chunk chunk = worldProvider.get().getWorld().getWorldData()
+ .getChunk(chunkX, chunkZ, dimension);
NBTChunkData entityData = chunk.getEntity();
@@ -62,36 +68,44 @@ private void loadEntityMarkers(int chunkX, int chunkZ){
entityData.load();
- if(entityData.tags == null) return;
+ if (entityData.tags == null) return;
for (Tag tag : entityData.tags) {
- if (tag instanceof CompoundTag) {
- CompoundTag compoundTag = (CompoundTag) tag;
- //int id = ((IntTag) compoundTag.getChildTagByKey("id")).getValue();
- String tempName = compoundTag.getChildTagByKey("identifier").getValue().toString();
- tempName = tempName.replace("minecraft:","");
- tempName = tempName.substring(0, 1).toUpperCase() + tempName.substring(1);
- int id = Entity.getEntity(tempName).id;
- Entity e = Entity.getEntity(id & 0xff);
- if (e != null && e.bitmap != null) {
- List pos = ((ListTag) compoundTag.getChildTagByKey("Pos")).getValue();
- float xf = ((FloatTag) pos.get(0)).getValue();
- float yf = ((FloatTag) pos.get(1)).getValue();
- float zf = ((FloatTag) pos.get(2)).getValue();
-
- this.publishProgress(new AbstractMarker(Math.round(xf), Math.round(yf), Math.round(zf), chunkManager.dimension, e, false));
+ if (!(tag instanceof CompoundTag)) continue;
+ CompoundTag compoundTag = (CompoundTag) tag;
+ Entity e = null;
+ {
+ Tag idTag = compoundTag.getChildTagByKey("id");
+ if (idTag instanceof IntTag) {
+ Integer id = ((IntTag) idTag).getValue();
+ if (id != null) e = Entity.getEntity(id);
}
}
+ if (e == null) {
+ Tag idenTag = compoundTag.getChildTagByKey("identifier");
+ if (idenTag instanceof StringTag) {
+ String identifier = ((StringTag) idenTag).getValue();
+ if (identifier != null) e = Entity.getEntity(identifier);
+ }
+ }
+ if (e == null) e = Entity.UNKNOWN;
+ List pos = ((ListTag) compoundTag.getChildTagByKey("Pos")).getValue();
+ float xf = ((FloatTag) pos.get(0)).getValue();
+ float yf = ((FloatTag) pos.get(1)).getValue();
+ float zf = ((FloatTag) pos.get(2)).getValue();
+
+ this.publishProgress(new AbstractMarker(Math.round(xf), Math.round(yf), Math.round(zf), dimension, e, false));
}
- } catch (Exception e){
- Log.w(e.getMessage());
+ } catch (Exception e) {
+ Log.d(this, e);
}
}
- private void loadTileEntityMarkers(int chunkX, int chunkZ){
+ private void loadTileEntityMarkers(int chunkX, int chunkZ) {
try {
- Chunk chunk = chunkManager.getChunk(chunkX, chunkZ);
+ Chunk chunk = worldProvider.get().getWorld().getWorldData()
+ .getChunk(chunkX, chunkZ, dimension);
NBTChunkData tileEntityData = chunk.getBlockEntity();
@@ -99,7 +113,7 @@ private void loadTileEntityMarkers(int chunkX, int chunkZ){
tileEntityData.load();
- if(tileEntityData.tags == null) return;
+ if (tileEntityData.tags == null) return;
for (Tag tag : tileEntityData.tags) {
if (tag instanceof CompoundTag) {
@@ -111,18 +125,19 @@ private void loadTileEntityMarkers(int chunkX, int chunkZ){
int eY = ((IntTag) compoundTag.getChildTagByKey("y")).getValue();
int eZ = ((IntTag) compoundTag.getChildTagByKey("z")).getValue();
- this.publishProgress(new AbstractMarker(Math.round(eX), Math.round(eY), Math.round(eZ), chunkManager.dimension, te, false));
+ this.publishProgress(new AbstractMarker(Math.round(eX), Math.round(eY), Math.round(eZ), dimension, te, false));
}
}
}
- } catch (Exception e){
- Log.w(e.getMessage());
+ } catch (Exception e) {
+ Log.d(this, e);
}
}
- private void loadCustomMarkers(int chunkX, int chunkZ){
- Collection chunk = worldProvider.getWorld().getMarkerManager()
+ private void loadCustomMarkers(int chunkX, int chunkZ) {
+ WorldActivityInterface wai = worldProvider.get();
+ Collection chunk = wai.getWorld().getMarkerManager()
.getMarkersOfChunk(chunkX, chunkZ);
AbstractMarker[] markers = new AbstractMarker[chunk.size()];
this.publishProgress(chunk.toArray(markers));
@@ -130,8 +145,27 @@ private void loadCustomMarkers(int chunkX, int chunkZ){
@Override
protected void onProgressUpdate(AbstractMarker... values) {
- for(AbstractMarker marker : values){
- worldProvider.addMarker(marker);
+ WorldActivityInterface wai = worldProvider.get();
+
+ // Some of the marks may have been added to screen already, remove first.
+ // TODO: Why not just skipping them?
+ for (AbstractMarker marker : values) {
+ // 2019/2/27 fixing crash here.
+ // Fatal Exception: java.lang.IllegalStateException
+ // The specified child already has a parent.
+ // You must call removeView() on the child's parent first.
+ // com.qozix.tileview.markers.MarkerLayout.addMarker
+ // We found it caused by custom markers reusing issue.
+ // Entity and TileEntity marks are all newly created.
+ // So we're removing custom marks from parent if present.
+
+ if (marker.view != null) {
+ ViewParent par = marker.view.getParent();
+ if (par instanceof ViewGroup)
+ ((ViewGroup) par).removeView(marker.view);
+ }
+
+ wai.addMarker(marker);
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/MarkerManager.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/MarkerManager.java
index 2df8b669..15791ca2 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/MarkerManager.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/MarkerManager.java
@@ -3,7 +3,7 @@
import android.util.LongSparseArray;
import com.mithrilmania.blocktopograph.Log;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
import com.mithrilmania.blocktopograph.map.marker.AbstractMarker;
import com.mithrilmania.blocktopograph.map.marker.CustomNamedBitmapProvider;
import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
@@ -26,7 +26,6 @@
/**
* TODO docs
- *
*/
public class MarkerManager {
@@ -51,6 +50,7 @@ public class MarkerManager {
//
// example:
// 1 "Test \" marker" "default \" \"_ma 1 rker 1" 1234 64 4321 overworld ;
+ // Why bother inventing a format?
private static final Pattern formatRegex = Pattern.compile("(\\d+)\\s+\"(?:(?:(.+?[^\\\\]))|)\"\\s+\"(?:(?:(.+?[^\\\\]))|)\"\\s+(\\d+?)\\s+(\\d+?)\\s+(\\d+?)\\s+(.+?)\\s*;");
@@ -62,12 +62,12 @@ public class MarkerManager {
private boolean dirty;
- public MarkerManager(File markerFile){
+ public MarkerManager(File markerFile) {
this.markerFile = markerFile;
executorService = Executors.newSingleThreadExecutor();
}
- public void load(){
+ public void load() {
executorService.submit(new Runnable() {
@Override
public void run() {
@@ -76,31 +76,35 @@ public void run() {
});
}
- public void removeMarker(AbstractMarker marker, boolean dirty){
+ private static long xzToKey(int x, int z) {
+ return (((long) x) << 32) | z;
+ }
+
+ public void removeMarker(AbstractMarker marker, boolean dirty) {
- long chunkKey = ChunkManager.xzToKey(marker.x >> 4, marker.z >> 4);
+ long chunkKey = xzToKey(marker.x >> 4, marker.z >> 4);
Set chunk = chunks.get(chunkKey);
- if(chunk != null) chunk.remove(marker);
+ if (chunk != null) chunk.remove(marker);
//only set it to dirty if the marker is removed.
this.dirty |= markers.remove(marker) && dirty;
}
- public void addMarker(AbstractMarker marker, boolean dirty){
+ public void addMarker(AbstractMarker marker, boolean dirty) {
markers.add(marker);
- long chunkKey = ChunkManager.xzToKey(marker.x >> 4, marker.z >> 4);
+ long chunkKey = xzToKey(marker.x >> 4, marker.z >> 4);
Set chunk = chunks.get(chunkKey);
- if(chunk == null) chunks.put(chunkKey, chunk = new HashSet<>());
+ if (chunk == null) chunks.put(chunkKey, chunk = new HashSet<>());
chunk.add(marker);
this.dirty |= dirty;
}
- private synchronized Set loadFromFile(){
+ private synchronized Set loadFromFile() {
markers = new HashSet<>();
- if(this.markerFile.exists()) {
+ if (this.markerFile.exists()) {
try {
BufferedReader br = new BufferedReader(new FileReader(this.markerFile));
String line;
@@ -130,7 +134,7 @@ private synchronized Set loadFromFile(){
}
} catch (Exception e) {
//ok, probably a comment or something, just ignore
- Log.d("Invalid line in marker file: " + line);
+ Log.d(this, "Invalid line in marker file: " + line);
}
}
br.close();
@@ -148,8 +152,8 @@ private synchronized Set loadFromFile(){
/**
* Saves the current markers, if and only if the markers were changed.
*/
- public void save(){
- if(dirty) executorService.submit(new Runnable() {
+ public void save() {
+ if (dirty) executorService.submit(new Runnable() {
@Override
public void run() {
MarkerManager.this.saveToFile();
@@ -158,15 +162,16 @@ public void run() {
});
}
- private synchronized void saveToFile(){
+ private synchronized void saveToFile() {
try {
- if(markerFile.createNewFile()) Log.d("Created "+this.markerFile.getAbsolutePath());
+ if (markerFile.createNewFile())
+ Log.d(this, "Created " + this.markerFile.getAbsolutePath());
//append to file
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(this.markerFile, false)));
- for(AbstractMarker marker : markers){
+ for (AbstractMarker marker : markers) {
out.format("1 \"%s\", \"%s\", %d %d %d %s ;\n",
marker.getNamedBitmapProvider().getBitmapDisplayName().replace("\"", "\\\""),
marker.getNamedBitmapProvider().getBitmapDataName().replace("\"", "\\\""),
@@ -180,27 +185,27 @@ private synchronized void saveToFile(){
}
}
- public Collection getMarkers(){
+ public Collection getMarkers() {
return Collections.unmodifiableSet(markers);
}
- public Collection getMarkersOfChunk(int chunkX, int chunkZ){
- long key = ChunkManager.xzToKey(chunkX, chunkZ);
+ public Collection getMarkersOfChunk(int chunkX, int chunkZ) {
+ long key = xzToKey(chunkX, chunkZ);
Set chunk = chunks.get(key);
- if(chunk == null) chunks.put(key, chunk = new HashSet<>());
+ if (chunk == null) chunks.put(key, chunk = new HashSet<>());
return chunk;
}
- public static AbstractMarker markerFromData(String displayName, String iconName, int x, int y, int z, Dimension dimension){
+ public static AbstractMarker markerFromData(String displayName, String iconName, int x, int y, int z, Dimension dimension) {
- NamedBitmapProvider nbp = Block.getByDataName(iconName);
- if(nbp == null || nbp.getBitmap() == null) nbp = Entity.getEntity(iconName);
- if(nbp == null || nbp.getBitmap() == null) nbp = TileEntity.getTileEntity(iconName);
- if(nbp == null || nbp.getBitmap() == null) nbp = CustomIcon.getCustomIcon(iconName);
- if(nbp == null || nbp.getBitmap() == null) nbp = CustomIcon.DEFAULT_MARKER;
+ NamedBitmapProvider nbp = KnownBlockRepr.getByDataName(iconName);
+ if (nbp == null || nbp.getBitmap() == null) nbp = Entity.getEntity(iconName);
+ if (nbp == null || nbp.getBitmap() == null) nbp = TileEntity.getTileEntity(iconName);
+ if (nbp == null || nbp.getBitmap() == null) nbp = CustomIcon.getCustomIcon(iconName);
+ if (nbp == null || nbp.getBitmap() == null) nbp = CustomIcon.DEFAULT_MARKER;
return new AbstractMarker(x, y, z, dimension,
- new CustomNamedBitmapProvider(nbp, displayName), true);
+ new CustomNamedBitmapProvider(nbp, displayName), true);
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/OpenLongPressMenuHandler.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/OpenLongPressMenuHandler.java
new file mode 100644
index 00000000..98adb766
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/OpenLongPressMenuHandler.java
@@ -0,0 +1,7 @@
+package com.mithrilmania.blocktopograph.map;
+
+public interface OpenLongPressMenuHandler {
+
+ void open();
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/Player.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/Player.java
new file mode 100644
index 00000000..b50d1834
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/Player.java
@@ -0,0 +1,59 @@
+package com.mithrilmania.blocktopograph.map;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.util.math.DimensionVector3;
+
+
+public class Player {
+
+ public static final String LOCAL_PLAYER_NAME = "~local_player";
+
+ private final boolean isLocal;
+ private String dbName;
+ private DimensionVector3 position;
+
+ private Player(boolean isLocal, String dbName) {
+ this.isLocal = isLocal;
+ this.dbName = dbName;
+ }
+
+ @NonNull
+
+ public static Player localPlayer() {
+ return new Player(true, LOCAL_PLAYER_NAME);
+ }
+
+ @NonNull
+
+ public static Player networkPlayer(String dbName) {
+ return new Player(false, dbName);
+ }
+
+ public boolean isLocal() {
+ return isLocal;
+ }
+
+ public String getDbName() {
+ return dbName;
+ }
+
+ public DimensionVector3 getPosition() {
+ return position;
+ }
+
+ public String getPositionDescription(Context context) {
+ if (position == null)
+ return context.getString(R.string.map_locator_player_pos_unknown);
+ return context.getString(R.string.player_position_desc,
+ Math.round(position.x), Math.round(position.y),
+ Math.round(position.z), context.getString(position.dimension.getName()));
+ }
+
+ public void setPosition(DimensionVector3 position) {
+ this.position = position;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/TileEntity.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/TileEntity.java
index 75530f07..5120c971 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/TileEntity.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/TileEntity.java
@@ -1,8 +1,11 @@
package com.mithrilmania.blocktopograph.map;
+import android.content.res.AssetManager;
import android.graphics.Bitmap;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.block.ListingBlock;
import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
import com.mithrilmania.blocktopograph.util.NamedBitmapProviderHandle;
@@ -12,41 +15,52 @@
public enum TileEntity implements NamedBitmapProviderHandle, NamedBitmapProvider {
- CHEST(0, "Chest", "Chest", Block.B_54_0_CHEST),
- TRAPPED_CHEST(1, "Trapped Chest", "TrappedChest", Block.B_146_0_TRAPPED_CHEST),
- ENDER_CHEST(2, "Ender Chest", "EnderChest", Block.B_130_0_ENDER_CHEST),
- MOB_SPAWNER(3, "Mob Spawner", "MobSpawner", Block.B_52_0_MOB_SPAWNER),
- END_PORTAL(4, "End Portal", "EndPortal", Block.B_119_0_END_PORTAL),
- BEACON(5, "Beacon", "Beacon", Block.B_138_0_BEACON);
+ CHEST(0, "Chest", "Chest", ListingBlock.B_54_CHEST),
+ TRAPPED_CHEST(1, "Trapped Chest", "TrappedChest", ListingBlock.B_146_TRAPPED_CHEST),
+ ENDER_CHEST(2, "Ender Chest", "EnderChest", ListingBlock.B_130_ENDER_CHEST),
+ MOB_SPAWNER(3, "Mob Spawner", "MobSpawner", ListingBlock.B_52_MOB_SPAWNER),
+ END_PORTAL(4, "End Portal", "EndPortal", ListingBlock.B_119_END_PORTAL),
+ BEACON(5, "Beacon", "Beacon", ListingBlock.B_138_BEACON);
+ private static final Map tileEntityMap;
+ private static final Map tileEntityByID;
+
public final int id;
public final String displayName, dataName;
- public final Block block;
+ static {
+ tileEntityMap = new HashMap<>();
+ tileEntityByID = new HashMap<>();
+ for (TileEntity e : TileEntity.values()) {
+ tileEntityMap.put(e.dataName, e);
+ tileEntityByID.put(e.id, e);
+ }
+ }
+
+ public final ListingBlock block;
+ public Bitmap icon;
- TileEntity(int id, String displayName, String dataName, Block block){
+ TileEntity(int id, String displayName, String dataName, ListingBlock block) {
this.id = id;
this.displayName = displayName;
this.dataName = dataName;
this.block = block;
}
- @Override
- public Bitmap getBitmap(){
- return block.bitmap;
+ static public synchronized void loadIcons(AssetManager assMan) {
+ for (TileEntity entity : values())
+ if (entity.icon == null)
+ entity.icon = Bitmap.createScaledBitmap(entity.block.getIcon(assMan),
+ 36, 36, false);
}
- @NonNull
- @Override
- public NamedBitmapProvider getNamedBitmapProvider(){
- return this;
+ public static TileEntity getTileEntity(int id) {
+ return tileEntityByID.get(id);
}
- @NonNull
- @Override
- public String getBitmapDisplayName(){
- return this.displayName;
+ public static TileEntity getTileEntity(String dataName) {
+ return tileEntityMap.get(dataName);
}
@NonNull
@@ -55,25 +69,22 @@ public String getBitmapDataName() {
return this.dataName;
}
- private static final Map tileEntityMap;
- private static final Map tileEntityByID;
-
- static {
- tileEntityMap = new HashMap<>();
- tileEntityByID = new HashMap<>();
- for(TileEntity e : TileEntity.values()){
- tileEntityMap.put(e.dataName, e);
- tileEntityByID.put(e.id, e);
- }
+ @Override
+ public Bitmap getBitmap() {
+ return icon;
}
- public static TileEntity getTileEntity(int id){
- return tileEntityByID.get(id);
+ @NonNull
+ @Override
+ public NamedBitmapProvider getNamedBitmapProvider() {
+ return this;
}
- public static TileEntity getTileEntity(String dataName){
- return tileEntityMap.get(dataName);
+ @NonNull
+ @Override
+ public String getBitmapDisplayName() {
+ return this.displayName;
}
-
+
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChBiomeEdit.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChBiomeEdit.java
new file mode 100644
index 00000000..cc8b8ea1
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChBiomeEdit.java
@@ -0,0 +1,30 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+import com.mithrilmania.blocktopograph.map.Biome;
+
+
+public class ChBiomeEdit implements EditTarget.RandomAccessEdit {
+
+ @Nullable
+ private Biome mFrom;
+
+ @NonNull
+ private Biome mTo;
+
+ ChBiomeEdit(@Nullable Biome fromBiome, @NonNull Biome toBiome) {
+ mFrom = fromBiome;
+ mTo = toBiome;
+ }
+
+ @Override
+ public int edit(Chunk chunk, int x, int y, int z) {
+ if (mFrom == null || chunk.getBiome(x, z) == mFrom.id)
+ chunk.setBiome(x, z, mTo.id);
+ return 0;
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChBiomeFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChBiomeFragment.java
new file mode 100644
index 00000000..556eb60f
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChBiomeFragment.java
@@ -0,0 +1,119 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RadioGroup;
+
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.DialogFragment;
+
+import com.mithrilmania.blocktopograph.BiomeSelectDialog;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.databinding.FragChBiomeBinding;
+import com.mithrilmania.blocktopograph.map.Biome;
+import com.mithrilmania.blocktopograph.map.selection.SelectionMenuFragment;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.io.Serializable;
+
+import static android.app.Activity.RESULT_OK;
+
+public final class ChBiomeFragment extends DialogFragment {
+
+ public static final String KEY_FROM = "from";
+ public static final String KEY_TO = "to";
+ private static final int REQUEST_CODE_FOR = 2012;
+ private static final int REQUEST_CODE_TO = 2013;
+ private FragChBiomeBinding mBinding;
+ private SelectionMenuFragment.EditFunctionEntry mEntry;
+
+ public static ChBiomeFragment newInstance(SelectionMenuFragment.EditFunctionEntry entry) {
+ ChBiomeFragment fragment = new ChBiomeFragment();
+ fragment.mEntry = entry;
+ return fragment;
+ }
+
+ private void onChangeForCheckedChanged(@NonNull RadioGroup group, @IdRes int checkedId) {
+ mBinding.biomeView.getRoot().setVisibility(
+ checkedId == R.id.biome_for_specific ? View.VISIBLE : View.GONE);
+ }
+
+ @NonNull
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ mBinding = DataBindingUtil.inflate(inflater, R.layout.frag_ch_biome, container, false);
+ mBinding.changeFor.setOnCheckedChangeListener(this::onChangeForCheckedChanged);
+ mBinding.biomeView.getRoot().setOnClickListener(v ->
+ startActivityForResult(new Intent(getActivity(), BiomeSelectDialog.class), REQUEST_CODE_FOR));
+ mBinding.biomeReplace.getRoot().setOnClickListener(v ->
+ startActivityForResult(new Intent(getActivity(), BiomeSelectDialog.class), REQUEST_CODE_TO));
+ UiUtil.blendBlockColor(mBinding.biomeView.getRoot(), Biome.PLAINS);
+ mBinding.biomeView.setBiome(Biome.PLAINS);
+ mBinding.biomeView.getRoot().setVisibility(View.GONE);
+ UiUtil.blendBlockColor(mBinding.biomeReplace.getRoot(), Biome.JUNGLE);
+ mBinding.biomeReplace.setBiome(Biome.JUNGLE);
+ View root = mBinding.getRoot();
+ Dialog dialog = getDialog();
+ if (dialog instanceof AlertDialog) {
+ ((AlertDialog) dialog).setView(root);
+ }
+ return root;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ Context context = requireContext();
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.map_edit_func_chbiome)
+ .setPositiveButton(android.R.string.ok, this::onClickOk)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ switch (requestCode) {
+ case REQUEST_CODE_FOR:
+ case REQUEST_CODE_TO:
+ if (resultCode == RESULT_OK && data != null) {
+ Serializable ser = data.getSerializableExtra(BiomeSelectDialog.KEY_BIOME);
+ if (ser instanceof Biome) {
+ Biome biome = (Biome) ser;
+ switch (requestCode) {
+ case REQUEST_CODE_FOR:
+ UiUtil.blendBlockColor(mBinding.biomeView.getRoot(), biome);
+ mBinding.biomeView.setBiome(biome);
+ break;
+ case REQUEST_CODE_TO:
+ UiUtil.blendBlockColor(mBinding.biomeReplace.getRoot(), biome);
+ mBinding.biomeReplace.setBiome(biome);
+ break;
+ }
+ }
+ }
+ return;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ private void onClickOk(DialogInterface dia, int i) {
+ Bundle bundle = new Bundle();
+ bundle.putSerializable(KEY_FROM,
+ mBinding.changeFor.getCheckedRadioButtonId() == R.id.biome_for_all ?
+ null : mBinding.biomeView.getBiome());
+ Biome biomeTo = mBinding.biomeReplace.getBiome();
+ bundle.putSerializable(KEY_TO, biomeTo == null ? Biome.PLAINS : biomeTo);
+ mEntry.invokeEditFunction(EditFunction.CHBIOME, bundle);
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChunkBasedEditResult.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChunkBasedEditResult.java
new file mode 100644
index 00000000..6253b834
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/ChunkBasedEditResult.java
@@ -0,0 +1,25 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import com.mithrilmania.blocktopograph.map.Dimension;
+
+/**
+ * Used to publish result for every chunks in chunk-cased edit.
+ */
+public class ChunkBasedEditResult {
+
+ public int x;
+
+ public int z;
+
+ public Dimension dimension;
+
+ public EditResultCode resultCode;
+
+ public ChunkBasedEditResult(int x, int z, Dimension dimension, EditResultCode resultCode) {
+ this.x = x;
+ this.z = z;
+ this.dimension = dimension;
+ this.resultCode = resultCode;
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/DchunkEdit.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/DchunkEdit.java
new file mode 100644
index 00000000..7192f406
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/DchunkEdit.java
@@ -0,0 +1,29 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+
+public class DchunkEdit implements EditTarget.ChunkBasedEdit {
+
+ private static final int MAX_EXCEPTION = 5;
+
+ private int exceptionCount;
+
+ public DchunkEdit() {
+ exceptionCount = 0;
+ }
+
+ @Override
+ public int edit(Chunk chunk, int fromX, int toX, int fromY, int toY, int fromZ, int toZ) {
+ try {
+ chunk.deleteThis();
+ } catch (Exception e) {
+ if (exceptionCount < MAX_EXCEPTION) {
+ Log.d(this, e);
+ exceptionCount++;
+ }
+ return -1;
+ }
+ return 0;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditFunction.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditFunction.java
new file mode 100644
index 00000000..44f589d1
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditFunction.java
@@ -0,0 +1,9 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+public enum EditFunction {
+ LAMPSHADE,
+ SNR,
+ DCHUNK,
+ CHBIOME,
+ PICER
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditResultCode.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditResultCode.java
new file mode 100644
index 00000000..ce81dacf
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditResultCode.java
@@ -0,0 +1,5 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+public enum EditResultCode {
+ SUCCESS, DB_ERROR, GENERAL_FAILURE, PARTIALLY_FAILED, QUIT_TOO_MANY_ERROR
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditTarget.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditTarget.java
new file mode 100644
index 00000000..ba7caa0f
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/EditTarget.java
@@ -0,0 +1,49 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+
+
+public abstract class EditTarget {
+
+ protected int mMaxError = 10;
+
+ protected final boolean mIsChunkAware;
+ @NonNull
+ protected final WorldData mWorldData;
+
+ protected EditTarget(boolean isChunkAware, @NonNull WorldData worldData) {
+ mIsChunkAware = isChunkAware;
+ mWorldData = worldData;
+ }
+
+ public abstract EditResultCode forEachXyz(RandomAccessEdit edit);
+
+ public abstract EditResultCode forEachXz(RandomAccessEdit edit);
+
+ public abstract EditResultCode forEachChunk(ChunkBasedEdit edit);
+
+ public final void setMaxError(int maxError) {
+ mMaxError = maxError;
+ }
+
+
+ public final boolean isChunkAware() {
+ return mIsChunkAware;
+ }
+
+ public interface RandomAccessEdit {
+
+ int edit(Chunk chunk, int x, int y, int z);
+
+ }
+
+ public interface ChunkBasedEdit {
+
+ int edit(Chunk chunk, int fromX, int toX, int fromY, int toY, int fromZ, int toZ);
+
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/RectEditTarget.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/RectEditTarget.java
new file mode 100644
index 00000000..0f4c3571
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/RectEditTarget.java
@@ -0,0 +1,145 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import android.annotation.SuppressLint;
+import android.graphics.Rect;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+import com.mithrilmania.blocktopograph.chunk.Version;
+import com.mithrilmania.blocktopograph.map.Dimension;
+
+
+public class RectEditTarget extends EditTarget {
+
+ @NonNull
+ private final Rect mArea;
+
+ private final int yLowest;
+
+ private final int yHighest;
+
+ @NonNull
+ private final Dimension dimension;
+
+ public RectEditTarget(@NonNull WorldData worldData, @NonNull Rect area, @NonNull Dimension dimension) {
+ super(true, worldData);
+ mArea = new Rect(area);
+ mArea.right--;
+ mArea.bottom--;
+ yLowest = 0;
+ yHighest = 255;
+ this.dimension = dimension;
+ }
+
+ @Override
+ public EditResultCode forEachXyz(RandomAccessEdit edit) {
+ return forEach(false, false, null, edit);
+ }
+
+ @Override
+ public EditResultCode forEachXz(RandomAccessEdit edit) {
+ return forEach(false, true, null, edit);
+ }
+
+ @Override
+ public EditResultCode forEachChunk(ChunkBasedEdit edit) {
+ return forEach(true, false, edit, null);
+ }
+
+ @SuppressLint("DefaultLocale")
+ private EditResultCode forEach(boolean chunkBased, boolean is2d,
+ @Nullable ChunkBasedEdit chunkBasedEdit,
+ @Nullable RandomAccessEdit randomAccessEdit) {
+
+ int exceptionCount = 0;
+
+ int chunkMinX = mArea.left >> 4;
+ int chunkMaxX = mArea.right >> 4;
+ int chunkMinZ = mArea.top >> 4;
+ int chunkMaxZ = mArea.bottom >> 4;
+
+ // Cache should not be used till end.
+
+ for (int chunkX = chunkMinX; chunkX <= chunkMaxX; chunkX++) {
+ int innerMinX = (chunkX == chunkMinX) ? (mArea.left & 0xf) : 0;
+ int innerMaxX = (chunkX == chunkMaxX) ? (mArea.right & 0xf) : 15;
+
+ for (int chunkZ = chunkMinZ; chunkZ <= chunkMaxZ; chunkZ++) {
+ int innerMinZ = (chunkZ == chunkMinZ) ? (mArea.top & 0xf) : 0;
+ int innerMaxZ = (chunkZ == chunkMaxZ) ? (mArea.bottom & 0xf) : 15;
+
+ Chunk chunk = mWorldData.getChunkStreaming(chunkX, chunkZ, dimension, false, Version.V1_2_PLUS);
+
+ if (chunkBased) {
+ int result = chunkBasedEdit.edit(chunk, innerMinX, innerMaxX, yLowest, yHighest, innerMinZ, innerMaxZ);
+ if (result != 0) {
+ if (exceptionCount < 5 || exceptionCount > mMaxError) {
+ Log.d(this, String.format(
+ "Failed with chunk (%d,%d), code %d",
+ chunkX, chunkZ, result));
+ if (exceptionCount > mMaxError)
+ return EditResultCode.QUIT_TOO_MANY_ERROR;
+ exceptionCount++;
+ }
+ }
+ } else {
+ boolean supportHightMap = chunk.supportsHeightMap();
+
+ for (int innerX = innerMinX; innerX <= innerMaxX; innerX++) {
+ for (int innerZ = innerMinZ; innerZ <= innerMaxZ; innerZ++) {
+
+ if (is2d) {
+ int result = randomAccessEdit.edit(chunk, innerX, 0, innerZ);
+ if (result != 0) {
+ if (exceptionCount < 5 || exceptionCount > mMaxError) {
+ Log.d(this, String.format(
+ "Failed with chunk (%d,%d), rel (%d,%d), code %d",
+ chunkX, chunkZ, innerX, innerZ, result));
+ if (exceptionCount > mMaxError)
+ return EditResultCode.QUIT_TOO_MANY_ERROR;
+ exceptionCount++;
+ }
+ }
+ } else {
+
+ //Math.min(yHighest, chunk.getHeightMapValue(innerX, innerZ) - 1)
+ //: yHighest;
+ for (int y = yLowest; y <= yHighest; y++) {
+ int result = randomAccessEdit.edit(chunk, innerX, y, innerZ);
+ if (result != 0) {
+ if (exceptionCount < 5 || exceptionCount > mMaxError) {
+ Log.d(this, String.format(
+ "Failed with chunk (%d,%d), rel (%d,%d,%d), code %d",
+ chunkX, chunkZ, innerX, y, innerZ, result));
+ if (exceptionCount > mMaxError)
+ return EditResultCode.QUIT_TOO_MANY_ERROR;
+ exceptionCount++;
+ }
+ }
+ }// End for y
+
+ }
+ }// End for innerZ
+ }// End for innerX
+ }
+
+ try {
+ chunk.save();
+ } catch (Exception e) {
+ if (exceptionCount < 5 || exceptionCount > mMaxError) {
+ Log.d(this, e);
+ if (exceptionCount > mMaxError) return EditResultCode.QUIT_TOO_MANY_ERROR;
+ exceptionCount++;
+ }
+ }
+ }// End for ChunkZ
+ }// End for ChunkX
+
+ mWorldData.resetCache();
+ return exceptionCount > 0 ? EditResultCode.PARTIALLY_FAILED : EditResultCode.SUCCESS;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SearchAndReplaceFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SearchAndReplaceFragment.java
new file mode 100644
index 00000000..e86ee3c3
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SearchAndReplaceFragment.java
@@ -0,0 +1,300 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.DialogFragment;
+
+import com.jbvincey.nestedradiobutton.NestedRadioGroupManager;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.OldBlockRegistry;
+import com.mithrilmania.blocktopograph.databinding.FragSerachAndReplaceBinding;
+import com.mithrilmania.blocktopograph.databinding.IncludeBlockBinding;
+import com.mithrilmania.blocktopograph.flat.PickBlockActivity;
+import com.mithrilmania.blocktopograph.map.selection.SelectionMenuFragment;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+import com.tomergoldst.tooltips.ToolTip;
+import com.tomergoldst.tooltips.ToolTipsManager;
+
+import java.io.Serializable;
+
+import static android.app.Activity.RESULT_OK;
+
+public class SearchAndReplaceFragment extends DialogFragment {
+
+ public static final String CONFIG = "config";
+ private static final int REQUEST_CODE = 2012;
+ private static final int[] REQ_OFFSET_IDS = {
+ R.id.search_block_any, R.id.search_block_bg,
+ R.id.search_block_fg, R.id.replace_block_any,
+ R.id.replace_block_bg, R.id.replace_block_fg
+ };
+ private FragSerachAndReplaceBinding mBinding;
+ private SelectionMenuFragment.EditFunctionEntry mEntry;
+ private ToolTipsManager mToolTipsManager;
+ private OldBlockRegistry registry;
+
+ public static SearchAndReplaceFragment newInstance(OldBlockRegistry registry, SelectionMenuFragment.EditFunctionEntry entry) {
+ SearchAndReplaceFragment fragment = new SearchAndReplaceFragment();
+ fragment.mEntry = entry;
+ fragment.registry = registry;
+ return fragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ mBinding = DataBindingUtil.inflate(inflater, R.layout.frag_serach_and_replace, container, false);
+ // Saved instance has highest priority to be recovered.
+ Serializable ser;
+ if (savedInstanceState != null && (ser = savedInstanceState.getSerializable(CONFIG)) instanceof SnrConfig) {
+ SnrConfig cfg = (SnrConfig) ser;
+ recoverSearchIn(cfg.searchMode);
+ recoverPlaceIn(cfg.placeMode);
+ switch (cfg.searchMode) {
+ case 1:
+ case 2:
+ case 3:
+ recoverBlock(mBinding.searchBlockAny, cfg.searchBlockMain);
+ break;
+ case 4:
+ recoverBlock(mBinding.searchBlockBg, cfg.searchBlockSub);
+ recoverBlock(mBinding.searchBlockFg, cfg.searchBlockMain);
+ break;
+ }
+ switch (cfg.placeMode) {
+ case 1:
+ case 2:
+ recoverBlock(mBinding.replaceBlockAny, cfg.placeOldBlockMain);
+ break;
+ case 3:
+ recoverBlock(mBinding.replaceBlockBg, cfg.placeOldBlockSub);
+ recoverBlock(mBinding.replaceBlockFg, cfg.placeOldBlockMain);
+ }
+ //mBinding.cbIgsub.setChecked(cfg.ignoreSubId);
+ } else {
+ setBlockToItem(mBinding.searchBlockAny, BlockTemplates.getOfType("minecraft:grass")[0]);
+ setBlockToItem(mBinding.searchBlockBg, BlockTemplates.getOfType("minecraft:air")[0]);
+ setBlockToItem(mBinding.searchBlockFg, BlockTemplates.getOfType("minecraft:grass")[0]);
+ setBlockToItem(mBinding.replaceBlockAny, BlockTemplates.getOfType("minecraft:glass")[0]);
+ setBlockToItem(mBinding.replaceBlockFg, BlockTemplates.getOfType("minecraft:glass")[0]);
+ setBlockToItem(mBinding.replaceBlockBg, BlockTemplates.getOfType("minecraft:water")[0]);
+ }
+
+ mBinding.searchIn.setOnCheckedChangeListener(this::onCheckedChanged);
+ mBinding.placeIn.setOnCheckedChangeListener(this::onCheckedChanged);
+ mBinding.searchBlockAny.getRoot().setOnClickListener(this::onBlockItemClick);
+ mBinding.searchBlockBg.getRoot().setOnClickListener(this::onBlockItemClick);
+ mBinding.searchBlockFg.getRoot().setOnClickListener(this::onBlockItemClick);
+ mBinding.replaceBlockAny.getRoot().setOnClickListener(this::onBlockItemClick);
+ mBinding.replaceBlockBg.getRoot().setOnClickListener(this::onBlockItemClick);
+ mBinding.replaceBlockFg.getRoot().setOnClickListener(this::onBlockItemClick);
+ mBinding.ok.setOnClickListener(this::onClickOk);
+ mBinding.help.setOnClickListener(this::onClickHelpMain);
+ mToolTipsManager = new ToolTipsManager();
+ View root = mBinding.getRoot();
+ Dialog dialog = getDialog();
+ if (dialog instanceof AlertDialog) {
+ ((AlertDialog) dialog).setView(root);
+ }
+ return root;
+ }
+
+ private void onClickHelpMain(@NonNull View view) {
+ if (mToolTipsManager.findAndDismiss(view)) return;
+ ToolTip.Builder builder = new ToolTip.Builder(
+ view.getContext(), view, mBinding.frameMain,
+ getString(R.string.map_edit_snr_help_background), ToolTip.POSITION_BELOW)
+ .setAlign(ToolTip.ALIGN_LEFT);
+ mToolTipsManager.show(builder.build());
+ }
+
+ private int getSearchInCode() {
+ if (mBinding.rbSearchBg.isChecked()) return 1;
+ if (mBinding.rbSearchFg.isChecked()) return 2;
+ if (mBinding.rbSearchOr.isChecked()) return 3;
+ if (mBinding.rbSearchBoth.isChecked()) return 4;
+ return 0;
+ }
+
+ private int getPlaceInCode() {
+ if (mBinding.rbPlaceBg.isChecked()) return 1;
+ if (mBinding.rbPlaceFg.isChecked()) return 2;
+ if (mBinding.rbPlaceBoth.isChecked()) return 3;
+ return 0;
+ }
+
+ private void recoverSearchIn(int code) {
+ switch (code) {
+ case 1:
+ mBinding.rbSearchBg.setChecked(true);
+ break;
+ case 2:
+ mBinding.rbSearchFg.setChecked(true);
+ break;
+ case 3:
+ mBinding.rbSearchOr.setChecked(true);
+ break;
+ case 4:
+ mBinding.rbSearchBoth.setChecked(true);
+ break;
+ }
+ }
+
+ private void recoverPlaceIn(int code) {
+ switch (code) {
+ case 1:
+ mBinding.rbPlaceBg.setChecked(true);
+ break;
+ case 2:
+ mBinding.rbPlaceFg.setChecked(true);
+ break;
+ case 3:
+ mBinding.rbPlaceBoth.setChecked(true);
+ break;
+ }
+ }
+
+ private void recoverBlock(@NonNull IncludeBlockBinding item, @Nullable Serializable data) {
+ setBlockToItem(item, data instanceof BlockTemplate ? (BlockTemplate) data : BlockTemplates.getAirTemplate());
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ writeToBundle(outState);
+ super.onSaveInstanceState(outState);
+ }
+
+ private void writeToBundle(@NonNull Bundle bundle) {
+ SnrConfig cfg = new SnrConfig();
+ cfg.searchMode = getSearchInCode();
+ cfg.placeMode = getPlaceInCode();
+ switch (cfg.searchMode) {
+ case 1:
+ case 2:
+ case 3:
+ cfg.searchBlockMain = new SnrConfig.SearchConditionBlock(
+ mBinding.searchBlockAny.getBlockTemplate().getBlock(), false, true);
+ break;
+ case 4:
+ cfg.searchBlockMain = new SnrConfig.SearchConditionBlock(
+ mBinding.searchBlockFg.getBlockTemplate().getBlock(), false, true);
+ cfg.searchBlockSub = new SnrConfig.SearchConditionBlock(
+ mBinding.searchBlockBg.getBlockTemplate().getBlock(), false, true);
+ break;
+ }
+ switch (cfg.placeMode) {
+ case 1:
+ case 2:
+ cfg.placeOldBlockMain = mBinding.replaceBlockAny.getBlockTemplate().getBlock();
+ break;
+ case 3:
+ cfg.placeOldBlockMain = mBinding.replaceBlockFg.getBlockTemplate().getBlock();
+ cfg.placeOldBlockSub = mBinding.replaceBlockBg.getBlockTemplate().getBlock();
+ break;
+ }
+ cfg.ignoreSubId = true;// mBinding.cbIgsub.isChecked();
+ bundle.putSerializable(CONFIG, cfg);
+ }
+
+ private void onBlockItemClick(@NonNull View view) {
+ int req = REQUEST_CODE;
+ int id = view.getId();
+ for (int i = 0; i < REQ_OFFSET_IDS.length; i++) {
+ if (REQ_OFFSET_IDS[i] == id) {
+ req += i;
+ break;
+ }
+ }
+ startActivityForResult(
+ new Intent(view.getContext(), PickBlockActivity.class), req
+ );
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ if (resultCode == RESULT_OK && data != null) {
+ var blockTemplate = (BlockTemplate) data.getSerializableExtra(PickBlockActivity.EXTRA_KEY_BLOCK);
+ switch (requestCode - REQUEST_CODE) {
+ case 0:
+ setBlockToItem(mBinding.searchBlockAny, blockTemplate);
+ break;
+ case 1:
+ setBlockToItem(mBinding.searchBlockBg, blockTemplate);
+ break;
+ case 2:
+ setBlockToItem(mBinding.searchBlockFg, blockTemplate);
+ break;
+ case 3:
+ setBlockToItem(mBinding.replaceBlockAny, blockTemplate);
+ break;
+ case 4:
+ setBlockToItem(mBinding.replaceBlockBg, blockTemplate);
+ break;
+ case 5:
+ setBlockToItem(mBinding.replaceBlockFg, blockTemplate);
+ break;
+ }
+ return;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ private void setBlockToItem(@NonNull IncludeBlockBinding item, @NonNull BlockTemplate template) {
+ item.icon.setImageBitmap(template.getIcon().getIcon(getContext()));
+ UiUtil.blendBlockColor(item.getRoot(), template);
+ item.setBlockTemplate(template);
+ }
+
+ private void onClickOk(View view) {
+ Bundle bundle = new Bundle();
+ writeToBundle(bundle);
+ mEntry.invokeEditFunction(EditFunction.SNR, bundle);
+ dismiss();
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ Context context = requireContext();
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.map_edit_func_snr)
+ .create();
+ }
+
+ private void onCheckedChanged(@NonNull NestedRadioGroupManager group, @IdRes int checkedId) {
+ switch (checkedId) {
+ case R.id.rb_search_both:
+ mBinding.frameSearchTwo.setVisibility(View.VISIBLE);
+ mBinding.frameSearchOne.setVisibility(View.GONE);
+ break;
+ case R.id.rb_search_bg:
+ case R.id.rb_search_fg:
+ case R.id.rb_search_or:
+ mBinding.frameSearchTwo.setVisibility(View.GONE);
+ mBinding.frameSearchOne.setVisibility(View.VISIBLE);
+ break;
+ case R.id.rb_place_both:
+ mBinding.framePlaceTwo.setVisibility(View.VISIBLE);
+ mBinding.framePlaceOne.setVisibility(View.GONE);
+ break;
+ case R.id.rb_place_bg:
+ case R.id.rb_place_fg:
+ mBinding.framePlaceTwo.setVisibility(View.GONE);
+ mBinding.framePlaceOne.setVisibility(View.VISIBLE);
+ break;
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SelectionBasedContextFreeEditTask.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SelectionBasedContextFreeEditTask.java
new file mode 100644
index 00000000..69b92384
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SelectionBasedContextFreeEditTask.java
@@ -0,0 +1,153 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.OldBlockRegistry;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+import com.mithrilmania.blocktopograph.map.Biome;
+import com.mithrilmania.blocktopograph.map.MapFragment;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+
+public class SelectionBasedContextFreeEditTask extends
+ AsyncTask {
+
+ @NonNull
+ private final EditFunction mFunction;
+
+ @Nullable
+ private Bundle mArgs;
+
+ @NonNull
+ private final WeakReference mOwner;
+
+ @NonNull
+ private final OldBlockRegistry registry;
+
+ private AlertDialog mWaitDialog;
+
+ public SelectionBasedContextFreeEditTask(
+ @NonNull EditFunction func, @Nullable Bundle args, @NonNull MapFragment owner,
+ @NonNull OldBlockRegistry registry) {
+ mFunction = func;
+ mArgs = args;
+ this.registry = registry;
+ mOwner = new WeakReference<>(owner);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ MapFragment owner = mOwner.get();
+ Activity activity;
+ if (owner == null || (activity = owner.getActivity()) == null) return;
+ mWaitDialog = UiUtil.buildProgressWaitDialog(
+ activity, R.string.general_please_wait, this::onCancel
+ );
+ mWaitDialog.show();
+ owner.world.setHaveBackgroundJob(true);
+ }
+
+ @Override
+ protected EditResultCode doInBackground(EditTarget... editTargets) {
+
+ switch (mFunction) {
+ case LAMPSHADE: {
+ SnrConfig cfg = new SnrConfig();
+ cfg.searchMode = 2;
+ cfg.placeMode = 1;
+ cfg.searchBlockMain = new SnrConfig.SearchConditionBlock(BlockTemplates.getOfType("minecraft:torch")[0].getBlock(), true, true);
+ cfg.placeOldBlockMain = BlockTemplates.getOfType("minecraft:glass")[0].getBlock();
+ cfg.ignoreSubId = true;
+ return doSnr(cfg, editTargets);
+ }
+ case SNR: {
+ Serializable ser;
+ if (mArgs == null || !((ser = mArgs.getSerializable(SearchAndReplaceFragment.CONFIG)) instanceof SnrConfig))
+ return EditResultCode.GENERAL_FAILURE;
+ return doSnr((SnrConfig) ser, editTargets);
+ }
+ case DCHUNK:
+ return doDchunk(editTargets);
+ case CHBIOME: {
+ Serializable serFrom, serTo;
+ if (mArgs == null || !((serTo = mArgs.getSerializable(ChBiomeFragment.KEY_TO)) instanceof Biome))
+ return EditResultCode.GENERAL_FAILURE;
+ serFrom = mArgs.getSerializable(ChBiomeFragment.KEY_FROM);
+ return doChBiome(serFrom instanceof Biome ? (Biome) serFrom : null, (Biome) serTo, editTargets);
+ }
+ }
+ return null;
+ }
+
+ private EditResultCode doSnr(SnrConfig cfg, @NonNull EditTarget... editTargets) {
+ SnrEdit edit = new SnrEdit(cfg);
+ for (EditTarget editTarget : editTargets) {
+ editTarget.setMaxError(Integer.MAX_VALUE);
+ editTarget.forEachXyz(edit);
+ }
+ return EditResultCode.SUCCESS;
+ }
+
+ private EditResultCode doDchunk(@NonNull EditTarget... editTargets) {
+ DchunkEdit edit = new DchunkEdit();
+ for (EditTarget editTarget : editTargets) {
+ editTarget.setMaxError(Integer.MAX_VALUE);
+ editTarget.forEachChunk(edit);
+ }
+ return EditResultCode.SUCCESS;
+ }
+
+ private EditResultCode doChBiome(@Nullable Biome from, @NonNull Biome to,
+ @NonNull EditTarget... editTargets) {
+ ChBiomeEdit edit = new ChBiomeEdit(from, to);
+ for (EditTarget editTarget : editTargets) {
+ editTarget.setMaxError(Integer.MAX_VALUE);
+ editTarget.forEachXz(edit);
+ }
+ return EditResultCode.SUCCESS;
+ }
+
+ private void onCancel(DialogInterface dialogInterface) {
+ cancel(true);
+ mWaitDialog = null;
+ MapFragment owner;
+ if ((owner = mOwner.get()) != null)
+ owner.world.setHaveBackgroundJob(false);
+ }
+
+ @Override
+ protected void onPostExecute(@Nullable EditResultCode editResultCode) {
+ if (mWaitDialog != null) {
+ mWaitDialog.dismiss();
+ }
+ MapFragment owner = mOwner.get();
+ Activity activity;
+ if (owner != null && (activity = owner.getActivity()) != null) {
+ owner.world.setHaveBackgroundJob(false);
+ if (editResultCode == null)
+ return;
+ switch (editResultCode) {
+ case SUCCESS:
+ Toast.makeText(activity, R.string.general_done, Toast.LENGTH_SHORT).show();
+ owner.refreshAfterEdit();
+ break;
+ case DB_ERROR:
+ default:
+ Toast.makeText(activity, R.string.general_failed, Toast.LENGTH_SHORT).show();
+ break;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SnrConfig.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SnrConfig.java
new file mode 100644
index 00000000..b4b98850
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SnrConfig.java
@@ -0,0 +1,81 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+
+import com.google.common.collect.Streams;
+import com.mithrilmania.blocktopograph.block.Block;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Objects;
+
+public class SnrConfig implements Serializable {
+
+ private static final String KEY_SEARCH_IN = "search_in";
+ private static final String KEY_PLACE_IN = "place_in";
+ private static final String KEY_SEARCH_ANY = "search_any";
+ private static final String KEY_SEARCH_BG = "search_bg";
+ private static final String KEY_SEARCH_FG = "search_fg";
+ private static final String KEY_PLACE_ANY = "place_any";
+ private static final String KEY_PLACE_BG = "place_bg";
+ private static final String KEY_PLACE_FG = "place_fg";
+
+ public boolean ignoreSubId;
+ public int searchMode;
+ public int placeMode;
+ public SearchConditionBlock searchBlockMain;
+ public SearchConditionBlock searchBlockSub;
+ public Block placeOldBlockMain;
+ public Block placeOldBlockSub;
+
+ //savedInstanceState.getInt(KEY_SEARCH_IN, 0)
+ //savedInstanceState.getInt(KEY_PLACE_IN, 0)
+ //savedInstanceState.getSerializable(KEY_SEARCH_ANY)
+ //savedInstanceState.getSerializable(KEY_SEARCH_BG)
+ //savedInstanceState.getSerializable(KEY_SEARCH_FG)
+ //savedInstanceState.getSerializable(KEY_PLACE_ANY)
+ //savedInstanceState.getSerializable(KEY_PLACE_BG)
+ //savedInstanceState.getSerializable(KEY_PLACE_FG)
+
+
+// bundle.putInt(KEY_SEARCH_IN, getSearchInCode());
+// bundle.putInt(KEY_PLACE_IN, getPlaceInCode());
+// bundle.putSerializable(KEY_SEARCH_ANY, mBinding.searchBlockAny.getBlock());
+// bundle.putSerializable(KEY_SEARCH_BG, mBinding.searchBlockBg.getBlock());
+// bundle.putSerializable(KEY_SEARCH_FG, mBinding.searchBlockFg.getBlock());
+// bundle.putSerializable(KEY_PLACE_ANY, mBinding.replaceBlockAny.getBlock());
+// bundle.putSerializable(KEY_PLACE_BG, mBinding.replaceBlockBg.getBlock());
+// bundle.putSerializable(KEY_PLACE_FG, mBinding.replaceBlockFg.getBlock());
+
+ public static class SearchConditionBlock implements Serializable {
+ private final Block examplar;
+ private final boolean matchNameOnly;
+ private final boolean allowExtraStates;
+
+ public SearchConditionBlock(@NonNull Block block, boolean matchNameOnly, boolean allowExtraStates) {
+ this.examplar = block;
+ this.matchNameOnly = matchNameOnly;
+ this.allowExtraStates = allowExtraStates;
+ }
+
+ public boolean matches(Block block) {
+ if (!examplar.getName().equals(block.getName())) return false;
+ var examplarKnownProperties = examplar.getKnownProperties();
+ if (examplarKnownProperties != null && Streams.zip(Arrays.stream(examplarKnownProperties),
+ Arrays.stream(block.getKnownProperties()), Pair::new)
+ .anyMatch(pair -> pair.first != null && !Objects.equals(pair.first, pair.second))) {
+ return false;
+ }
+ var examplarCustomProperties = examplar.getCustomProperties();
+ var blockCustomProperties = block.getCustomProperties();
+ if (!allowExtraStates && blockCustomProperties.size() > examplarCustomProperties.size())
+ return false;
+ for (var pair : examplarCustomProperties.entrySet())
+ if (!Objects.equals(pair.getValue(), blockCustomProperties.get(pair.getKey())))
+ return false;
+ return true;
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SnrEdit.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SnrEdit.java
new file mode 100644
index 00000000..4d58f347
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/edit/SnrEdit.java
@@ -0,0 +1,72 @@
+package com.mithrilmania.blocktopograph.map.edit;
+
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.block.Block;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+
+
+public class SnrEdit implements EditTarget.RandomAccessEdit {
+
+ private final SnrConfig config;
+ private SnrConfig.SearchConditionBlock b1;
+ private SnrConfig.SearchConditionBlock b2;
+ private Block b3;
+ private Block b4;
+
+ SnrEdit(@NonNull SnrConfig cfg) {
+ config = cfg;
+ switch (cfg.searchMode) {
+ case 1:
+ case 2:
+ case 3:
+ b1 = cfg.searchBlockMain;
+ break;
+ case 4:
+ b1 = cfg.searchBlockMain;
+ b2 = cfg.searchBlockSub;
+ break;
+ }
+ switch (cfg.placeMode) {
+ case 1:
+ case 2:
+ b3 = cfg.placeOldBlockMain;
+ break;
+ case 3:
+ b3 = cfg.placeOldBlockMain;
+ b4 = cfg.placeOldBlockSub;
+ break;
+ }
+ }
+
+ @Override
+ public int edit(Chunk chunk, int x, int y, int z) {
+ if (
+ (config.searchMode == 1 && b1.matches(chunk.getBlock(x, y, z, 1))
+ ) || (config.searchMode == 2 && b1.matches(chunk.getBlock(x, y, z))
+ ) || (config.searchMode == 3 && (
+ b1.matches(chunk.getBlock(x, y, z))
+ || b1.matches(chunk.getBlock(x, y, z, 1)))
+ ) || (config.searchMode == 4 && (
+ b1.matches(chunk.getBlock(x, y, z))
+ && b2.matches(chunk.getBlock(x, y, z, 1)))
+ )
+ ) {
+ switch (config.placeMode) {
+ case 1:
+ chunk.setBlock(x, y, z, 1, b3);
+ break;
+ case 2:
+ chunk.setBlock(x, y, z, 0, b3);
+ break;
+ case 3:
+ chunk.setBlock(x, y, z, 0, b3);
+ chunk.setBlock(x, y, z, 1, b4);
+ break;
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/AdvancedLocatorFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/AdvancedLocatorFragment.java
new file mode 100644
index 00000000..406353b4
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/AdvancedLocatorFragment.java
@@ -0,0 +1,176 @@
+package com.mithrilmania.blocktopograph.map.locator;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.World;
+import com.mithrilmania.blocktopograph.databinding.FragMapGotoBinding;
+import com.mithrilmania.blocktopograph.map.FloatPaneFragment;
+
+import java.lang.ref.WeakReference;
+
+public final class AdvancedLocatorFragment extends FloatPaneFragment {
+
+ public static final String PREF_KEY_LOCATOR_PAGE = "locator_page";
+ private World mWorld;
+ private LocatorPageFragment.CameraMoveCallback mCameraMoveCallback;
+ private LocatorPagerAdapter mAdapter;
+
+ public static AdvancedLocatorFragment create(World world, LocatorPageFragment.CameraMoveCallback cameraMoveCallback) {
+ AdvancedLocatorFragment ret = new AdvancedLocatorFragment();
+ ret.mWorld = world;
+ ret.mCameraMoveCallback = cameraMoveCallback;
+ return ret;
+ }
+
+ @NonNull
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ FragMapGotoBinding binding = DataBindingUtil.inflate(inflater, R.layout.frag_map_goto, container, false);
+ mAdapter = new LocatorPagerAdapter(getChildFragmentManager(), this);
+ binding.pager.setAdapter(mAdapter);
+ binding.header.close.setOnClickListener(view -> {
+ if (mOnCloseButtonClickListener != null)
+ mOnCloseButtonClickListener.onCloseButtonClick();
+ });
+ Activity act = getActivity();
+ assert act != null;
+ int page = act.getPreferences(Context.MODE_PRIVATE).getInt(PREF_KEY_LOCATOR_PAGE, 1);
+ if (page >= 0 && page < LocatorPagerAdapter.PAGES_COUNT)
+ binding.pager.setCurrentItem(page);
+ binding.pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int i, float v, int i1) {
+ }
+
+ @Override
+ public void onPageSelected(int i) {
+ Activity activity = getActivity();
+ if (activity == null) return;
+ activity.getPreferences(Context.MODE_PRIVATE)
+ .edit()
+ .putInt(PREF_KEY_LOCATOR_PAGE, i)
+ .apply();
+ mAdapter.doOverScroll(i);
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int i) {
+ }
+ });
+ return binding.getRoot();
+ }
+
+ public static class LocatorPagerAdapter extends FragmentPagerAdapter {
+
+ static final int PAGES_COUNT = 3;
+
+ private LocatorPlayersFragment locatorPlayersFragment;
+ private LocatorMarkersFragment locatorMarkersFragment;
+ private LocatorCoordFragment locatorCoordFragment;
+ private WeakReference owner;
+
+ LocatorPagerAdapter(FragmentManager fm, AdvancedLocatorFragment owner) {
+ super(fm);
+ this.owner = new WeakReference<>(owner);
+ }
+
+ @NonNull
+ private LocatorPlayersFragment getLocatorPlayersFragment(
+ @NonNull AdvancedLocatorFragment owner) {
+ if (locatorPlayersFragment == null) {
+ locatorPlayersFragment = LocatorPlayersFragment.create(owner.mWorld);
+ locatorPlayersFragment.mCameraMoveCallback = owner.mCameraMoveCallback;
+ }
+ return locatorPlayersFragment;
+ }
+
+ @NonNull
+ private LocatorMarkersFragment getLocatorMarkersFragment(
+ @NonNull AdvancedLocatorFragment owner) {
+ if (locatorMarkersFragment == null) {
+ locatorMarkersFragment = LocatorMarkersFragment.create(owner.mWorld);
+ locatorMarkersFragment.mCameraMoveCallback = owner.mCameraMoveCallback;
+ }
+ return locatorMarkersFragment;
+ }
+
+ @NonNull
+ private LocatorCoordFragment getLocatorCoordFragment(
+ @NonNull AdvancedLocatorFragment owner) {
+ if (locatorCoordFragment == null) {
+ locatorCoordFragment = LocatorCoordFragment.create();
+ locatorCoordFragment.mCameraMoveCallback = owner.mCameraMoveCallback;
+ }
+ return locatorCoordFragment;
+ }
+
+ void doOverScroll(int i) {
+ if (i == 0 && locatorCoordFragment != null)
+ locatorCoordFragment.doOverScroll();
+ }
+
+ @Nullable
+ @Override
+ public CharSequence getPageTitle(int position) {
+ AdvancedLocatorFragment owner = this.owner.get();
+ if (owner == null) return null;
+ switch (position) {
+ case 1:
+ return owner.getString(R.string.locator_page_player);
+ case 2:
+ return owner.getString(R.string.locator_page_marker);
+ case 0:
+ return owner.getString(R.string.locator_page_coor);
+ default:
+ return null;
+ }
+ }
+
+ @NonNull
+ private Fragment getAnyPlaceHolderFragment() {
+ if (locatorPlayersFragment != null) return locatorPlayersFragment;
+ if (locatorMarkersFragment != null) return locatorMarkersFragment;
+ if (locatorCoordFragment != null) return locatorCoordFragment;
+ throw new RuntimeException();
+ }
+
+ @Override
+ @NonNull
+ public Fragment getItem(int i) {
+ AdvancedLocatorFragment owner = this.owner.get();
+ if (owner == null) {
+ // Try not trigger a crash.
+ return getAnyPlaceHolderFragment();
+ }
+ switch (i) {
+ case 1:
+ return getLocatorPlayersFragment(owner);
+ case 2:
+ return getLocatorMarkersFragment(owner);
+ case 0:
+ return getLocatorCoordFragment(owner);
+ default:
+ return getAnyPlaceHolderFragment();
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return PAGES_COUNT;
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorCoordFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorCoordFragment.java
new file mode 100644
index 00000000..450ff6a6
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorCoordFragment.java
@@ -0,0 +1,55 @@
+package com.mithrilmania.blocktopograph.map.locator;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.databinding.DataBindingUtil;
+
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.databinding.FragLocatorCoordBinding;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+public final class LocatorCoordFragment extends LocatorPageFragment {
+
+ private FragLocatorCoordBinding mBinding;
+
+ @NonNull
+
+ public static LocatorCoordFragment create() {
+ return new LocatorCoordFragment();
+ }
+
+ private void onClickGo(View view) {
+ if (mCameraMoveCallback != null) {
+ int x, z;
+ x = UiUtil.readIntFromView(mBinding.editX);
+ z = UiUtil.readIntFromView(mBinding.editZ);
+ mCameraMoveCallback.moveCamera(x, z);
+ }
+ }
+
+ @NonNull
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ mBinding = DataBindingUtil.inflate(
+ inflater, R.layout.frag_locator_coord, container, false);
+ mBinding.buttonGo.setOnClickListener(this::onClickGo);
+ mBinding.editZ.setOnEditorActionListener((textView, i, keyEvent) -> {
+ if (i == 233 && keyEvent != null) {
+ onClickGo(null);
+ return true;
+ }
+ return false;
+ });
+ return mBinding.getRoot();
+ }
+
+ public void doOverScroll() {
+ mBinding.scroll.doOverScroll();
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorMarkersFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorMarkersFragment.java
new file mode 100644
index 00000000..6795c97d
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorMarkersFragment.java
@@ -0,0 +1,170 @@
+package com.mithrilmania.blocktopograph.map.locator;
+
+import android.app.Activity;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.databinding.DataBindingUtil;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.World;
+import com.mithrilmania.blocktopograph.databinding.FragLocatorPlayersBinding;
+import com.mithrilmania.blocktopograph.databinding.ItemLocatorMarkerBinding;
+import com.mithrilmania.blocktopograph.map.marker.AbstractMarker;
+
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+
+public final class LocatorMarkersFragment extends LocatorPageFragment {
+
+ private FragLocatorPlayersBinding mBinding;
+ private World mWorld;
+
+ public static LocatorMarkersFragment create(World world) {
+ LocatorMarkersFragment ret = new LocatorMarkersFragment();
+ ret.mWorld = world;
+ return ret;
+ }
+
+ @NonNull
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ mBinding = DataBindingUtil.inflate(
+ inflater, R.layout.frag_locator_players, container, false);
+ new LoadingTask(this).execute(mWorld);
+ return mBinding.getRoot();
+ }
+
+ private static class MarkersAdapter extends RecyclerView.Adapter {
+
+ @NonNull
+ private final WeakReference owner;
+
+ @NonNull
+ private final AbstractMarker[] markers;
+
+ MarkersAdapter(@NonNull WeakReference owner, @NonNull AbstractMarker[] markers) {
+ this.owner = owner;
+ this.markers = markers;
+ }
+
+ @NonNull
+ @Override
+ public MeowHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ LocatorPageFragment owner = this.owner.get();
+ LayoutInflater inflater;
+ if (owner != null) inflater = owner.getLayoutInflater();
+ else inflater = LayoutInflater.from(viewGroup.getContext());
+
+ ItemLocatorMarkerBinding binding = DataBindingUtil.inflate(
+ inflater, R.layout.item_locator_marker,
+ viewGroup, false
+ );
+ MeowHolder meowHolder = new MeowHolder(binding.getRoot());
+ meowHolder.binding = binding;
+ return meowHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull MeowHolder meowHolder, int i) {
+ AbstractMarker marker = markers[i];
+ meowHolder.binding.setMarker(marker);
+ }
+
+ @Override
+ public int getItemCount() {
+ return markers.length;
+ }
+
+ class MeowHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
+
+ ItemLocatorMarkerBinding binding;
+
+ MeowHolder(@NonNull View itemView) {
+ super(itemView);
+ itemView.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ LocatorPageFragment owner = MarkersAdapter.this.owner.get();
+ if (owner == null) return;
+ if (owner.mCameraMoveCallback != null) {
+ int index = getAdapterPosition();
+ AbstractMarker marker = markers[index];
+ owner.mCameraMoveCallback.moveCamera(marker.x, marker.z);
+ }
+ }
+ }
+
+ }
+
+ private static class LoadingTask extends AsyncTask {
+
+ private final WeakReference owner;
+
+ private LoadingTask(LocatorMarkersFragment owner) {
+ this.owner = new WeakReference<>(owner);
+ }
+
+ @Nullable
+ @Override
+ protected AbstractMarker[] doInBackground(World... worlds) {
+ try {
+ World world;
+ if (worlds.length != 1 || (world = worlds[0]) == null) return null;
+
+ Collection markers;
+ try {
+ markers = world.getMarkerManager().getMarkers();
+ } catch (Exception e) {
+ Log.d(this, e);
+ return null;
+ }
+
+ if (markers == null) return null;
+ if (markers.isEmpty()) return new AbstractMarker[0];
+ try {
+ return markers.toArray(new AbstractMarker[0]);
+ } catch (Exception e) {
+ Log.d(this, e);
+ return null;
+ }
+
+ } catch (Exception e) {
+ Log.d(this, e);
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(AbstractMarker[] markers) {
+ LocatorMarkersFragment owner = this.owner.get();
+ Activity activity;
+ if (owner == null || (activity = owner.getActivity()) == null) return;
+ owner.mBinding.loading.setVisibility(View.GONE);
+ if (markers == null) {
+ owner.mBinding.empty.setVisibility(View.VISIBLE);
+ owner.mBinding.empty.setText(R.string.general_failed);
+ } else if (markers.length == 0) {
+ owner.mBinding.empty.setVisibility(View.VISIBLE);
+ owner.mBinding.empty.setText(R.string.no_custom_markers);
+ } else {
+ owner.mBinding.list.setLayoutManager(
+ new LinearLayoutManager(activity));
+ owner.mBinding.list.setAdapter(
+ new MarkersAdapter(new WeakReference<>(owner), markers));
+ owner.mBinding.list.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorPageFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorPageFragment.java
new file mode 100644
index 00000000..7857537d
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorPageFragment.java
@@ -0,0 +1,14 @@
+package com.mithrilmania.blocktopograph.map.locator;
+
+import androidx.fragment.app.Fragment;
+
+public abstract class LocatorPageFragment extends Fragment {
+
+ protected CameraMoveCallback mCameraMoveCallback;
+
+ public interface CameraMoveCallback {
+
+ void moveCamera(double x, double z);
+
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorPlayersFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorPlayersFragment.java
new file mode 100644
index 00000000..d7cee04f
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/locator/LocatorPlayersFragment.java
@@ -0,0 +1,167 @@
+package com.mithrilmania.blocktopograph.map.locator;
+
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.databinding.DataBindingUtil;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.World;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.databinding.FragLocatorPlayersBinding;
+import com.mithrilmania.blocktopograph.databinding.ItemLocatorPlayerBinding;
+import com.mithrilmania.blocktopograph.map.Player;
+import com.mithrilmania.blocktopograph.util.math.DimensionVector3;
+
+import java.lang.ref.WeakReference;
+
+public final class LocatorPlayersFragment extends LocatorPageFragment {
+
+ private FragLocatorPlayersBinding mBinding;
+ private World mWorld;
+
+ public static LocatorPlayersFragment create(World world) {
+ LocatorPlayersFragment ret = new LocatorPlayersFragment();
+ ret.mWorld = world;
+ return ret;
+ }
+
+ @NonNull
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ mBinding = DataBindingUtil.inflate(
+ inflater, R.layout.frag_locator_players, container, false);
+ new LoadingTask(this).execute(mWorld);
+ return mBinding.getRoot();
+ }
+
+ private static class PlayersAdapter extends RecyclerView.Adapter {
+
+ private final WeakReference owner;
+ private final Player[] players;
+
+ PlayersAdapter(WeakReference owner, Player[] players) {
+ this.owner = owner;
+ this.players = players;
+ }
+
+ @NonNull
+ @Override
+ public MeowHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ LocatorPageFragment owner = this.owner.get();
+ assert owner != null;
+ ItemLocatorPlayerBinding binding = DataBindingUtil.inflate(
+ owner.getLayoutInflater(), R.layout.item_locator_player,
+ viewGroup, false
+ );
+ MeowHolder meowHolder = new MeowHolder(binding.getRoot());
+ meowHolder.binding = binding;
+ return meowHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull MeowHolder meowHolder, int i) {
+ Player player = players[i];
+ meowHolder.binding.setPlayer(player);
+ }
+
+ @Override
+ public int getItemCount() {
+ return players.length;
+ }
+
+ class MeowHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
+
+ ItemLocatorPlayerBinding binding;
+
+ MeowHolder(@NonNull View itemView) {
+ super(itemView);
+ itemView.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ LocatorPageFragment owner = PlayersAdapter.this.owner.get();
+ if (owner == null) return;
+ if (owner.mCameraMoveCallback != null) {
+ int index = getAdapterPosition();
+ DimensionVector3 pos = players[index].getPosition();
+ if (pos != null)
+ owner.mCameraMoveCallback.moveCamera(pos.x, pos.z);
+ }
+ }
+ }
+
+ }
+
+ private static class LoadingTask extends AsyncTask {
+
+ private final WeakReference owner;
+
+ private LoadingTask(LocatorPlayersFragment owner) {
+ this.owner = new WeakReference<>(owner);
+ }
+
+ @Override
+ protected Player[] doInBackground(World... worlds) {
+ World world;
+ if (worlds.length != 1 || (world = worlds[0]) == null) return null;
+ WorldData worldData = world.getWorldData();
+ try {
+ worldData.openDB();
+ DimensionVector3 localPlayerPos = world.getPlayerPos();
+ String[] mlst = worldData.getNetworkPlayerNames();
+ Player[] players;
+ int offset;
+ if (localPlayerPos == null) {
+ players = new Player[mlst.length];
+ offset = 0;
+ } else {
+ players = new Player[mlst.length + 1];
+ offset = 1;
+ players[0] = Player.localPlayer();
+ players[0].setPosition(localPlayerPos);
+ }
+ for (int i = 0; i < mlst.length; i++) {
+ Player player = Player.networkPlayer(mlst[i]);
+ try {
+ player.setPosition(world.getMultiPlayerPos(mlst[i]));
+ } catch (Exception e) {
+ Log.d(this, e);
+ }
+ players[i + offset] = player;
+ }
+ return players;
+ } catch (Exception e) {
+ Log.d(this, e);
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Player[] players) {
+ LocatorPlayersFragment owner = this.owner.get();
+ if (owner == null) return;
+ owner.mBinding.loading.setVisibility(View.GONE);
+ if (players == null || players.length == 0) {
+ owner.mBinding.empty.setVisibility(View.VISIBLE);
+ owner.mBinding.empty.setText(R.string.failed_find_player);
+ } else {
+ owner.mBinding.list.setLayoutManager(
+ new LinearLayoutManager(owner.getActivity()));
+ owner.mBinding.list.setAdapter(
+ new PlayersAdapter(new WeakReference<>(owner), players));
+ owner.mBinding.list.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/AbstractMarker.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/AbstractMarker.java
index cde65996..fb1ce417 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/AbstractMarker.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/AbstractMarker.java
@@ -1,9 +1,10 @@
package com.mithrilmania.blocktopograph.map.marker;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.widget.ImageView;
+import com.mithrilmania.blocktopograph.R;
import com.mithrilmania.blocktopograph.map.Dimension;
import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
import com.mithrilmania.blocktopograph.util.NamedBitmapProviderHandle;
@@ -27,25 +28,33 @@ public AbstractMarker(int x, int y, int z, Dimension dimension, NamedBitmapProvi
this.isCustom = isCustom;
}
- public int getChunkX(){
+ public String getPositionDescription(Context context) {
+ return context.getString(R.string.player_position_desc,
+ Math.round(x), Math.round(y),
+ Math.round(z), context.getString(dimension.getName()));
+ }
+
+ public int getChunkX() {
return x >> 4;
}
- public int getChunkZ(){
+ public int getChunkZ() {
return z >> 4;
}
public MarkerImageView view;
public MarkerImageView getView(Context context) {
- if(view != null) return view;
- view = new MarkerImageView(context, this);
- this.loadIcon(view);
+ if (view == null) {
+ view = new MarkerImageView(context, this);
+ this.loadIcon(view);
+ }
return view;
}
/**
* Loads the provided bitmap into the image view.
+ *
* @param iconView The view to load the icon into.
*/
public void loadIcon(ImageView iconView) {
@@ -70,10 +79,10 @@ public boolean equals(Object o) {
AbstractMarker that = (AbstractMarker) o;
return x == that.x
- && y == that.y
- && z == that.z
- && dimension == that.dimension
- && (namedBitmapProvider != null
+ && y == that.y
+ && z == that.z
+ && dimension == that.dimension
+ && (namedBitmapProvider != null
? namedBitmapProvider.equals(that.namedBitmapProvider)
: that.namedBitmapProvider == null);
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/CustomNamedBitmapProvider.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/CustomNamedBitmapProvider.java
index 4a517cd0..452d9e18 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/CustomNamedBitmapProvider.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/CustomNamedBitmapProvider.java
@@ -2,7 +2,7 @@
import android.graphics.Bitmap;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.mithrilmania.blocktopograph.util.NamedBitmapProvider;
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/MarkerImageView.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/MarkerImageView.java
index 49000ed7..4530cd40 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/MarkerImageView.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/marker/MarkerImageView.java
@@ -6,7 +6,7 @@
/**
* TODO docs
*/
-public class MarkerImageView extends android.support.v7.widget.AppCompatImageView {
+public class MarkerImageView extends androidx.appcompat.widget.AppCompatImageView {
private final AbstractMarker markerHook;
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/AnalyzeTask.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/AnalyzeTask.java
new file mode 100644
index 00000000..bc6f8aa2
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/AnalyzeTask.java
@@ -0,0 +1,219 @@
+package com.mithrilmania.blocktopograph.map.picer;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.AsyncTask;
+
+import com.litl.leveldb.DB;
+import com.litl.leveldb.Iterator;
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.World;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.chunk.Version;
+import com.mithrilmania.blocktopograph.map.Dimension;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.appcompat.app.AlertDialog;
+
+class AnalyzeTask extends AsyncTask {
+
+ private final WeakReference owner;
+ private boolean hasWrongChunks;
+ private boolean hasOldChunks;
+ private AlertDialog waitDialog;
+
+ AnalyzeTask(PicerFragment owner) {
+ this.owner = new WeakReference<>(owner);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ PicerFragment owner = this.owner.get();
+ Activity activity;
+ if (owner == null || (activity = owner.getActivity()) == null) {
+ cancel(true);
+ return;
+ }
+ waitDialog = UiUtil.buildProgressWaitDialog(activity, R.string.picer_progress_analyzing,
+ dialogInterface -> {
+ PicerFragment diaFrag = AnalyzeTask.this.owner.get();
+ if (diaFrag != null) diaFrag.dismiss();
+ });
+ waitDialog.show();
+ }
+
+ @Override
+ @Nullable
+ protected Rect doInBackground(Void... voids) {
+
+ PicerFragment owner = this.owner.get();
+ if (owner == null) return null;
+
+ // Get db.
+ DB db = null;
+ getDb:
+ {
+ World world = owner.mWorld;
+ if (world == null) break getDb;
+ WorldData worldData = world.getWorldData();
+ try {
+ worldData.openDB();
+ } catch (Exception e) {
+ break getDb;
+ }
+ db = worldData.db;
+ }
+ if (db == null) return null;
+
+ Dimension dimension = owner.mDimension;
+ int verKeyLenOfDim;
+ switch (dimension) {
+ case OVERWORLD:
+ verKeyLenOfDim = 9;
+ break;
+ case NETHER:
+ case END:
+ verKeyLenOfDim = 13;
+ break;
+ default:
+ return null;
+ }
+
+ // We used to separate world into areas or clusters, now that
+ // we have selection so just measure whole world here.
+ // If it's too large we just say select before using this.
+ //List areas = new ArrayList<>(32);
+ //Area.maxDist = 10;
+ Rect rect = null;
+
+ // Iterate over all items.
+ try {
+ db.put(new byte[]{0, 1, 2, 3, 0, 1, 2, 3, 118}, new byte[]{0});
+ Iterator iterator = db.iterator();
+ boolean cancelled = false;
+ int loopCount = 0;
+ loop:
+ for (iterator.seekToFirst(); iterator.isValid(); iterator.next(), loopCount++) {
+
+ if (isCancelled()) {
+ cancelled = true;
+ break;
+ }
+
+ // Is it a key for a chunk of current dim's version record?
+ byte[] key = iterator.getKey();
+ if (key.length != verKeyLenOfDim) continue;
+ if (key[verKeyLenOfDim - 1] != (byte) 0x76) continue;
+ ByteBuffer byteBuffer = ByteBuffer.wrap(key);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ int x = byteBuffer.getInt();
+ int z = byteBuffer.getInt();
+ // Wrong dim.
+ if (verKeyLenOfDim == 13 && dimension.id != byteBuffer.getInt()) continue;
+ byte[] value = iterator.getValue();
+ Version version = Version.getVersion(value);
+ // Record unsupported stuff and skip.
+ switch (version) {
+ case ERROR:
+ case NULL:
+ hasWrongChunks = true;
+ continue loop;
+ case OLD_LIMITED:
+ hasOldChunks = true;
+ continue loop;
+ }
+
+ if (rect != null) {
+ if (x < rect.left) rect.left = x;
+ else if (x > rect.right) rect.right = x;
+ if (z < rect.top) rect.top = z;
+ else if (z > rect.bottom) rect.bottom = z;
+ if (rect.right - rect.left > PicerFragment.MAX_LENGTH
+ || rect.bottom - rect.top > PicerFragment.MAX_LENGTH
+ || loopCount % 36 == 0 && (rect.right - rect.left) * (rect.bottom - rect.top) > PicerFragment.MAX_AREA)
+ break;
+ } else {
+ rect = new Rect(x, z, x, z);
+ }
+
+ // Add the chunk to area list.
+// add:
+// {
+// for (Area area : areas) {
+// // Try add to existing areas.
+// if (area.add(x, z)) break add;
+// }
+// // Failed then create new.
+// areas.add(new Area(x, z));
+// }
+// // As more chunks were read maybe we can merge more of them.
+// if (loopCount > 16) Area.absMergeList(areas);
+ }
+ iterator.close();
+ if (cancelled) return null;
+ } catch (Throwable e) {
+ Log.d(this, e);
+ return null;
+ }
+
+ // Final merge. Redundant? Who cares.
+// Area.absMergeList(areas);
+//
+// owner = this.owner.get();
+// if (owner == null) return null;
+//
+// if (areas.size() == 0) return null;
+// if (areas.size() == 1) return areas.get(0);
+//
+// // Then should decide which area to use based on camera position.
+// // For not let's ignore.
+// return areas.get(0);
+ if (rect != null) {
+ rect.left *= 16;
+ rect.top *= 16;
+ rect.right *= 16 + 15;
+ rect.bottom *= 16 + 15;
+ }
+ return rect;
+ }
+
+ @Override
+ protected void onCancelled() {
+ PicerFragment owner = this.owner.get();
+ if (owner != null) {
+ owner.mOngoingTask = null;
+ waitDialog.dismiss();
+ }
+ }
+
+ @Override
+ protected void onPostExecute(@Nullable Rect rect) {
+
+ // We finished too late. No longer needed.
+ PicerFragment owner = this.owner.get();
+ if (owner == null) return;
+ owner.mOngoingTask = null;
+ waitDialog.dismiss();
+
+ if (rect != null) {
+ owner.onAnalyzeDone(rect);
+
+ } else if (hasWrongChunks || hasOldChunks) {
+ // Size 0 with exception, dismiss and show exception in dialog.
+ @StringRes int strId;
+ if (hasWrongChunks) strId = R.string.picer_failed_corrupt;
+ else strId = R.string.picer_failed_old;
+ owner.showFailureDialogAndDismiss(strId);
+
+ // Otherwise a toast is enough.
+ } else owner.showFailureMsgAndDismiss(R.string.picer_failed_nodata);
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/Area.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/Area.java
new file mode 100644
index 00000000..0545c289
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/Area.java
@@ -0,0 +1,96 @@
+package com.mithrilmania.blocktopograph.map.picer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+public class Area {
+
+ static int maxDist;
+
+ int mMinX;
+ int mMinZ;
+ int mMaxX;
+ int mMaxZ;
+ private final List mList;
+
+ Area(int firstX, int firstZ) {
+ mMaxX = mMinX = firstX;
+ mMaxZ = mMinZ = firstZ;
+ mList = new ArrayList<>(16);
+ }
+
+ boolean add(int x, int z) {
+ if (x >= mMinX - maxDist && x <= mMaxX + maxDist
+ && z >= mMinZ - maxDist && z <= mMaxZ + maxDist) {
+ if (x < mMinX) mMinX = x;
+ else if (x > mMaxX) mMaxX = x;
+ if (z < mMinZ) mMinZ = z;
+ else if (z > mMaxZ) mMaxZ = z;
+ mList.add(new Member(x, z));
+ return true;
+ }
+ return false;
+ }
+
+ private boolean absMerge(@NonNull Area another) {
+ if (another.mMaxX >= mMinX - maxDist && another.mMinX <= mMaxX + maxDist
+ && another.mMaxZ >= mMinZ - maxDist && another.mMinZ <= mMaxZ + maxDist) {
+ if (another.mMinX < mMinX) mMinX = another.mMinX;
+ else if (another.mMaxX > mMaxX) mMaxX = another.mMaxX;
+ if (another.mMinZ < mMinZ) mMinZ = another.mMinZ;
+ else if (another.mMaxZ > mMaxZ) mMaxZ = another.mMaxZ;
+ mList.addAll(another.mList);
+ return true;
+ }
+ return false;
+ }
+
+ static void absMergeList(@NonNull List list) {
+ boolean hasOp;
+ do {
+ hasOp = false;
+ for (int i = list.size() - 1; i > 0; i--) {
+ Area toBeMerged = list.get(i);
+ assert toBeMerged != null;
+ for (int j = 0; j < i; j++) {
+ if (list.get(j).absMerge(toBeMerged)) {
+ list.remove(toBeMerged);
+ hasOp = true;
+ break;
+ }
+ }
+ }
+ } while (hasOp);
+ }
+
+ @NonNull
+ List getList() {
+ return mList;
+ }
+
+ int calculateArea() {
+ return (mMaxX - mMinX) * (mMaxZ - mMinZ);
+ }
+
+ public int width() {
+ return mMaxX - mMinX;
+ }
+
+ public int height() {
+ return mMaxZ - mMinZ;
+ }
+
+ class Member {
+
+ public int x;
+ public int z;
+
+ Member(int x, int z) {
+ this.x = x;
+ this.z = z;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/GenerateThread.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/GenerateThread.java
new file mode 100644
index 00000000..efbf24e7
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/GenerateThread.java
@@ -0,0 +1,113 @@
+package com.mithrilmania.blocktopograph.map.picer;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentActivity;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.map.Dimension;
+import com.mithrilmania.blocktopograph.map.edit.RectEditTarget;
+import com.mithrilmania.blocktopograph.map.renderer.MapRenderer;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+class GenerateThread extends Thread {
+
+ private final Rect area;
+ private final WeakReference owner;
+ private final int scale;
+ private final Bitmap.Config config;
+ private final WeakReference dialog;
+
+ private boolean cancelled;
+
+ GenerateThread(PicerFragment owner, Rect area, int scale, Bitmap.Config config,
+ AlertDialog dialog) {
+ this.owner = new WeakReference<>(owner);
+ this.area = area;
+ this.scale = scale;
+ this.config = config;
+ this.dialog = new WeakReference<>(dialog);
+ }
+
+ @Override
+ public void run() {
+
+ PicerFragment owner = this.owner.get();
+ if (owner == null) return;
+
+ Dimension dimension = owner.mDimension;
+ MapRenderer renderer = dimension.defaultMapType.renderer;
+ WorldData wdata = owner.mWorld.getWorldData();
+
+ int width = area.right - area.left + 1;
+ int height = area.bottom - area.top + 1;
+
+ Bitmap bitmap = Bitmap.createBitmap(width * scale, height * scale, config);
+ Canvas canvas = new Canvas(bitmap);
+
+ int poolSize = 5;
+
+ ExecutorService executor =
+ new ThreadPoolExecutor(poolSize, poolSize, 0, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(poolSize << 1),
+ new ThreadPoolExecutor.CallerRunsPolicy());
+
+ ThreadLocal paintSub = new ThreadLocal() {
+ @NonNull
+ @Override
+ protected Paint initialValue() {
+ return new Paint();
+ }
+ };
+
+ new RectEditTarget(wdata, area, dimension).forEachChunk(
+ (chunk, fromX, toX, fromY, toY, fromZ, toZ) -> {
+ if (cancelled) {
+ executor.shutdownNow();
+ return 0;
+ }
+ executor.execute(() -> {
+ try {
+ renderer.renderToBitmap(chunk, canvas, dimension, chunk.mChunkX, chunk.mChunkZ,
+ (chunk.mChunkX * 16 - area.left) * scale,
+ (chunk.mChunkZ * 16 - area.top) * scale,
+ scale, scale, paintSub.get(), wdata);
+ } catch (Exception e) {
+ Log.d(this, e);
+ }
+ });
+ return 0;
+ });
+ executor.shutdown();
+ try {
+ executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return;
+ }
+
+ owner = this.owner.get();
+ if (owner == null) return;
+
+ FragmentActivity activity = owner.getActivity();
+ if (activity != null)
+ activity.runOnUiThread(() -> this.owner.get().onGenerationDone(bitmap, dialog.get()));
+
+ owner.mOngoingThread = null;
+ }
+
+ void cancel() {
+ cancelled = true;
+ interrupt();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/PicerFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/PicerFragment.java
new file mode 100644
index 00000000..808d97e9
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/PicerFragment.java
@@ -0,0 +1,336 @@
+package com.mithrilmania.blocktopograph.map.picer;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+import android.widget.SeekBar;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.annotation.UiThread;
+import androidx.appcompat.app.AlertDialog;
+import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.DialogFragment;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.DataSource;
+import com.bumptech.glide.load.engine.GlideException;
+import com.bumptech.glide.request.RequestListener;
+import com.bumptech.glide.request.target.Target;
+import com.google.android.material.snackbar.Snackbar;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.World;
+import com.mithrilmania.blocktopograph.databinding.FragPicerBinding;
+import com.mithrilmania.blocktopograph.map.Dimension;
+import com.mithrilmania.blocktopograph.map.OpenLongPressMenuHandler;
+import com.mithrilmania.blocktopograph.util.ConvertUtil;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.io.File;
+
+public final class PicerFragment extends DialogFragment {
+
+ public static final int MAX_LENGTH = 2048;
+ public static final int MAX_AREA = 64 * 64 * 256;
+ public static final int MAX_SCALE = 32;
+ private FragPicerBinding mBinding;
+ Rect mRange;
+
+ World mWorld;
+ Dimension mDimension;
+ AsyncTask mOngoingTask;
+ private int stage = 0;
+ GenerateThread mOngoingThread;
+ private OpenLongPressMenuHandler mOpenLongPressMenuHandler;
+
+ public static PicerFragment create(@NonNull World world, @NonNull Dimension dimension,
+ @Nullable Rect range, @Nullable OpenLongPressMenuHandler openLongPressMenuHandler) {
+ PicerFragment ret = new PicerFragment();
+ ret.mWorld = world;
+ ret.mDimension = dimension;
+ ret.mRange = range;
+ ret.mOpenLongPressMenuHandler = openLongPressMenuHandler;
+ return ret;
+ }
+
+ private static boolean rangeCheck(@NonNull Rect rect) {
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ return width <= MAX_LENGTH && height <= MAX_LENGTH && width * height <= MAX_AREA;
+ }
+
+ @NonNull
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ mBinding = DataBindingUtil.inflate(inflater, R.layout.frag_picer,
+ container, false);
+ mBinding.finalButton.setOnClickListener(this::onClickFinalButton);
+ mBinding.scaleSeek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+ mBinding.setScale(i + 1);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ View root = mBinding.getRoot();
+ Dialog dialog = getDialog();
+ if (dialog instanceof AlertDialog)
+ ((AlertDialog) dialog).setView(root);
+ if (mRange == null)
+ root.post(() -> mOngoingTask = new AnalyzeTask(this).execute());
+ else goToScalePhase();
+ return root;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ AlertDialog dialog = new AlertDialog.Builder(new ContextThemeWrapper(requireContext(), R.style.AppTheme_Dialog))
+ .setTitle(R.string.picer_title)
+ .create();
+ dialog.setCanceledOnTouchOutside(false);
+ return dialog;
+ }
+
+ @Override
+ public void onDismiss(@NonNull DialogInterface dialog) {
+ super.onDismiss(dialog);
+ if (mOngoingTask != null) mOngoingTask.cancel(true);
+ if (mOngoingThread != null) mOngoingThread.cancel();
+ }
+
+ // Result callbacks from AnalyzeTask.
+
+ @UiThread
+ void showFailureDialogAndDismiss(@StringRes int resId) {
+ Activity activity = getActivity();
+ if (activity == null) return;
+ AlertDialog dialog = new AlertDialog.Builder(activity)
+ .setMessage(resId)
+ .create();
+ dialog.show();
+ dismiss();
+ }
+
+ @UiThread
+ void showFailureMsgAndDismiss(@StringRes int resId) {
+ Activity activity = getActivity();
+ if (activity == null) return;
+ Toast.makeText(activity, resId, Toast.LENGTH_SHORT).show();
+ dismiss();
+ }
+
+ private void goToScalePhase() {
+ Activity activity = getActivity();
+ if (activity == null) return;
+ mBinding.selectCase.setVisibility(View.VISIBLE);
+ int w = mRange.right - mRange.left;
+ int h = mRange.bottom - mRange.top;
+ if (w <= 0 || h <= 0) {
+ dismiss();
+ return;
+ }
+ int len = w > h ? w : h;
+ int maxScale = MAX_LENGTH / len;
+ len = w * h;
+ w = MAX_AREA / len;
+ if (w < maxScale) maxScale = w;
+ if (maxScale <= 0) {
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.map_picer_selection_too_large)
+ .setMessage(getString(R.string.map_picer_selection_too_large_detail, MAX_LENGTH, MAX_AREA))
+ .setPositiveButton(android.R.string.ok, null)
+ .create()
+ .show();
+ dismiss();
+ return;
+ } else if (maxScale == 1) {
+ mBinding.scaleBox.setVisibility(View.GONE);
+ mBinding.scaleNot.setVisibility(View.VISIBLE);
+ } else {
+ if (MAX_SCALE < maxScale) maxScale = MAX_SCALE;
+ mBinding.scaleBox.setVisibility(View.VISIBLE);
+ mBinding.scaleNot.setVisibility(View.GONE);
+ mBinding.scaleSeek.setMax(maxScale - 1);
+ mBinding.scaleSeek.setProgress(maxScale - 1);
+ }
+ stage = 1;
+ mBinding.finalButton.setVisibility(View.VISIBLE);
+ mBinding.finalButton.setText(R.string.picer_btn_generate);
+// Minimal 16x16 px per chunk.
+// int size = area.calculateArea() * 256;
+//
+// // Oops.
+// if (size > MAX_PIXELS) {
+// showFailureDialogAndDismiss(R.string.picer_failed_too_large);
+// return;
+// }
+//
+// // How many levels could we scale.
+// int levels = 1;
+// for (int m = size; m <= MAX_PIXELS / 2; levels++) m *= 4;
+//
+// if (levels == 1) {
+// // Cannot scale at all.
+// mBinding.scaleBox.setVisibility(View.GONE);
+// mBinding.scaleNot.setVisibility(View.VISIBLE);
+// mBinding.scaleSeek.setMax(1);
+// mBinding.scaleSeek.setProgress(1);
+// } else {
+// mBinding.scaleSeek.setMax(levels - 1);
+// mBinding.scaleSeek.setProgress(levels - 1);
+// }
+// mBinding.selectCase.setVisibility(View.VISIBLE);
+// mBinding.setArea(area);
+//
+// mBinding.finalButton.setVisibility(View.VISIBLE);
+// mBinding.finalButton.setText(R.string.picer_btn_generate);
+ }
+
+ @UiThread
+ private void onClickFinalButton(@NonNull View view) {
+ switch (stage) {
+ case 1:
+ onClickGenerate();
+ break;
+ case 2:
+ onClickSave(view);
+ break;
+ }
+ }
+
+ @UiThread
+ void onAnalyzeDone(@NonNull Rect rect) {
+
+ Activity activity = getActivity();
+ if (activity == null) return;
+
+ if (rangeCheck(rect)) {
+ mRange = rect;
+ goToScalePhase();
+ } else {
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.map_picer_world_too_large)
+ .setMessage(R.string.map_picer_use_selection_instead)
+ .setPositiveButton(android.R.string.ok, (dia, i) -> mOpenLongPressMenuHandler.open())
+ .create().show();
+ dismiss();
+ }
+ }
+
+ // Callback from .
+
+ @UiThread
+ private void onClickGenerate() {
+ Activity activity = getActivity();
+ if (activity == null) return;
+
+ int scale = mBinding.scaleSeek.getProgress() + 1;
+ AlertDialog dialog = UiUtil.buildProgressWaitDialog(
+ activity, R.string.picer_progress_generating, dialogInterface -> dismiss());
+ dialog.show();
+
+ mBinding.finalButton.setVisibility(View.GONE);
+ mBinding.selectCase.setVisibility(View.GONE);
+
+ mOngoingThread = new GenerateThread(this, mRange, scale, Bitmap.Config.ARGB_8888, dialog);
+ mOngoingThread.start();
+ }
+
+ @UiThread
+ void onGenerationDone(@Nullable Bitmap bitmap, @Nullable AlertDialog dialog) {
+
+ if (dialog != null) dialog.dismiss();
+
+ if (bitmap == null) {
+ Activity activity = getActivity();
+ if (activity != null) Toast.makeText(
+ activity, R.string.general_failed, Toast.LENGTH_SHORT).show();
+ dismiss();
+ return;
+ }
+
+ stage = 2;
+ mBinding.finalButton.setVisibility(View.VISIBLE);
+ mBinding.finalButton.setText(R.string.picer_save);
+ mBinding.finalButton.setTag(bitmap);
+ mBinding.previewCase.setVisibility(View.VISIBLE);
+
+ Glide.with(this).load(bitmap).listener(new RequestListener() {
+ @Override
+ public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
+ // How could.
+ return false;
+ }
+
+ @Override
+ public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
+ mBinding.scroll.post(() ->
+ mBinding.scroll.fullScroll(ScrollView.FOCUS_DOWN));
+ return false;
+ }
+ }).into(mBinding.image);
+
+ }
+
+ @UiThread
+ private void onClickSave(@NonNull View view) {
+ Object o = view.getTag();
+ if (!(o instanceof Bitmap)) return;
+ Bitmap bmp = (Bitmap) o;
+ view.setTag(null);
+ String name = mWorld.getWorldDisplayName();
+ name = ConvertUtil.getLegalFileName(name);
+ new SaveTask(this, name).execute(bmp);
+ }
+
+ @UiThread
+ void onSavedBitmap(@Nullable File file) {
+ Activity activity = getActivity();
+ if (activity == null) return;
+ if (file == null)
+ Toast.makeText(activity, R.string.general_failed, Toast.LENGTH_SHORT).show();
+ else {
+ MediaScannerConnection.scanFile(activity,
+ new String[]{file.getAbsolutePath()},
+ new String[]{"image/png"}, null);
+ Snackbar snackbar = Snackbar.make(
+ activity.getWindow().getDecorView(),
+ getString(R.string.picer_saved), Snackbar.LENGTH_SHORT)
+ .setAction(R.string.general_share, v -> {
+ Intent shareIntent = new Intent();
+ shareIntent.setAction(Intent.ACTION_SEND);
+ shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
+ shareIntent.setType("image/jpeg");
+ getActivity().startActivity(
+ Intent.createChooser(shareIntent,
+ v.getContext().getString(R.string.picer_share_title)));
+ });
+ snackbar.show();
+ dismiss();
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/PreviewGenerateThread.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/PreviewGenerateThread.java
new file mode 100644
index 00000000..825d0979
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/PreviewGenerateThread.java
@@ -0,0 +1,60 @@
+package com.mithrilmania.blocktopograph.map.picer;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.AsyncTask;
+import android.util.Pair;
+
+import java.lang.ref.WeakReference;
+
+public class PreviewGenerateThread extends AsyncTask , Void> {
+
+ private int MAX_DIM = 800;
+ private final WeakReference owner;
+
+ PreviewGenerateThread(PicerFragment owner) {
+ this.owner = new WeakReference<>(owner);
+ }
+
+ @Override
+ protected Void doInBackground(Area... areas) {
+ assert areas != null;
+ for (int i = 0; i < areas.length; i++) {
+ Bitmap bitmap = null;
+ flow:
+ {
+ Area area = areas[i];
+ int width = area.width();
+ int height = area.height();
+ // Wow man that's way too large! 'll be broken~
+ // ( What the hell are you thinking about )
+ if (width > MAX_DIM || height > MAX_DIM) break flow;
+ // Scale up unless reach limit.
+ int scale = MAX_DIM / Math.max(width, height);
+ bitmap = Bitmap.createBitmap(
+ width * scale, height * scale, Bitmap.Config.ALPHA_8);
+ Canvas canvas = new Canvas(bitmap);
+ Paint paint = new Paint();
+ paint.setAlpha(127);
+ for (Area.Member mem : area.getList()) {
+ int x = mem.x - area.mMinX;
+ int y = mem.z - area.mMinZ;
+ canvas.drawRect(new Rect(
+ x * scale, y * scale,
+ (x + 1) * scale, (y + 1) * scale), paint);
+ }
+ }
+ //noinspection unchecked
+ publishProgress(new Pair<>(i, bitmap));
+ }
+ return null;
+ }
+
+ @SafeVarargs
+ @Override
+ protected final void onProgressUpdate(Pair... values) {
+ //
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/SaveTask.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/SaveTask.java
new file mode 100644
index 00000000..ac1851d4
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/picer/SaveTask.java
@@ -0,0 +1,62 @@
+package com.mithrilmania.blocktopograph.map.picer;
+
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.os.AsyncTask;
+import android.os.Environment;
+
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.util.IoUtil;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+
+class SaveTask extends AsyncTask {
+
+ private final WeakReference owner;
+ private WeakReference dialog;
+ private final String worldName;
+
+ SaveTask(PicerFragment owner, String worldName) {
+ this.owner = new WeakReference<>(owner);
+ this.worldName = worldName;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ PicerFragment owner = this.owner.get();
+ if (owner == null) return;
+ Activity activity = owner.getActivity();
+ if (activity == null) return;
+ AlertDialog dia = new AlertDialog.Builder(activity)
+ .setView(R.layout.general_wait)
+ .setCancelable(false)
+ .create();
+ dia.setCanceledOnTouchOutside(false);
+ dia.show();
+ dialog = new WeakReference<>(dia);
+ }
+
+ @Override
+ protected File doInBackground(Bitmap... bitmaps) {
+ // assert bitmaps != null && bitmaps.length == 1;
+ Bitmap bmp = bitmaps[0];
+ assert bmp != null;
+ return IoUtil.saveBitmap(bmp, Bitmap.CompressFormat.PNG, 0,
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
+ worldName + "_map", true);
+ }
+
+ @Override
+ protected void onPostExecute(@Nullable File result) {
+ AlertDialog dia;
+ if (dialog != null && (dia = dialog.get()) != null) dia.dismiss();
+ PicerFragment owner = this.owner.get();
+ if (owner == null) return;
+ owner.onSavedBitmap(result);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/BiomeRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/BiomeRenderer.java
index 1c93d71e..9b6f4e0b 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/BiomeRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/BiomeRenderer.java
@@ -1,73 +1,37 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import com.mithrilmania.blocktopograph.WorldData;
import com.mithrilmania.blocktopograph.chunk.Chunk;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
import com.mithrilmania.blocktopograph.chunk.Version;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
import com.mithrilmania.blocktopograph.map.Biome;
import com.mithrilmania.blocktopograph.map.Dimension;
-
public class BiomeRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- Chunk chunk = cm.getChunk(chunkX, chunkZ);
- Version cVersion = chunk.getVersion();
-
- if(cVersion == Version.ERROR) return MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- if(cVersion == Version.NULL) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
- //the bottom sub-chunk is sufficient to get biome data.
- TerrainChunkData data = chunk.getTerrain((byte) 0);
- if(data == null || !data.load2DData()) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
int x, z, biomeID, color, i, j, tX, tY;
Biome biome;
- for (z = bZ, tY = pY ; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
-
+ for (z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (x = 0, tX = pX; x < 16; x++, tX += pW) {
- biomeID = data.getBiome(x, z) & 0xff;
+ biomeID = chunk.getBiome(x, z) & 0xff;
biome = Biome.getBiome(biomeID);
color = biome == null ? 0xff000000 : (biome.color.red << 16) | (biome.color.green << 8) | (biome.color.blue) | 0xff000000;
- for(i = 0; i < pL; i++){
- for(j = 0; j < pW; j++){
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
}
}
-
- return bm;
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/BlockLightRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/BlockLightRenderer.java
index bc12c772..bf9bc79b 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/BlockLightRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/BlockLightRenderer.java
@@ -1,86 +1,50 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import com.mithrilmania.blocktopograph.WorldData;
import com.mithrilmania.blocktopograph.chunk.Chunk;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
import com.mithrilmania.blocktopograph.chunk.Version;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
import com.mithrilmania.blocktopograph.map.Dimension;
-
public class BlockLightRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- Chunk chunk = cm.getChunk(chunkX, chunkZ);
- Version cVersion = chunk.getVersion();
-
- if(cVersion == Version.ERROR) return MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- if(cVersion == Version.NULL) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
-
- int x, y, z, subChunk, color, i, j, tX, tY;
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
+
+ int x, y, z, subChunk, color, yLim, tX, tY;
//render width in blocks
- int rW = eX - bX;
- int[] light = new int[rW * (eZ - bZ)];
-
- for(subChunk = 0; subChunk < cVersion.subChunks; subChunk++) {
- TerrainChunkData data = chunk.getTerrain((byte) subChunk);
- if (data == null || !data.loadTerrain()) break;
-
- for (z = bZ; z < eZ; z++) {
- for (x = bX; x < eX; x++) {
- for (y = 0; y < cVersion.subChunkHeight; y++) {
- light[((z - bZ) * rW) + (x - bX)] += data.getBlockLightValue(x, y, z) & 0xff;
- }
+ int rW = 16;
+ int[] light = new int[rW * 16];
+
+ yLim = chunk.getHeightLimit();
+
+ for (z = 0; z < 16; z++) {
+ for (x = 0; x < 16; x++) {
+ for (y = 0; y < yLim; y++) {
+ light[(z * rW) + x] += chunk.getBlockLightValue(x, y, z) & 0xff;
}
}
}
int l;
- for (z = bZ, tY = pY; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
+ for (z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (x = 0, tX = pX; x < 16; x++, tX += pW) {
- l = light[((z - bZ) * rW) + (x - bX)];
+ l = light[(z * rW) + x];
l = l < 0 ? 0 : ((l > 0xff) ? 0xff : l);
color = (l << 16) | (l << 8) | (l) | 0xff000000;
- for(i = 0; i < pL; i++){
- for(j = 0; j < pW; j++){
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
}
}
-
- if(subChunk == 0) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
- return bm;
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/CaveRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/CaveRenderer.java
index 7aa2beae..ffd7d1c1 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/CaveRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/CaveRenderer.java
@@ -1,70 +1,34 @@
package com.mithrilmania.blocktopograph.map.renderer;
-
-import android.graphics.Bitmap;
-
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.OldBlock;
import com.mithrilmania.blocktopograph.chunk.Chunk;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
import com.mithrilmania.blocktopograph.chunk.Version;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
-import com.mithrilmania.blocktopograph.map.Block;
import com.mithrilmania.blocktopograph.map.Dimension;
-
public class CaveRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- Chunk chunk = cm.getChunk(chunkX, chunkZ);
- Version cVersion = chunk.getVersion();
-
- if(cVersion == Version.ERROR) return MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- if(cVersion == Version.NULL) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
boolean solid, intoSurface;
- int id, meta, cavyness, layers, offset;
- Block block;
- int x, y, z, subChunk, color, i, j, tX, tY, r, g, b;
-
- //the bottom sub-chunk is sufficient to get heightmap data.
- TerrainChunkData floorData = chunk.getTerrain((byte) 0);
- if(floorData == null || !floorData.load2DData()) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
+ int cavyness, layers;
- TerrainChunkData data;
-
- for (z = bZ, tY = pY; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
+ for (int z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (int x = 0, tX = pX; x < 16; x++, tX += pW) {
solid = false;
intoSurface = false;
cavyness = 0;
layers = 0;
- y = floorData.getHeightMapValue(x, z);
- offset = y % cVersion.subChunkHeight;
- subChunk = y / cVersion.subChunkHeight;
-
/*
while (cavefloor > 0) {
caveceil = chunk.getCaveYUnderAt(x, z, cavefloor - 1);
@@ -78,104 +42,78 @@ public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, in
*/
- r = g = b = 0;
-
- subChunkLoop: for(; subChunk >= 0; subChunk--) {
-
- data = chunk.getTerrain((byte) subChunk);
- if (data == null || !data.loadTerrain()){
- //start at the top of the next chunk! (current offset might differ)
- offset = cVersion.subChunkHeight - 1;
- continue;
- }
-
-
- for (y = offset; y >= 0; y--) {
-
- id = data.getBlockTypeId(x, y, z) & 0xff;
-
- meta = data.getBlockData(x, y, z) & 0xff;
- block = Block.getBlock(id, meta);
-
- //try the default meta value: 0
- if (block == null) block = Block.getBlock(id, 0);
-
- switch (id) {
- case 0:
- //count the number of times it goes from solid to air
- if(solid) layers++;
-
- //count the air blocks underground,
- // but avoid trees by skipping the first layer
- if(intoSurface) cavyness++;
- break;
- case 66://rail
- if (b < 150) {
- b = 150;
- r = g = 50;
- }
- break;
- case 5://wooden plank
- if (b < 100) {
- b = 100;
- r = g = 100;
- }
- break;
- case 52://monster spawner
- r = g = b = 255;
- break subChunkLoop;
- case 54://chest
- if (b < 170) {
- b = 170;
- r = 240;
- g = 40;
- }
- break;
- case 98://stone bricks
- if (b < 145) {
- b = 145;
- r = g = 120;
- }
- break;
- case 48://moss cobblestone
- case 4://cobblestone
- if (b < 140) {
- b = 140;
- r = g = 100;
- }
- break;
+ int r = 0, g = 0, b = 0;
+
+ for (int y = chunk.getHeightMapValue(x, z); y >= 0; y--) {
+
+ var blockTemplate = chunk.getBlockTemplate(x, y, z, 0);
+
+ //wooden plank
+ //stone bricks
+ //moss cobblestone
+ if (BlockTemplates.getAirTemplate().equals(blockTemplate)) {
+ //count the number of times it goes from solid to air
+ if (solid) layers++;
+ //count the air blocks underground,
+ // but avoid trees by skipping the first layer
+ if (intoSurface) cavyness++;
+ } else {
+ var blockName = blockTemplate.getBlock().getName();
+ if ("minecraft:rail".equals(blockName)) {//rail
+ if (b < 150) {
+ b = 150;
+ r = g = 50;
+ }
+ } else if ("minecraft:planks".equals(blockName)) {
+ if (b < 100) {
+ b = 100;
+ r = g = 100;
+ }
+ } else if ("minecraft:mob_spawner".equals(blockName)) {//monster spawner
+ r = g = b = 255;
+ break;
+ } else if ("minecraft:chest".equals(blockName)) {//chest
+ if (b < 170) {
+ b = 170;
+ r = 240;
+ g = 40;
+ }
+ } else if ("minecraft:stonebrick".equals(blockName)) {
+ if (b < 145) {
+ b = 145;
+ r = g = 120;
+ }
+ } else if ("minecraft:mossy_cobblestone".equals(blockName) || "minecraft:cobblestone".equals(blockName)) {//cobblestone
+ if (b < 140) {
+ b = 140;
+ r = g = 100;
+ }
}
- r += data.getBlockLightValue(x, y, z);
- solid = block != null && block.color.alpha == 0xff;
- intoSurface |= solid && (y < 60 || layers > 0);
}
+ r += chunk.getBlockLightValue(x, y, z);
+ solid = Color.alpha(blockTemplate.getColor()) == 0xff;
+ intoSurface |= solid && (y < 60 || layers > 0);
}
- if (g == 0 && layers > 0){
+ if (g == 0 && layers > 0) {
g = (r + 2) * cavyness;
r *= 32 * layers;
b = 16 * cavyness * (layers - 1);
} else r *= r;
- r = r < 0 ? 0 : r > 255 ? 255 : r;
- g = g < 0 ? 0 : g > 255 ? 255 : g;
+ r = r < 0 ? 0 : Math.min(r, 255);
+ g = g < 0 ? 0 : Math.min(g, 255);
//b = b < 0 ? 0 : b > 255 ? 255 : b;
- color = (r << 16) | (g << 8) | b | 0xff000000;
+ int color = (r << 16) | (g << 8) | b | 0xff000000;
-
- for (i = 0; i < pL; i++) {
- for (j = 0; j < pW; j++) {
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
}
}
-
- return bm;
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/ChessPatternRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/ChessPatternRenderer.java
index c840cd5d..8f627bfb 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/ChessPatternRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/ChessPatternRenderer.java
@@ -1,58 +1,37 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
import com.mithrilmania.blocktopograph.chunk.Version;
import com.mithrilmania.blocktopograph.map.Dimension;
-
public class ChessPatternRenderer implements MapRenderer {
public final int darkShade, lightShade;// int DARK_SHADE = 0xFF2B2B2B, LIGHT_SHADE = 0xFF585858;
- ChessPatternRenderer(int darkShade, int lightShade){
+ ChessPatternRenderer(int darkShade, int lightShade) {
this.darkShade = darkShade;
this.lightShade = lightShade;
}
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- int x, z, i, j, tX, tY;
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
+
+ int x, z, tX, tY;
int color;
- for (z = bZ, tY = pY ; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
+ for (z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (x = 0, tX = pX; x < 16; x++, tX += pW) {
color = ((x + z) & 1) == 1 ? darkShade : lightShade;
- for (i = 0; i < pL; i++) {
- for (j = 0; j < pW; j++) {
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
+ //This would get hardware acceleration.
}
}
-
-
- return bm;
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/DebugRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/DebugRenderer.java
index 7c505051..dcf538c9 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/DebugRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/DebugRenderer.java
@@ -1,53 +1,33 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
import com.mithrilmania.blocktopograph.chunk.Version;
import com.mithrilmania.blocktopograph.map.Dimension;
-
public class DebugRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
int x, z, i, j, tX, tY;
int offsetX = chunkX * dimension.chunkW;
int offsetZ = chunkZ * dimension.chunkL;
- for (z = bZ, tY = pY ; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
- for(i = 0; i < pL; i++){
- for(j = 0; j < pW; j++){
- bm.setPixel(tX + j, tY + i, 0xff000000 | ((offsetX + x) ^ (offsetZ + z)));
+ for (z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (x = 0, tX = pX; x < 16; x++, tX += pW) {
+ for (i = 0; i < pL; i++) {
+ for (j = 0; j < pW; j++) {
+ paint.setColor(0xff000000 | ((offsetX + x) ^ (offsetZ + z)));
+ canvas.drawPoint(tX + j, tY + i, paint);
}
}
}
}
-
-
- return bm;
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/GrassRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/GrassRenderer.java
index a908e567..a4c74063 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/GrassRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/GrassRenderer.java
@@ -1,66 +1,32 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import com.mithrilmania.blocktopograph.WorldData;
import com.mithrilmania.blocktopograph.chunk.Chunk;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
import com.mithrilmania.blocktopograph.chunk.Version;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
import com.mithrilmania.blocktopograph.map.Dimension;
public class GrassRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
- Chunk chunk = cm.getChunk(chunkX, chunkZ);
- Version cVersion = chunk.getVersion();
+ int x, z, color, tX, tY;
- if(cVersion == Version.ERROR) return MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- if(cVersion == Version.NULL) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
+ for (z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (x = 0, tX = pX; x < 16; x++, tX += pW) {
- //the bottom sub-chunk is sufficient to get grass data.
- TerrainChunkData data = chunk.getTerrain((byte) 0);
- if(data == null || !data.load2DData()) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
+ color = chunk.getGrassColor(x, z);
-
- int x, z, color, i, j, tX, tY;
-
- for (z = bZ, tY = pY; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
-
- color = ((data.getGrassR(x, z) & 0xff) << 16) | ((data.getGrassG(x, z) & 0xff) << 8) | (data.getGrassB(x, z) & 0xff) | 0xff000000;
-
- for (i = 0; i < pL; i++) {
- for (j = 0; j < pW; j++) {
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
}
}
-
- return bm;
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/HeightmapRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/HeightmapRenderer.java
index 5c91b532..77458380 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/HeightmapRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/HeightmapRenderer.java
@@ -1,82 +1,55 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import com.mithrilmania.blocktopograph.WorldData;
import com.mithrilmania.blocktopograph.chunk.Chunk;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
import com.mithrilmania.blocktopograph.chunk.Version;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
import com.mithrilmania.blocktopograph.map.Dimension;
public class HeightmapRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- Chunk chunk = cm.getChunk(chunkX, chunkZ);
- Version cVersion = chunk.getVersion();
-
- if(cVersion == Version.ERROR) return MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- if(cVersion == Version.NULL) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
- //the bottom sub-chunk is sufficient to get heightmap data.
- TerrainChunkData data = chunk.getTerrain((byte) 0);
- if(data == null || !data.load2DData()) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
-
- TerrainChunkData dataW = cm.getChunk(chunkX - 1, chunkZ).getTerrain((byte) 0);
- TerrainChunkData dataN = cm.getChunk(chunkX, chunkZ-1).getTerrain((byte) 0);
-
- boolean west = dataW != null && dataW.load2DData(),
- north = dataN != null && dataN.load2DData();
-
- int x, y, z, color, i, j, tX, tY;
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
+
+ Chunk dataW = worldData.getChunk(chunkX - 1, chunkZ, dimension);
+ Chunk dataN = worldData.getChunk(chunkX, chunkZ - 1, dimension);
+
+ boolean west = dataW != null && !dataW.isVoid(),
+ north = dataN != null && !dataN.isVoid();
+
+ int x, y, z, color, tX, tY;
int yW, yN;
int r, g, b;
float yNorm, yNorm2, heightShading;
- for (z = bZ, tY = pY ; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
+ for (z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (x = 0, tX = pX; x < 16; x++, tX += pW) {
//smooth step function: 6x^5 - 15x^4 + 10x^3
- y = data.getHeightMapValue(x, z);
+ y = chunk.getHeightMapValue(x, z);
+
+ if (y < 0) continue;
yNorm = (float) y / (float) dimension.chunkH;
- yNorm2 = yNorm*yNorm;
- yNorm = ((6f*yNorm2) - (15f*yNorm) + 10f)*yNorm2*yNorm;
+ yNorm2 = yNorm * yNorm;
+ yNorm = ((6f * yNorm2) - (15f * yNorm) + 10f) * yNorm2 * yNorm;
yW = (x == 0) ? (west ? dataW.getHeightMapValue(dimension.chunkW - 1, z) : y)//chunk edge
- : data.getHeightMapValue(x - 1, z);//within chunk
+ : chunk.getHeightMapValue(x - 1, z);//within chunk
yN = (z == 0) ? (north ? dataN.getHeightMapValue(x, dimension.chunkL - 1) : y)//chunk edge
- : data.getHeightMapValue(x, z - 1);//within chunk
+ : chunk.getHeightMapValue(x, z - 1);//within chunk
heightShading = SatelliteRenderer.getHeightShading(y, yW, yN);
- r = (int) (yNorm*heightShading*256f);
- g = (int) (70f*heightShading);
- b = (int) (256f*(1f-yNorm)/(yNorm + 1f));
-
+ r = (int) (yNorm * heightShading * 256f);
+ g = (int) (70f * heightShading);
+ b = (int) (256f * (1f - yNorm) / (yNorm + 1f));
+
r = r < 0 ? 0 : r > 255 ? 255 : r;
g = g < 0 ? 0 : g > 255 ? 255 : g;
b = b < 0 ? 0 : b > 255 ? 255 : b;
@@ -84,17 +57,12 @@ public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, in
color = (r << 16) | (g << 8) | b | 0xff000000;
- for(i = 0; i < pL; i++){
- for(j = 0; j < pW; j++){
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
}
}
-
- return bm;
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/MapRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/MapRenderer.java
index d567e222..558108f4 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/MapRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/MapRenderer.java
@@ -1,9 +1,10 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
-import com.mithrilmania.blocktopograph.chunk.ChunkData;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
import com.mithrilmania.blocktopograph.chunk.Version;
import com.mithrilmania.blocktopograph.map.Dimension;
@@ -16,27 +17,28 @@ will just make things worse on some (most?) phones.
So I guess we have to do some weird patterns to make this efficient...
Currently trying to keep tile sizes constant, for bitmap recycling.
Makes zooming look sharp too.
+
+ The cat solved this :)
*/
+
/**
* Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
*
- * @throws Version.VersionException when the version of the chunk is unsupported.
+ * @param chunk The chunk.
+ * @param canvas Canvas for the corresponding bitmap to render to, hw acceleration on
+ * @param dimension Mapped dimension
+ * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
+ * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
+ * @param pX texture X pixel coord to start rendering to
+ * @param pY texture Y pixel coord to start rendering to
+ * @param pW width (X) of one block in pixels
+ * @param pL length (Z) of one block in pixels
+ * @param paint Paint instance used to draw on canvas
+ * @param worldData ChunkManager, some renderer needs info about its neighbor
+ * @throws RuntimeException when the version of the chunk is unsupported.
+ * TODO: reduce complicity, e.g. remove chunkManager from parameters.
*/
- Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException;
+ void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException;
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/MapType.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/MapType.java
index 0524862b..a2037594 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/MapType.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/MapType.java
@@ -42,6 +42,9 @@ public enum MapType implements DetailLevelManager.LevelType {
NETHER_XRAY(new XRayRenderer()),
NETHER_BLOCK_LIGHT(new BlockLightRenderer()),
+
+ //add in 1.16.0
+ NETHER_BIOME(new BiomeRenderer()),
END_SATELLITE(new SatelliteRenderer()),
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/NetherRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/NetherRenderer.java
index 9d0dd824..599345eb 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/NetherRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/NetherRenderer.java
@@ -1,82 +1,47 @@
package com.mithrilmania.blocktopograph.map.renderer;
-
-import android.graphics.Bitmap;
-import com.mithrilmania.blocktopograph.Log;
-
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
import com.mithrilmania.blocktopograph.chunk.Chunk;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
import com.mithrilmania.blocktopograph.chunk.Version;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
-import com.mithrilmania.blocktopograph.map.Block;
import com.mithrilmania.blocktopograph.map.Dimension;
public class NetherRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- Chunk chunk = cm.getChunk(chunkX, chunkZ);
- Version cVersion = chunk.getVersion();
-
- if(cVersion == Version.ERROR) return MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- if(cVersion == Version.NULL) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
- //bottom chunk must be present
- TerrainChunkData floorData = chunk.getTerrain((byte) 0);
- if(floorData == null || !floorData.load2DData()) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
-
- Chunk chunkW = cm.getChunk(chunkX - 1, chunkZ);
- Chunk chunkN = cm.getChunk(chunkX, chunkZ-1);
-
- TerrainChunkData data;
-
- float shading, shadingSum, rf, gf, bf, af, a, blendR, blendG, blendB, sumRf, sumGf, sumBf;
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
+
+ Chunk chunkW = worldData.getChunk(chunkX - 1, chunkZ, dimension);
+ Chunk chunkN = worldData.getChunk(chunkX, chunkZ - 1, dimension);
+
+ //Do you have to list all variables here in a 80s manner
+ // regardless of many are only used within nested loop...
+
+ float shading, shadingSum, a, blendR, blendG, blendB, sumRf, sumGf, sumBf;
int layers;
int caveceil, cavefloor, cavefloorW, cavefloorN;
- int x, y, z, color, i, j, tX, tY, r, g, b;
- Block block;
- int id, meta;
int worth;
- int lightValue;
+ int y;
float heightShading, lightShading, sliceShading, avgShading;
- int offset;
- int stop;
- int subChunk;
- int stopSubChunk;
-
- for (z = bZ, tY = pY ; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
+ for (int z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (int x = 0, tX = pX; x < 16; x++, tX += pW) {
worth = 0;
shadingSum = 0;
sumRf = sumGf = sumBf = 0;
layers = 1;
- cavefloor = floorData.getHeightMapValue(x, z);//TODO test this
+ cavefloor = chunk.getHeightMapValue(x, z);//TODO test this
- //See-through-multi-level-height-light-shading is the new black -- @mithrilmania
while (cavefloor > 0) {
caveceil = chunk.getCaveYUnderAt(x, z, cavefloor - 1);
@@ -91,16 +56,10 @@ public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, in
heightShading = SatelliteRenderer.getHeightShading(cavefloor, cavefloorW, cavefloorN);
y = cavefloor + 1;
- data = chunk.getTerrain((byte) (y / cVersion.subChunkHeight));
-
- //light sources
- lightValue = (data != null && data.loadTerrain())
- ? data.getBlockLightValue(x, y % cVersion.subChunkHeight, z)
- : 0;
//check if it is supported, default to full brightness to not lose details.
- if(data.supportsBlockLightValues()) {
- lightShading = (float) lightValue / 15f + 1;
+ if (chunk.supportsBlockLightValues()) {
+ lightShading = (float) chunk.getBlockLightValue(x, y, z) / 15f + 1;
} else {
lightShading = 2f;
}
@@ -115,69 +74,44 @@ public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, in
shadingSum += shading;
-
-
a = 1f;
- offset = caveceil % cVersion.subChunkHeight;
- stop = 0;
- subChunk = caveceil / cVersion.subChunkHeight;
- stopSubChunk = caveceil / cVersion.subChunkHeight;
-
-
- subChunkLoop: for(; subChunk >= stopSubChunk; subChunk--) {
- if (subChunk == stopSubChunk) stop = cavefloor % cVersion.subChunkHeight;
-
- data = chunk.getTerrain((byte) subChunk);
- if (data == null || !data.loadTerrain()) {
- //start at the top of the next chunk! (current offset might differ)
- offset = cVersion.subChunkHeight - 1;
- continue;
- }
-
- for (y = offset; y >= stop; y--) {
-
- id = data.getBlockTypeId(x, y, z) & 0xff;
+ for (y = caveceil; y >= cavefloor; y--) {
- if (id == 0) continue;//skip air blocks
+ var blockTemplate = chunk.getBlockTemplate(x, y, z, 0);
- meta = data.getBlockData(x, y, z) & 0xff;
- block = Block.getBlock(id, meta);
+ if (BlockTemplates.getAirTemplate().equals(blockTemplate))
+ continue;//skip air blocks
- //try the default meta value: 0
- if (block == null) block = Block.getBlock(id, 0);
+ //try the default meta value: 0
+ //if (oldBlock == null) oldBlock = KnownBlockRepr.getBlock(id, 0);
- if (block == null) {
- Log.w("UNKNOWN block: id: " + id + " meta: " + meta);
- continue;
- }
+ int color = blockTemplate.getColor();
+ // no need to process oldBlock if it is fully transparent
+ if (Color.alpha(color) == 0) continue;
- // no need to process block if it is fully transparent
- if (block.color.alpha == 0) continue;
+ float rf = Color.red(color) / 255f;
+ float gf = Color.green(color) / 255f;
+ float bf = Color.blue(color) / 255f;
+ float af = Color.alpha(color) / 255f;
- rf = block.color.red / 255f;
- gf = block.color.green / 255f;
- bf = block.color.blue / 255f;
- af = block.color.alpha / 255f;
+ // alpha blend and multiply
+ blendR = a * af * rf * shading;
+ blendG = a * af * gf * shading;
+ blendB = a * af * bf * shading;
- // alpha blend and multiply
- blendR = a * af * rf * shading;
- blendG = a * af * gf * shading;
- blendB = a * af * bf * shading;
-
- sumRf += blendR;
- sumGf += blendG;
- sumBf += blendB;
- a *= 1f - af;
-
- // break when an opaque block is encountered
- if (block.color.alpha == 0xff) break subChunkLoop;
- }
+ sumRf += blendR;
+ sumGf += blendG;
+ sumBf += blendB;
+ a *= 1f - af;
- //start at the top of the next chunk! (current offset might differ)
- offset = cVersion.subChunkHeight - 1;
+ // break when an opaque oldBlock is encountered
+ if (Color.alpha(color) == 0xff) break;
}
+ //start at the top of the next chunk! (current offset might differ)
+ //offset = 15;//cVersion.subChunkHeight - 1;
+ //}
layers++;
@@ -186,65 +120,49 @@ public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, in
avgShading = shadingSum / layers;
// apply the shading
- r = (int) (avgShading * sumRf / layers * 255f);
- g = (int) (avgShading * sumGf / layers * 255f);
- b = (int) (avgShading * sumBf / layers * 255f);
-
-
- r = r < 0 ? 0 : r > 255 ? 255 : r;
- g = g < 0 ? 0 : g > 255 ? 255 : g;
- b = b < 0 ? 0 : b > 255 ? 255 : b;
-
-
- subChunkLoop: for(subChunk = 0; subChunk < cVersion.subChunks; subChunk++) {
- data = chunk.getTerrain((byte) subChunk);
- if (data == null || data.loadTerrain()) break;
-
- for (y = 0; y < cVersion.subChunkHeight; y++) {
-
- //some x-ray for important stuff like portals
- switch (data.getBlockTypeId(x, y, z)) {
- case 52://monster spawner
- r = g = b = 255;
- break subChunkLoop;//max already? just stop
- case 54://chest
- if (worth < 90) {
- worth = 90;
- b = 170;
- r = 240;
- g = 40;
- }
- break;
- case 115://nether wart
- if (worth < 80) {
- worth = 80;
- r = b = 120;
- g = 170;
- }
- break;
- case 90://nether portal
- if (worth < 95) {
- worth = 95;
- r = 60;
- g = 0;
- b = 170;
- }
- break;
+ int r = (int) (avgShading * sumRf / layers * 255f);
+ int g = (int) (avgShading * sumGf / layers * 255f);
+ int b = (int) (avgShading * sumBf / layers * 255f);
+
+
+ r = r < 0 ? 0 : Math.min(r, 255);
+ g = g < 0 ? 0 : Math.min(g, 255);
+ b = b < 0 ? 0 : Math.min(b, 255);
+
+ for (y = 0; y < chunk.getHeightLimit(); y++) {
+
+ //some x-ray for important stuff like portals
+ BlockTemplate blockTemplate = chunk.getBlockTemplate(x, y, z, 0);
+ var blockName = blockTemplate.getBlock().getName();
+ if ("minecraft:mob_spawner".equals(blockName)) {//monster spawner
+ r = g = b = 255;
+ } else if ("minecraft:chest".equals(blockName)) {//chest
+ if (worth < 90) {
+ worth = 90;
+ b = 170;
+ r = 240;
+ g = 40;
+ }
+ } else if ("minecraft:nether_wart".equals(blockName)) {//nether wart
+ if (worth < 80) {
+ worth = 80;
+ r = b = 120;
+ g = 170;
+ }
+ } else if ("minecraft:portal".equals(blockName)) {//nether portal
+ if (worth < 95) {
+ worth = 95;
+ r = 60;
+ g = 0;
+ b = 170;
}
}
}
- color = (r << 16) | (g << 8) | b | 0xff000000;
-
- for(i = 0; i < pL; i++){
- for(j = 0; j < pW; j++){
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor((r << 16) | (g << 8) | b | 0xff000000);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
}
}
-
- return bm;
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/SatelliteRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/SatelliteRenderer.java
index c63e2ab6..ef4cc528 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/SatelliteRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/SatelliteRenderer.java
@@ -1,186 +1,75 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
-import com.mithrilmania.blocktopograph.Log;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import androidx.annotation.NonNull;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
import com.mithrilmania.blocktopograph.chunk.Chunk;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
import com.mithrilmania.blocktopograph.chunk.Version;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
-import com.mithrilmania.blocktopograph.map.Block;
import com.mithrilmania.blocktopograph.map.Dimension;
public class SatelliteRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- Chunk chunk = cm.getChunk(chunkX, chunkZ);
- Version cVersion = chunk.getVersion();
-
- if(cVersion == Version.ERROR) return MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- if(cVersion == Version.NULL) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
- //the bottom sub-chunk is sufficient to get heightmap data.
- TerrainChunkData data = chunk.getTerrain((byte) 0);
- if(data == null || !data.load2DData()) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
-
- TerrainChunkData dataW = cm.getChunk(chunkX - 1, chunkZ).getTerrain((byte) 0);
- TerrainChunkData dataN = cm.getChunk(chunkX, chunkZ-1).getTerrain((byte) 0);
-
- boolean west = dataW != null && dataW.load2DData(),
- north = dataN != null && dataN.load2DData();
-
- int x, y, z, color, i, j, tX, tY;
- for (z = bZ, tY = pY ; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
-
- y = data.getHeightMapValue(x, z);
-
- color = getColumnColour(chunk, data, x, y, z,
- (x == 0) ? (west ? dataW.getHeightMapValue(dimension.chunkW - 1, z) : y)//chunk edge
- : data.getHeightMapValue(x - 1, z),//within chunk
- (z == 0) ? (north ? dataN.getHeightMapValue(x, dimension.chunkL - 1) : y)//chunk edge
- : data.getHeightMapValue(x, z - 1)//within chunk
- );
-
- for(i = 0; i < pL; i++){
- for(j = 0; j < pW; j++){
- bm.setPixel(tX + j, tY + i, color);
- }
- }
-
-
- }
- }
-
- return bm;
- }
-
//calculate color of one column
- private static int getColumnColour(Chunk chunk, TerrainChunkData floorData, int x, int y, int z, int heightW, int heightN) throws Version.VersionException {
- float a = 1f;
- float r = 0f;
- float g = 0f;
- float b = 0f;
+ static int getColumnColour(@NonNull Chunk chunk, int x, int y, int z, int heightW, int heightN) throws Version.VersionException {
+ float alphaRemain = 1f;
+ float finalR = 0f;
+ float finalG = 0f;
+ float finalB = 0f;
// extract colour components as normalized doubles, from ARGB format
- float biomeR = (float) (floorData.getGrassR(x, z) & 0xff) / 255f;
- float biomeG = (float) (floorData.getGrassG(x, z) & 0xff) / 255f;
- float biomeB = (float) (floorData.getGrassB(x, z) & 0xff) / 255f;
+ int grassColor = chunk.getGrassColor(x, z);
+ float biomeR = (float) Color.red(grassColor) / 255f;
+ float biomeG = (float) Color.green(grassColor) / 255f;
+ float biomeB = (float) Color.blue(grassColor) / 255f;
- float blendR, blendG, blendB;
+ y--;
+ for (; y >= 0 && alphaRemain >= .1f; y--) {
- float blockA, blockR, blockG, blockB;
+ var blockTemplate = chunk.getBlockTemplate(x, y, z, 0);
+ if (BlockTemplates.getAirTemplate().equals(blockTemplate)) continue;//skip air blocks
- Block block;
- int id, meta;
+ int color = blockTemplate.getColor();
- Version cVersion = chunk.getVersion();
- int realY = y;
- int offset = y % cVersion.subChunkHeight;
- int subChunk = y / cVersion.subChunkHeight;
+ // no need to process block if it is fully transparent
+ if (Color.alpha(color) == 0) continue;
- TerrainChunkData data;
+ float blendA = Color.alpha(color) / 255f;
- subChunkLoop: for(; subChunk >= 0; subChunk--) {
+ // alpha blend and multiply
+ float blendR = alphaRemain * blendA * (Color.red(color) / 255f);
+ float blendG = alphaRemain * blendA * (Color.green(color) / 255f);
+ float blendB = alphaRemain * blendA * (Color.blue(color) / 255f);
- data = chunk.getTerrain((byte) subChunk);
- if (data == null || !data.loadTerrain()){
- //start at the top of the next chunk! (current offset might differ)
- offset = cVersion.subChunkHeight - 1;
- continue;
+ //blend biome-colored blocks
+ if (blockTemplate.isHasBiomeShading()) {
+ blendR *= biomeR;
+ blendG *= biomeG;
+ blendB *= biomeB;
}
- for (y = offset; y >= 0; y--) {
-
- id = data.getBlockTypeId(x, y, z) & 0xff;
-
- if (id == 0) continue;//skip air blocks
-
- meta = data.getBlockData(x, y, z) & 0xff;
- block = Block.getBlock(id, meta);
-
- //try the default meta value: 0
- if (block == null) block = Block.getBlock(id, 0);
-
-
- //TODO log null blocks to debug missing blocks
- if (block == null) {
- Log.w("UNKNOWN block: id: " + id + " meta: " + meta);
- continue;
- }
-
- // no need to process block if it is fully transparent
- if (block.color == null || block.color.alpha == 0) continue;
-
- blockR = block.color.red / 255f;
- blockG = block.color.green / 255f;
- blockB = block.color.blue / 255f;
- blockA = block.color.alpha / 255f;
-
- // alpha blend and multiply
- blendR = a * blockA * blockR;
- blendG = a * blockA * blockG;
- blendB = a * blockA * blockB;
-
- //blend biome-colored blocks
- if (block.hasBiomeShading) {
- blendR *= biomeR;
- blendG *= biomeG;
- blendB *= biomeB;
- }
-
- r += blendR;
- g += blendG;
- b += blendB;
- a *= 1f - blockA;
-
- // break when an opaque block is encountered
- if (block.color.alpha == 0xff){
- break subChunkLoop;
- }
- }
-
- //start at the top of the next chunk! (current offset might differ)
- offset = cVersion.subChunkHeight - 1;
+ finalR += blendR;
+ finalG += blendG;
+ finalB += blendB;
+ alphaRemain *= 1f - blendA;
}
- //set y to the "real" y; consider all sub-chunks as a stack of chunks.
- y = realY;
-
//height shading (based on slopes in terrain; height diff)
float heightShading = getHeightShading(y, heightW, heightN);
//go back to "surface"
y++;
-
- TerrainChunkData surfaceChunk = chunk.getTerrain((byte) (y / cVersion.subChunkHeight));
//light sources
- int lightValue = (surfaceChunk != null && surfaceChunk.loadTerrain())
- ? (surfaceChunk.getBlockLightValue(x, y % cVersion.subChunkHeight, z) & 0xff)
- : 0;
+ int lightValue = chunk.getBlockLightValue(x, y, z) & 0xff;
float lightShading = (float) lightValue / 15f + 1;
//mix shading
@@ -190,16 +79,45 @@ private static int getColumnColour(Chunk chunk, TerrainChunkData floorData, int
//shading *= Math.max(Math.min(y / 40f, 1f), 0.2f);//shade ravines & caves, minimum *0.2 to keep some color
// apply the shading
- r = Math.min(Math.max(0f, r * shading), 1f);
- g = Math.min(Math.max(0f, g * shading), 1f);
- b = Math.min(Math.max(0f, b * shading), 1f);
+ finalR = Math.min(Math.max(0f, finalR * shading), 1f);
+ finalG = Math.min(Math.max(0f, finalG * shading), 1f);
+ finalB = Math.min(Math.max(0f, finalB * shading), 1f);
// now we have our final RGB values as floats, convert to a packed ARGB pixel.
return 0xff000000 |
- ((((int) (r * 255f)) & 0xff) << 16) |
- ((((int) (g * 255f)) & 0xff) << 8) |
- (((int) (b * 255f)) & 0xff);
+ ((((int) (finalR * 255f)) & 0xff) << 16) |
+ ((((int) (finalG * 255f)) & 0xff) << 8) |
+ (((int) (finalB * 255f)) & 0xff);
+ }
+
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
+
+ Chunk dataW = worldData.getChunk(chunkX - 1, chunkZ, dimension);
+ Chunk dataN = worldData.getChunk(chunkX, chunkZ - 1, dimension);
+
+ boolean west = dataW != null && !dataW.isVoid(),
+ north = dataN != null && !dataN.isVoid();
+
+ for (int z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (int x = 0, tX = pX; x < 16; x++, tX += pW) {
+
+ int y = chunk.getHeightMapValue(x, z);
+ if (y == 0) continue;
+
+ int color = getColumnColour(chunk, x, y, z,
+ (x == 0) ? (west ? dataW.getHeightMapValue(dimension.chunkW - 1, z) : y)//chunk edge
+ : chunk.getHeightMapValue(x - 1, z),//within chunk
+ (z == 0) ? (north ? dataN.getHeightMapValue(x, dimension.chunkL - 1) : y)//chunk edge
+ : chunk.getHeightMapValue(x, z - 1)//within chunk
+ );
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
+
+
+ }
+ }
+
}
// shading Amp, possible range: [0, 2] (or use negative for reverse shading)
@@ -225,4 +143,4 @@ public static float getHeightShading(int height, int heightW, int heightN) {
return ((float) (Math.atan(heightDiff) / Math.PI) * shadingAmp) + 1f;
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/SlimeChunkRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/SlimeChunkRenderer.java
index 53c98511..d1c4cd75 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/SlimeChunkRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/SlimeChunkRenderer.java
@@ -1,53 +1,50 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
import com.mithrilmania.blocktopograph.chunk.Version;
import com.mithrilmania.blocktopograph.map.Dimension;
import com.mithrilmania.blocktopograph.util.MTwister;
-
public class SlimeChunkRenderer implements MapRenderer {
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- int x, z, i, j, tX, tY;
-
- MapType.OVERWORLD_SATELLITE.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
+
+ int x, z, tX, tY;
+
+ Chunk dataW = worldData.getChunk(chunkX - 1, chunkZ, dimension);
+ Chunk dataN = worldData.getChunk(chunkX, chunkZ - 1, dimension);
+
+ boolean west = dataW != null && !dataW.isVoid(),
+ north = dataN != null && !dataN.isVoid();
+
+ //MapType.OVERWORLD_SATELLITE.renderer.renderToBitmap(chunk, canvas, dimension, chunkX, chunkZ, pX, pY, pW, pL, paint, version, chunkManager);
boolean isSlimeChunk = isSlimeChunk(chunkX, chunkZ);
int color, r, g, b, avg;
//make slimeChunks much more green
- for (z = bZ, tY = pY ; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
- color = bm.getPixel(tX, tY);
+ for (z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (x = 0, tX = pX; x < 16; x++, tX += pW) {
+
+ int y = chunk.getHeightMapValue(x, z);
+
+ color = SatelliteRenderer.getColumnColour(chunk, x, y, z,
+ (x == 0) ? (west ? dataW.getHeightMapValue(dimension.chunkW - 1, z) : y)//chunk edge
+ : chunk.getHeightMapValue(x - 1, z),//within chunk
+ (z == 0) ? (north ? dataN.getHeightMapValue(x, dimension.chunkL - 1) : y)//chunk edge
+ : chunk.getHeightMapValue(x, z - 1)//within chunk
+ );
r = (color >> 16) & 0xff;
g = (color >> 8) & 0xff;
b = color & 0xff;
avg = (r + g + b) / 3;
- if(isSlimeChunk){
+ if (isSlimeChunk) {
r = b = avg;
g = (g + 0xff) >> 1;
} else {
@@ -55,25 +52,21 @@ public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, in
}
color = (color & 0xFF000000) | (r << 16) | (g << 8) | b;
- for(i = 0; i < pL; i++){
- for(j = 0; j < pW; j++){
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
}
}
- return bm;
}
// See: https://gist.github.com/mithrilmania/00b85bf34a75fd8176342b1ad28bfccc
- public static boolean isSlimeChunk(int cX, int cZ){
+ private static boolean isSlimeChunk(int cX, int cZ) {
//
// MCPE slime-chunk checker
// From Minecraft: Pocket Edition 0.15.0 (0.15.0.50_V870150050)
- // Reverse engineered by @mithrilmania and @jocopa3
+ // Reverse engineered by @protolambda and @jocopa3
//
// NOTE:
// - The world-seed doesn't seem to be incorporated into the randomness, which is very odd.
@@ -82,7 +75,7 @@ public static boolean isSlimeChunk(int cX, int cZ){
// - Reverse engineering this code cost a lot of time,
// please add CREDITS when you are copying this.
// Copy the following into your program source:
- // MCPE slime-chunk checker; reverse engineered by @mithrilmania and @jocopa3
+ // MCPE slime-chunk checker; reverse engineered by @protolambda and @jocopa3
//
// chunkX/Z are the chunk-coordinates, used in the DB keys etc.
@@ -119,7 +112,7 @@ public static boolean isSlimeChunk(int cX, int cZ){
// Multiply with 10 (3 bits)
// ---> effect: the 3 bit randomness decrease expresses a 1 in a 10 chance.
- long res = (((hi_shift3 + (hi_shift3 * 0x4)) & 0xffffffffL) * 0x2) & 0xffffffffL;
+ long res = (((hi_shift3 + (hi_shift3 * 0x4)) & 0xffffffffL) * 0x2) & 0xffffffffL;
// Final check: is the input equal to 10 times less random, but comparable, output.
// Every chunk has a 1 in 10 chance to be a slime-chunk.
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/XRayRenderer.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/XRayRenderer.java
index d241f8e3..b5d13fc9 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/XRayRenderer.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/renderer/XRayRenderer.java
@@ -1,12 +1,16 @@
package com.mithrilmania.blocktopograph.map.renderer;
-import android.graphics.Bitmap;
-
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.BlockTemplates;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
import com.mithrilmania.blocktopograph.chunk.Chunk;
-import com.mithrilmania.blocktopograph.chunk.ChunkManager;
import com.mithrilmania.blocktopograph.chunk.Version;
-import com.mithrilmania.blocktopograph.chunk.terrain.TerrainChunkData;
-import com.mithrilmania.blocktopograph.map.Block;
import com.mithrilmania.blocktopograph.map.Dimension;
@@ -16,100 +20,68 @@ public class XRayRenderer implements MapRenderer {
TODO make the X-ray viewable blocks configurable, without affecting performance too much...
*/
- /**
- * Render a single chunk to provided bitmap (bm)
- * @param cm ChunkManager, provides chunks, which provide chunk-data
- * @param bm Bitmap to render to
- * @param dimension Mapped dimension
- * @param chunkX X chunk coordinate (x-block coord / Chunk.WIDTH)
- * @param chunkZ Z chunk coordinate (z-block coord / Chunk.LENGTH)
- * @param bX begin block X coordinate, relative to chunk edge
- * @param bZ begin block Z coordinate, relative to chunk edge
- * @param eX end block X coordinate, relative to chunk edge
- * @param eZ end block Z coordinate, relative to chunk edge
- * @param pX texture X pixel coord to start rendering to
- * @param pY texture Y pixel coord to start rendering to
- * @param pW width (X) of one block in pixels
- * @param pL length (Z) of one block in pixels
- * @return bm is returned back
- *
- * @throws Version.VersionException when the version of the chunk is unsupported.
- */
- public Bitmap renderToBitmap(ChunkManager cm, Bitmap bm, Dimension dimension, int chunkX, int chunkZ, int bX, int bZ, int eX, int eZ, int pX, int pY, int pW, int pL) throws Version.VersionException {
-
- Chunk chunk = cm.getChunk(chunkX, chunkZ);
- Version cVersion = chunk.getVersion();
-
- if(cVersion == Version.ERROR) return MapType.ERROR.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- if(cVersion == Version.NULL) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
-
- //the bottom sub-chunk is sufficient to get heightmap data.
- TerrainChunkData data;
-
-
- int x, y, z, color, i, j, tX, tY;
+ public void renderToBitmap(Chunk chunk, Canvas canvas, Dimension dimension, int chunkX, int chunkZ, int pX, int pY, int pW, int pL, Paint paint, WorldData worldData) throws Version.VersionException {
//render width in blocks
- int rW = eX - bX;
- int size2D = rW * (eZ - bZ);
+ int rW = 16;
+ int size2D = rW * (16);
int index2D;
- Block[] bestBlock = new Block[size2D];
+ var bestBlock = new BlockTemplate[size2D];
int[] minValue = new int[size2D];
int bValue;
- Block block;
int average;
- int r, g, b;
-
- int subChunk;
- for(subChunk = 0; subChunk < cVersion.subChunks; subChunk++) {
- data = chunk.getTerrain((byte) subChunk);
- if (data == null || !data.loadTerrain()) break;
-
- for (z = bZ; z < eZ; z++) {
- for (x = bX; x < eX; x++) {
-
- for (y = 0; y < cVersion.subChunkHeight; y++) {
- block = Block.getBlock(data.getBlockTypeId(x, y, z) & 0xff, 0);
-
- index2D = ((z - bZ) * rW) + (x - bX);
- if (block == null || block.id <= 1)
- continue;
- else if (block == Block.B_56_0_DIAMOND_ORE) {
- bestBlock[index2D] = block;
- break;
- } else if (block == Block.B_129_0_EMERALD_ORE) bValue = 8;
- else if (block == Block.B_153_0_QUARTZ_ORE) bValue = 7;
- else if (block == Block.B_14_0_GOLD_ORE) bValue = 6;
- else if (block == Block.B_15_0_IRON_ORE) bValue = 5;
- else if (block == Block.B_73_0_REDSTONE_ORE) bValue = 4;
- else if (block == Block.B_21_0_LAPIS_ORE) bValue = 3;
- //else if(block == Block.COAL_ORE) bValue = 2;
- //else if(b == Block.LAVA || b == Block.STATIONARY_LAVA) bValue = 1;
- else bValue = 0;
-
- if (bValue > minValue[index2D]) {
- minValue[index2D] = bValue;
- bestBlock[index2D] = block;
- }
+ BlockTemplate blockTemplate;
+
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++) {
+
+ for (int y = 0; y < chunk.getHeightLimit(); y++) {
+ blockTemplate = chunk.getBlockTemplate(x, y, z, 0);
+ var blockName = blockTemplate.getBlock().getName();
+ index2D = (z * rW) + x;
+ if (BlockTemplates.getAirTemplate().equals(blockTemplate)) continue;
+ else if ("minecraft:diamond_ore".equals(blockName)) {
+ bestBlock[index2D] = blockTemplate;
+ break;
+ } else if ("minecraft:emerald_ore".equals(blockName)) bValue = 8;
+ else if ("minecraft:quartz_ore".equals(blockName)) bValue = 7;
+ else if ("minecraft:gold_ore".equals(blockName)) bValue = 6;
+ else if ("minecraft:iron_ore".equals(blockName)) bValue = 5;
+ else if ("minecraft:redstone_ore".equals(blockName)) bValue = 4;
+ else if ("minecraft:lapis_ore".equals(blockName)) bValue = 3;
+ //else if(oldBlock == KnownBlockRepr.COAL_ORE) bValue = 2;
+ //else if(b == KnownBlockRepr.LAVA || b == KnownBlockRepr.STATIONARY_LAVA) bValue = 1;
+ else bValue = 0;
+
+ if (bValue > minValue[index2D]) {
+ minValue[index2D] = bValue;
+ bestBlock[index2D] = blockTemplate;
}
}
}
}
- if(subChunk == 0) return MapType.CHESS.renderer.renderToBitmap(cm, bm, dimension, chunkX, chunkZ, bX, bZ, eX, eZ, pX, pY, pW, pL);
- for (z = bZ, tY = pY; z < eZ; z++, tY += pL) {
- for (x = bX, tX = pX; x < eX; x++, tX += pW) {
- block = bestBlock[((z - bZ) * rW) + (x - bX)];
- if (block == null || block.color == null) {
+// if (y == 0) {
+// MapType.CHESS.renderer.renderToBitmap(chunk, canvas, dimension, chunkX, chunkZ, pX, pY, pW, pL, paint, version, chunkManager);
+// return;
+// }
+
+ for (int z = 0, tY = pY; z < 16; z++, tY += pL) {
+ for (int x = 0, tX = pX; x < 16; x++, tX += pW) {
+ blockTemplate = bestBlock[(z * rW) + x];
+ int color;
+ if (blockTemplate == null) {
color = 0xff000000;
} else {
- r = block.color.red;
- g = block.color.green;
- b = block.color.blue;
+ color = blockTemplate.getColor();
+
+ int r = Color.red(color);
+ int g = Color.green(color);
+ int b = Color.blue(color);
average = (r + g + b) / 3;
//make the color better recognizable
@@ -126,19 +98,12 @@ else if (block == Block.B_56_0_DIAMOND_ORE) {
color = (r << 16) | (g << 8) | (b) | 0xff000000;
}
-
-
- for (i = 0; i < pL; i++) {
- for (j = 0; j < pW; j++) {
- bm.setPixel(tX + j, tY + i, color);
- }
- }
+ paint.setColor(color);
+ canvas.drawRect(new Rect(tX, tY, tX + pW, tY + pL), paint);
}
}
-
- return bm;
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionChangedListener.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionChangedListener.java
new file mode 100644
index 00000000..0c5b5c90
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionChangedListener.java
@@ -0,0 +1,9 @@
+package com.mithrilmania.blocktopograph.map.selection;
+
+import android.graphics.Rect;
+
+public interface SelectionChangedListener {
+
+ void onSelectionChanged(Rect selection);
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionMenuFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionMenuFragment.java
new file mode 100644
index 00000000..1ad4d5e0
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionMenuFragment.java
@@ -0,0 +1,248 @@
+package com.mithrilmania.blocktopograph.map.selection;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.block.OldBlockRegistry;
+import com.mithrilmania.blocktopograph.databinding.FragSelMenuBinding;
+import com.mithrilmania.blocktopograph.map.FloatPaneFragment;
+import com.mithrilmania.blocktopograph.map.edit.ChBiomeFragment;
+import com.mithrilmania.blocktopograph.map.edit.EditFunction;
+import com.mithrilmania.blocktopograph.map.edit.SearchAndReplaceFragment;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.lang.ref.WeakReference;
+
+public class SelectionMenuFragment extends FloatPaneFragment {
+
+ public static final String TAG_SNR = "Snr";
+ public static final String TAG_CHBIOME = "Chbiome";
+
+ @NonNull
+ private final Rect mSelection = new Rect();
+ private FragSelMenuBinding mBinding;
+ @Nullable
+ private SelectionChangedListener mSelectionChangedListener;
+
+ private EditFunctionEntry mEditFunctionEntry;
+
+ private OldBlockRegistry registry;
+
+ public static SelectionMenuFragment newInstance(
+ @NonNull Rect initial, @NonNull OldBlockRegistry registry, @NonNull EditFunctionEntry editFunctionEntry) {
+ SelectionMenuFragment fragment = new SelectionMenuFragment();
+ fragment.mSelection.set(initial);
+ fragment.registry = registry;
+ fragment.mEditFunctionEntry = editFunctionEntry;
+ return fragment;
+ }
+
+ private static boolean isSelectionChunkAligned(@NonNull Rect selection) {
+ return (selection.left & 0xf) == 0 && (selection.right & 0xf) == 0
+ && (selection.top & 0xf) == 0 && (selection.bottom & 0xf) == 0;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ }
+
+ public void setSelectionChangedListener(@Nullable SelectionChangedListener selectionChangedListener) {
+ mSelectionChangedListener = selectionChangedListener;
+ }
+
+ public void onSelectionChangedOutsides(Rect rect) {
+ mSelection.set(rect);
+ mBinding.content.setSelection(rect);
+ }
+
+ private void onApply(View button) {
+
+ // It should not live alone without a selection board.
+ if (mSelectionChangedListener == null) {
+ if (mOnCloseButtonClickListener != null)
+ mOnCloseButtonClickListener.onCloseButtonClick();
+ return;
+ }
+
+ int errno = 0;
+ flow:
+ {
+ mSelection.left = UiUtil.readIntFromView(mBinding.content.fromXText);
+ mSelection.top = UiUtil.readIntFromView(mBinding.content.fromYText);
+ int tmp = UiUtil.readIntFromView(mBinding.content.rangeWText);
+ if (tmp < 1) {
+ errno = -1;
+ break flow;
+ }
+ mSelection.right = mSelection.left + tmp;
+ tmp = UiUtil.readIntFromView(mBinding.content.rangeHText);
+ if (tmp < 1) {
+ errno = -1;
+ break flow;
+ }
+ mSelection.bottom = mSelection.top + tmp;
+ mSelectionChangedListener.onSelectionChanged(mSelection);
+ }
+ switch (errno) {
+ case -1: {
+ Activity activity = getActivity();
+ if (activity != null)
+ Toast.makeText(activity,
+ R.string.map_sel_error_size_one, Toast.LENGTH_SHORT).show();
+ break;
+ }
+ }
+ }
+
+ private void onChooseLampshade(@NonNull View view) {
+ AlertDialog dialog = new AlertDialog.Builder(new ContextThemeWrapper(view.getContext(), R.style.AppTheme))
+ .setView(R.layout.dialog_lampshade)
+ .setTitle(R.string.map_edit_func_lampshade)
+ .setPositiveButton(android.R.string.ok,
+ (dialogInterface, i) -> mEditFunctionEntry.invokeEditFunction(EditFunction.LAMPSHADE, null))
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ dialog.show();
+ Log.logFirebaseEvent(view.getContext(), Log.CustomFirebaseEvent.SNR_OPEN);
+ }
+
+ private void onChooseSnr(View view) {
+ SearchAndReplaceFragment fragment = SearchAndReplaceFragment.newInstance(registry, mEditFunctionEntry);
+ FragmentManager fragmentManager = getMeowFragmentManager();
+ fragment.show(fragmentManager, TAG_SNR);
+ Log.logFirebaseEvent(view.getContext(), Log.CustomFirebaseEvent.SNR_OPEN);
+ }
+
+ private void onChooseDchunk(View view) {
+ String text = getString(R.string.map_edit_dchunk_explain);
+ boolean aligned = isSelectionChunkAligned(mSelection);
+ if (!aligned)
+ text += "\n\n" + getString(R.string.map_edit_dchunk_warn_not_aligned);
+ AlertDialog dialog = new AlertDialog.Builder(new ContextThemeWrapper(view.getContext(), R.style.AppTheme))
+ .setTitle(R.string.map_edit_func_dchunk)
+ .setMessage(text)
+ .setPositiveButton(aligned ? android.R.string.ok : R.string.map_edit_dchunk_posbtn_with_auto_adjust,
+ ((dialogInterface, i) -> mEditFunctionEntry.invokeEditFunction(EditFunction.DCHUNK, null)))
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ dialog.show();
+ Log.logFirebaseEvent(view.getContext(), Log.CustomFirebaseEvent.DCHUNK);
+ }
+
+ private void onChooseChbiome(View view) {
+ ChBiomeFragment fragment = ChBiomeFragment.newInstance(mEditFunctionEntry);
+ FragmentManager fragmentManager = getMeowFragmentManager();
+ fragment.show(fragmentManager, TAG_CHBIOME);
+ Log.logFirebaseEvent(view.getContext(), Log.CustomFirebaseEvent.CH_BIOME);
+ }
+
+ private void onChoosePicer(View view) {
+ mEditFunctionEntry.invokeEditFunction(EditFunction.PICER, null);
+ }
+
+ @NonNull
+ private FragmentManager getMeowFragmentManager() {
+ FragmentActivity activity = getActivity();
+ FragmentManager fragmentManager = null;
+ if (activity != null) fragmentManager = activity.getSupportFragmentManager();
+ if (fragmentManager == null) fragmentManager = getChildFragmentManager();
+ return fragmentManager;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ mBinding = DataBindingUtil.inflate(inflater, R.layout.frag_sel_menu, container, false);
+ mBinding.content.setSelection(mSelection);
+ mBinding.content.fromXText.addTextChangedListener(new MeowWatcher(mBinding.content.fromXText));
+ mBinding.content.fromYText.addTextChangedListener(new MeowWatcher(mBinding.content.fromYText));
+ mBinding.content.rangeWText.addTextChangedListener(new MeowWatcher(mBinding.content.rangeWText));
+ mBinding.content.rangeHText.addTextChangedListener(new MeowWatcher(mBinding.content.rangeHText));
+ mBinding.content.applyButton.setOnClickListener(this::onApply);
+ mBinding.content.funcLampshade.setOnClickListener(this::onChooseLampshade);
+ mBinding.content.funcSnr.setOnClickListener(this::onChooseSnr);
+ mBinding.content.funcDchunk.setOnClickListener(this::onChooseDchunk);
+ mBinding.content.funcChbiome.setOnClickListener(this::onChooseChbiome);
+ mBinding.content.funcPicer.setOnClickListener(this::onChoosePicer);
+ return mBinding.getRoot();
+ }
+
+ public interface EditFunctionEntry {
+ void invokeEditFunction(@NonNull EditFunction func, @Nullable Bundle args);
+ }
+
+ private class MeowWatcher implements TextWatcher {
+
+ private final WeakReference which;
+
+ MeowWatcher(EditText which) {
+ this.which = new WeakReference<>(which);
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ EditText which = this.which.get();
+ if (which == null) return;
+ String text = editable.toString();
+ int val;
+ try {
+ val = Integer.parseInt(text);
+ } catch (NumberFormatException e) {
+ return;
+ }
+ switch (which.getId()) {
+ case R.id.from_x_text:
+ if (mSelection.left == val) return;
+ which.removeTextChangedListener(this);
+ mSelection.right += val - mSelection.left;
+ mSelection.left = val;
+ break;
+ case R.id.from_y_text:
+ if (mSelection.top == val) return;
+ which.removeTextChangedListener(this);
+ mSelection.bottom += val - mSelection.top;
+ mSelection.top = val;
+ break;
+ case R.id.range_w_text:
+ if (mSelection.right - mSelection.left == val) return;
+ which.removeTextChangedListener(this);
+ mSelection.right = mSelection.left + val;
+ break;
+ case R.id.range_h_text:
+ if (mSelection.bottom - mSelection.top == val) return;
+ which.removeTextChangedListener(this);
+ mSelection.bottom = mSelection.top + val;
+ break;
+ }
+ mBinding.content.setSelection(mSelection);
+ which.addTextChangedListener(this);
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionView.java b/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionView.java
new file mode 100644
index 00000000..41f22b7e
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/map/selection/SelectionView.java
@@ -0,0 +1,671 @@
+package com.mithrilmania.blocktopograph.map.selection;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import androidx.annotation.IdRes;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.map.MCTileProvider;
+import com.mithrilmania.blocktopograph.map.MapTileView;
+import com.mithrilmania.blocktopograph.util.ConvertUtil;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.lang.ref.WeakReference;
+
+public class SelectionView extends FrameLayout {
+
+ /**
+ * The view being dragged now.
+ */
+ @Nullable
+ private View mDragger;
+
+ /**
+ * Correction of drag begin point.
+ *
+ *
+ * It's the relative distance between the initially touched point
+ * and the view's left-top coordinates.
+ * ------------------
+ * | |
+ * |--[ This ]--X |
+ * | |
+ * | |
+ * ------------------
+ *
+ */
+ private float mDragBeginPosCorr;
+
+ /**
+ * Drag distance accumulation.
+ *
+ *
+ * If the drag distance of a given moment cannot move the selection
+ * at least 1 oldBlock's wide, we accumulate the distance to have a larger
+ * chance to move on the next round.
+ *
+ */
+ private float mDragAccumulation;
+
+ /**
+ * Current touch position.
+ *
+ *
+ * Produced in `onTouch` and consumed in `onMove`.
+ *
+ */
+ private float mDragCurrentPos;
+
+ /**
+ * Current dragging direction.
+ *
+ *
+ * Used for anti-jitter purpose.
+ *
+ */
+ private int mDragDirection;
+
+ /**
+ * Paint object used to draw selection onto canvas.
+ */
+ private final Paint mPaint = new Paint();
+
+ /**
+ * Selection range.
+ */
+ private final Rect mSelectionRect = new Rect();
+
+ /**
+ * The tileView we serves for.
+ */
+ private WeakReference mTileView;
+
+ /**
+ * Range of selection in pixel.
+ */
+ private final RectF mSelectionPixelRange = new RectF();
+
+ /**
+ * Visible range of selection in pixel.
+ */
+ private final RectF mVisiblePixelRange = new RectF();
+
+ /**
+ * Minimal distance between drag button and bound.
+ * -----O---------------------------
+ * |----| Like this.
+ */
+ private float BUTTON_TO_BOUND_MIN_DIST;
+
+ /**
+ * The minimal non-auto-scroll distance from touched point to screen boundary.
+ *
+ *
+ * Once it's exceed the tileView would be scrolled automatically.
+ *
+ */
+ private int MIN_DIST_TO_SCREEN_BOUND;
+
+ private int MIN_DIST_DRAGGERS;
+
+ private int HALF_MIN_DIST_DRAGGERS;
+
+ /**
+ * Runnable used to frequently alter selection while user dragging a adjust button.
+ */
+ private final Runnable mHoldingMover = this::onMove;
+
+ /**
+ * Indicates whether a selection exists.
+ */
+ private boolean mHasSelection;
+
+ /**
+ * The selection could be changed outsides, so we need this.
+ */
+ @Nullable
+ private SelectionChangedListener mSelectionChangedListener;
+
+ public SelectionView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public SelectionView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public SelectionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ public SelectionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(context);
+ }
+
+ private void init(Context context) {
+
+ // The viewGroup has static content.
+ LayoutInflater.from(context).inflate(R.layout.view_selection_view, this, true);
+
+ mPaint.setColor(Color.argb(0x80, 0, 0, 0));
+ setWillNotDraw(false);// Otherwise `onDraw` won't be called.
+ BUTTON_TO_BOUND_MIN_DIST = UiUtil.dpToPx(context, 72);
+ MIN_DIST_TO_SCREEN_BOUND = UiUtil.dpToPxInt(context, 100);
+ MIN_DIST_DRAGGERS = UiUtil.dpToPxInt(context, 50);
+ HALF_MIN_DIST_DRAGGERS = MIN_DIST_DRAGGERS / 2;
+
+ mDragger = null;
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public void onViewAdded(View child) {
+ switch (child.getId()) {
+ case R.id.left:
+ case R.id.right:
+ case R.id.top:
+ case R.id.bottom:
+ child.setOnTouchListener(this::onTouch);
+ break;
+ }
+ }
+
+ private boolean onTouch(View view, MotionEvent motionEvent) {
+
+ MapTileView tileView;
+ if (mTileView == null || (tileView = mTileView.get()) == null) return false;
+
+ // If already dragging another button, disallow dragging a second one.
+ @IdRes int which = view.getId();
+ if (mDragger != null && which != mDragger.getId()) {
+ // Well if we return false for an ACTION_DOWN then it won't bother popping
+ // Tons of confusing ACTION_MOVEs.
+ return false;
+ }
+
+ // Set current pos.
+ switch (which) {
+ case R.id.left:
+ case R.id.right:
+ // Motion event's get x is relative to view's x. Sum 'em up.
+ mDragCurrentPos = view.getX() + motionEvent.getX();
+ break;
+ case R.id.top:
+ case R.id.bottom:
+ mDragCurrentPos = view.getY() + motionEvent.getY();
+ break;
+ }
+
+ switch (motionEvent.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+
+ // Begin visual effect on the pressed button.
+ view.setPressed(true);
+
+ // Show icon.
+ View actionIcon = getChildAt(4);
+ actionIcon.setVisibility(VISIBLE);
+
+ switch (which) {
+ case R.id.left:
+ actionIcon.setRotation(270.0f);
+ break;
+ case R.id.right:
+ actionIcon.setRotation(90.0f);
+ break;
+ case R.id.top:
+ actionIcon.setRotation(0.0f);
+ break;
+ case R.id.bottom:
+ actionIcon.setRotation(180.0f);
+ break;
+ }
+
+ // Prevents tileView being touched while dragging.
+ tileView.setTouchable(false);
+
+ // Set current dragging item.
+ mDragger = view;
+ switch (which) {
+ case R.id.left:
+ case R.id.right:
+ mDragBeginPosCorr = motionEvent.getX();// - view.getX();
+ break;
+ case R.id.top:
+ case R.id.bottom:
+ mDragBeginPosCorr = motionEvent.getY();// - view.getY();
+ break;
+ }
+ mDragAccumulation = 0.0f;
+ mDragDirection = 0;
+
+ // And trigger a continuous detecting.
+ post(mHoldingMover);
+
+ // IMPORTANT! Forgot this once. Fuck you man, fuck you!
+ return true;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+
+ // End visual effect.
+ view.setPressed(false);
+
+ // Hide icon.
+ getChildAt(4).setVisibility(GONE);
+
+ // Clear & Unlock.
+ tileView.setTouchable(true);
+ mDragger = null;
+ return true;
+
+ case MotionEvent.ACTION_MOVE:
+ //onMove(tileView, which, motionEvent);
+ return true;
+ }
+
+ return false;
+ }
+
+ private void onMove() {
+
+ // The tileView we serves for.
+ MapTileView tileView;
+
+ // If user no longer holding or we don't have a tileView to serve for.
+ if (mDragger == null || !isEnabled() ||
+ mTileView == null || (tileView = mTileView.get()) == null) return;
+
+ // Distance between view position and current holding position.
+ float distOnScreen;
+
+ // Get the view to retrieve its position.
+
+ // Won't happen.
+ if (mDragger == null) return;
+
+ // Retrieve view position then get the distance and screen size.
+ int draggerId = mDragger.getId();
+ switch (draggerId) {
+ case R.id.left:
+ case R.id.right:
+ // `dragged.getX() - mDragBeginPosCorr` is the current position of user's initially
+ // touched point of the View.
+ distOnScreen = mDragCurrentPos - mDragger.getX() - mDragBeginPosCorr;
+ break;
+ case R.id.top:
+ case R.id.bottom:
+ distOnScreen = mDragCurrentPos - mDragger.getY() - mDragBeginPosCorr;
+ break;
+ default:
+ return;
+ }
+
+ flow:
+ {
+ // Amplify movement. Maybe we'd allow user to set it, or calculate based on screen
+ // density and tileView's scale.
+ float amp = 0.2f;
+
+ //Log.d(this, "" + distOnScreen + "," + mDragCurrentPos + "," + mDragBeginPosCorr);
+
+ // If a previous round failed to move at least 1 oldBlock's wide,
+ // it would accumulate the distance till in a future round we could move.
+ float movement = distOnScreen * amp + mDragAccumulation;
+
+ // Translate the distance back to blocks count.
+ float scale = tileView.getScale();
+ float pxPerBlx = scale * MCTileProvider.TILESIZE / 16;
+ int distanceInBlocks = Math.round(movement / pxPerBlx);
+
+ // If it's less than a oldBlock we couldn't move, let the accumulation grow.
+ if (distanceInBlocks == 0) {//&& Math.abs(movement) >= 0.00001f) {
+ mDragAccumulation = movement;
+ break flow;
+ }
+
+ // Anti-jitter. If the user's scrolling right carefully, we don't want it suddenly goes
+ // left because the view also moved and moved faster than the finger.
+ if (// If previous direction set, is negative to current, and current movement is short.
+ (distanceInBlocks < 0 && mDragDirection > 0 && distOnScreen > -10.0f)
+ || (distanceInBlocks > 0 && mDragDirection < 0 && distOnScreen < 10.0f)) {
+ // Then we do not move and clear accumulation.
+ mDragAccumulation = 0;
+ break flow;
+ }
+
+ // Set direction for next round's anti-jitter.
+ mDragDirection = distanceInBlocks > 0 ? 1 : -1;
+
+ // We've decided to move NOW AND TODAY clear accumulation.
+ mDragAccumulation = 0;
+
+ // Alter selection.
+ // Selection shall be at least 1x1.
+ switch (draggerId) {
+ case R.id.left:
+ if (mSelectionRect.left + distanceInBlocks >= mSelectionRect.right) {
+ mSelectionRect.left = mSelectionRect.right - 1;
+ distanceInBlocks = 0;
+ } else mSelectionRect.left += distanceInBlocks;
+ break;
+ case R.id.right:
+ if (mSelectionRect.right + distanceInBlocks <= mSelectionRect.left) {
+ mSelectionRect.right = mSelectionRect.left + 1;
+ distanceInBlocks = 0;
+ } else mSelectionRect.right += distanceInBlocks;
+ break;
+ case R.id.top:
+ if (mSelectionRect.top + distanceInBlocks >= mSelectionRect.bottom) {
+ mSelectionRect.top = mSelectionRect.bottom - 1;
+ distanceInBlocks = 0;
+ } else mSelectionRect.top += distanceInBlocks;
+ break;
+ case R.id.bottom:
+ if (mSelectionRect.bottom + distanceInBlocks <= mSelectionRect.top) {
+ mSelectionRect.bottom = mSelectionRect.top + 1;
+ distanceInBlocks = 0;
+ } else mSelectionRect.bottom += distanceInBlocks;
+ break;
+ }
+
+ // If no movement, return.
+ // It would be caused by the "Selection must be at least 1x1" rule.
+ // For instance in case it's already 200x1 we can't move vertically.
+ if (distanceInBlocks == 0) break flow;
+
+ // Notify outsides.
+ if (mSelectionChangedListener != null)
+ mSelectionChangedListener.onSelectionChanged(mSelectionRect);
+
+ // Should we move the underlying tileView as well?
+ // If touched point is near the moving direction (not the dragger position)
+ // then we scroll.
+
+ int sw = getMeasuredWidth();
+ int sh = getMeasuredHeight();
+ int minw = Math.max(MIN_DIST_TO_SCREEN_BOUND, sw / 8);
+ int minh = Math.max(MIN_DIST_TO_SCREEN_BOUND, sh / 8);
+
+ switch (draggerId) {
+ case R.id.left:
+ case R.id.right:
+ // (Moving right and near right bound) or
+ // (Moving left and near left bound)
+ if (mDragDirection > 0 && sw - mDragCurrentPos < minw
+ || (mDragDirection < 0 && mDragCurrentPos < minw)
+ )
+ tileView.setScrollX((int) (tileView.getScrollX() + movement));
+ else
+ requestLayout();
+ break;
+ case R.id.top:
+ case R.id.bottom:
+ if (mDragDirection > 0 && sh - mDragCurrentPos < minh
+ || (mDragDirection < 0 && mDragCurrentPos < minh)
+ )
+ tileView.setScrollY((int) (tileView.getScrollY() + movement));
+ else
+ requestLayout();
+ break;
+ }
+ }
+
+ // Schedule the next round.
+ postDelayed(mHoldingMover, 40);
+ }
+
+ public void setTileView(MapTileView tileView) {
+ mTileView = new WeakReference<>(tileView);
+ }
+
+ public void beginSelection(Rect selection) {
+ mHasSelection = true;
+ mSelectionRect.set(selection);
+ setVisibility(VISIBLE);
+ requestLayout();
+ }
+
+ public void beginSelection(int centerX, int centerZ) {
+
+ // Requires this.
+ MapTileView tileView;
+ if (mTileView == null || (tileView = mTileView.get()) == null) return;
+
+ // Self's not visible now and not sure whether has measured dimensions.
+ // Use tileView's instead.
+ float scale = tileView.getScale();
+ int w = tileView.getMeasuredWidth();
+ int h = tileView.getMeasuredHeight();
+
+ // Selection would be a square with length of half screen dimension.
+ if (w > h) w = h / 4;
+ else w /= 4;
+
+ // Translate to blocks.
+ float pxPerBlx = scale * MCTileProvider.TILESIZE / 16;
+ int rad = Math.round(w / pxPerBlx);
+ mHasSelection = true;
+
+ // Set it.
+ mSelectionRect.set(centerX - rad, centerZ - rad,
+ centerX + rad, centerZ + rad);
+ setVisibility(VISIBLE);
+ requestLayout();
+ }
+
+ public void onSelectionChangedOutsides(Rect rect) {
+ mSelectionRect.set(rect);
+ // If the selection's far away from current viewport,
+ // We want tho scroll the tileView to a nearest corner of the selection.
+ MapTileView tileView;
+ if (mTileView != null && (tileView = mTileView.get()) != null) {
+ float pxPerBlx = tileView.getScale() * MCTileProvider.TILESIZE / 16;
+ RectF r = new RectF();
+ r.left = (rect.left + MCTileProvider.HALF_WORLDSIZE) * pxPerBlx;
+ r.top = (rect.top + MCTileProvider.HALF_WORLDSIZE) * pxPerBlx;
+ r.right = (rect.right + MCTileProvider.HALF_WORLDSIZE) * pxPerBlx;
+ r.bottom = (rect.bottom + MCTileProvider.HALF_WORLDSIZE) * pxPerBlx;
+ int scrollX = tileView.getScrollX();
+ int scrollY = tileView.getScrollY();
+ int sw = getMeasuredWidth();
+ int sh = getMeasuredHeight();
+ RectF viewport = new RectF(scrollX, scrollY, scrollX + sw, scrollY + sh);
+ if (!viewport.intersect(r)) {
+ float hw = sw / 2.0f;
+ float currentX = scrollX + hw;
+ float hh = sh / 2.0f;
+ float currentY = scrollY + hh;
+ float dlt = ConvertUtil.distance(currentX, currentY, r.left, r.top);
+ float drt = ConvertUtil.distance(currentX, currentY, r.right, r.top);
+ float dlb = ConvertUtil.distance(currentX, currentY, r.left, r.bottom);
+ float drb = ConvertUtil.distance(currentX, currentY, r.right, r.bottom);
+ if (dlt < drt && dlt < dlb && dlt < drb) {
+ tileView.setScrollX((int) (r.left - hw));
+ tileView.setScrollY((int) (r.top - hh));
+ } else if (drt < dlb && drt < drb) {
+ tileView.setScrollX((int) (r.right - hw));
+ tileView.setScrollY((int) (r.top - hh));
+ } else if (dlb < drb) {
+ tileView.setScrollX((int) (r.left - hw));
+ tileView.setScrollY((int) (r.bottom - hh));
+ } else {
+ tileView.setScrollX((int) (r.right - hw));
+ tileView.setScrollY((int) (r.bottom - hh));
+ }
+ }
+ }
+ requestLayout();
+ }
+
+ public void endSelection() {
+ mHasSelection = false;
+ setVisibility(GONE);
+ requestLayout();
+ }
+
+ public boolean hasSelection() {
+ return mHasSelection;
+ }
+
+
+ public Rect getSelection() {
+ return new Rect(mSelectionRect);
+ }
+
+ @Override
+ protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
+
+ if (!mHasSelection) return;
+
+ float sw = getMeasuredWidth();
+ float sh = getMeasuredHeight();
+
+ MapTileView tileView;
+ if (mTileView == null || (tileView = mTileView.get()) == null) return;
+
+ float scale = tileView.getScale();
+
+ // Pixels per oldBlock.
+ float pxPerBlx = scale * MCTileProvider.TILESIZE / 16;
+
+ // This would translate coordinate related to view, e.g. getScrollX() result,
+ // into coordinate related to World.
+ float halfWorld = pxPerBlx * MCTileProvider.HALF_WORLDSIZE;
+
+ // These translate selection dimensions (rel. to World) to screen.
+ float transToScrX = (float) tileView.getScrollX() - halfWorld;
+ float transToScrY = (float) tileView.getScrollY() - halfWorld;
+
+ // Draw selected range
+
+ mSelectionPixelRange.left = pxPerBlx * mSelectionRect.left - transToScrX;
+ mSelectionPixelRange.top = pxPerBlx * mSelectionRect.top - transToScrY;
+ mSelectionPixelRange.right = pxPerBlx * mSelectionRect.right - transToScrX;
+ mSelectionPixelRange.bottom = pxPerBlx * mSelectionRect.bottom - transToScrY;
+
+ // To the middle of lefter bound of on-screen selection area.
+ float horix = ((mSelectionPixelRange.left < 0 ? 0.0f : mSelectionPixelRange.left)
+ + (mSelectionPixelRange.right > sw ? sw : mSelectionPixelRange.right)) / 2.0f;
+ float verty = ((mSelectionPixelRange.top < 0 ? 0.0f : mSelectionPixelRange.top)
+ + (mSelectionPixelRange.bottom > sh ? sh : mSelectionPixelRange.bottom)) / 2.0f;
+
+ // In case the selection's not too small.
+ if (mSelectionPixelRange.right - mSelectionPixelRange.left > BUTTON_TO_BOUND_MIN_DIST * 2) {
+
+ if (horix - mSelectionPixelRange.left < BUTTON_TO_BOUND_MIN_DIST)
+ horix = mSelectionPixelRange.left + BUTTON_TO_BOUND_MIN_DIST;
+
+ if (mSelectionPixelRange.right - horix < BUTTON_TO_BOUND_MIN_DIST)
+ horix = mSelectionPixelRange.right - BUTTON_TO_BOUND_MIN_DIST;
+
+ }
+ if (mSelectionPixelRange.bottom - mSelectionPixelRange.top > BUTTON_TO_BOUND_MIN_DIST * 2) {
+
+ if (verty - mSelectionPixelRange.top < BUTTON_TO_BOUND_MIN_DIST)
+ verty = mSelectionPixelRange.top + BUTTON_TO_BOUND_MIN_DIST;
+
+ if (mSelectionPixelRange.bottom - verty < BUTTON_TO_BOUND_MIN_DIST)
+ verty = mSelectionPixelRange.bottom - BUTTON_TO_BOUND_MIN_DIST;
+
+ }
+
+ int horit = (int) mSelectionPixelRange.top;
+ int vertl = (int) mSelectionPixelRange.left;
+ int horib = (int) mSelectionPixelRange.bottom;
+ int vertr = (int) mSelectionPixelRange.right;
+ int horixi = (int) horix;
+ int vertyi = (int) verty;
+
+ // Let's prevent draggers collapse together when the selection's small.
+
+ if (horib - horit <= MIN_DIST_DRAGGERS) {
+ horit -= HALF_MIN_DIST_DRAGGERS;
+ horib += HALF_MIN_DIST_DRAGGERS;
+ }
+
+ if (vertr - vertl <= MIN_DIST_DRAGGERS) {
+ vertl -= HALF_MIN_DIST_DRAGGERS;
+ vertr += HALF_MIN_DIST_DRAGGERS;
+ }
+
+ // Left
+ View view = getChildAt(0);
+ int humw = view.getMeasuredWidth() / 2;
+ int humh = view.getMeasuredHeight() / 2;
+ view.layout(vertl - humw, vertyi - humh, vertl + humw, vertyi + humh);
+
+ // Top
+ view = getChildAt(1);
+ humw = view.getMeasuredWidth() / 2;
+ humh = view.getMeasuredHeight() / 2;
+ view.layout(horixi - humw, horit - humh, horixi + humw, horit + humh);
+
+ // Right
+ view = getChildAt(2);
+ humw = view.getMeasuredWidth() / 2;
+ humh = view.getMeasuredHeight() / 2;
+ view.layout(vertr - humw, vertyi - humh, vertr + humw, vertyi + humh);
+
+ // Top
+ view = getChildAt(3);
+ humw = view.getMeasuredWidth() / 2;
+ humh = view.getMeasuredHeight() / 2;
+ view.layout(horixi - humw, horib - humh, horixi + humw, horib + humh);
+
+ // Current action icon.
+ view = getChildAt(4);
+ {
+ int vw = view.getMeasuredWidth();
+ int vh = view.getMeasuredHeight();
+ int l = (getMeasuredWidth() - vw) / 2;
+ int t = (getMeasuredHeight() - vh) / 2;
+ view.layout(l, t, l + vw, t + vh);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (!mHasSelection) return;
+
+ // Screen dimensions.
+ float sw = getMeasuredWidth();
+ float sh = getMeasuredHeight();
+
+ if (!canvas.quickReject(mSelectionPixelRange, Canvas.EdgeType.BW)) {
+
+ mVisiblePixelRange.left = (mSelectionPixelRange.left < 0.0f) ? 0.0f : mSelectionPixelRange.left;
+ mVisiblePixelRange.top = (mSelectionPixelRange.top < 0.0f) ? 0.0f : mSelectionPixelRange.top;
+ mVisiblePixelRange.right = (mSelectionPixelRange.right > sw) ? sw : mSelectionPixelRange.right;
+ mVisiblePixelRange.bottom = (mSelectionPixelRange.bottom > sh) ? sh : mSelectionPixelRange.bottom;
+
+ canvas.drawRect(mVisiblePixelRange, mPaint);
+ }
+
+ }
+
+ public void setSelectionChangedListener(@Nullable SelectionChangedListener selectionChangedListener) {
+ mSelectionChangedListener = selectionChangedListener;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/EditorFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/EditorFragment.java
index 9807ec54..5852d729 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/EditorFragment.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/EditorFragment.java
@@ -3,40 +3,44 @@
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
-import android.support.design.widget.FloatingActionButton;
-import android.support.design.widget.Snackbar;
import android.text.Editable;
-import android.text.Layout;
import android.text.TextWatcher;
-import com.mithrilmania.blocktopograph.Log;
-
-import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.android.material.snackbar.Snackbar;
+import com.mithrilmania.blocktopograph.Log;
import com.mithrilmania.blocktopograph.R;
-import com.mithrilmania.blocktopograph.WorldActivity;
import com.mithrilmania.blocktopograph.WorldActivityInterface;
import com.mithrilmania.blocktopograph.nbt.convert.NBTConstants;
-import com.mithrilmania.blocktopograph.nbt.tags.*;
-import com.unnamed.b.atv.holder.SimpleViewHolder;
+import com.mithrilmania.blocktopograph.nbt.tags.ByteTag;
+import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
+import com.mithrilmania.blocktopograph.nbt.tags.DoubleTag;
+import com.mithrilmania.blocktopograph.nbt.tags.FloatTag;
+import com.mithrilmania.blocktopograph.nbt.tags.IntTag;
+import com.mithrilmania.blocktopograph.nbt.tags.ListTag;
+import com.mithrilmania.blocktopograph.nbt.tags.LongTag;
+import com.mithrilmania.blocktopograph.nbt.tags.ShortTag;
+import com.mithrilmania.blocktopograph.nbt.tags.StringTag;
+import com.mithrilmania.blocktopograph.nbt.tags.Tag;
import com.unnamed.b.atv.model.TreeNode;
import com.unnamed.b.atv.view.AndroidTreeView;
@@ -46,545 +50,143 @@
public class EditorFragment extends Fragment {
/**
- *
* TODO:
- *
+ *
* - The onSomethingChanged listeners should start Asynchronous tasks
- * when directly modifying NBT.
- *
+ * when directly modifying NBT.
+ *
* - This editor should be refactored into parts, it grew too large.
- *
+ *
* - The functions lack documentation. Add it. Ask @mithrilmania for now...
- *
*/
private EditableNBT nbt;
- public void setEditableNBT(EditableNBT nbt){
+ public void setNbt(@NonNull EditableNBT nbt) {
this.nbt = nbt;
}
- public static class ChainTag {
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
- public Tag parent, self;
- public ChainTag(Tag parent, Tag self){
- this.parent = parent;
- this.self = self;
+ if (nbt == null) {
+ Log.e(this, "No NBT data provided");
+ if (getActivity() == null) return null;
+ //What are you doing!
+ TextView textView = new TextView(getActivity());
+ textView.setText("Cannot load data. Close me please.");
+ return textView;
}
- }
- public static class RootNodeHolder extends TreeNode.BaseNodeViewHolder{
+ final View rootView = inflater.inflate(R.layout.nbt_editor, container, false);
+ // edit functionality
+ // ================================
- public RootNodeHolder(Context context) {
- super(context);
- }
+ TreeNode superRoot = TreeNode.root();
+ TreeNode root = new TreeNode(nbt);
+ superRoot.addChild(root);
+ root.setExpanded(true);
+ root.setSelectable(false);
- @Override
- public View createNodeView(TreeNode node, EditableNBT value) {
- final LayoutInflater inflater = LayoutInflater.from(context);
+ final Activity activity = getActivity();
- final View tagView = inflater.inflate(R.layout.tag_root_layout, null, false);
- TextView tagName = (TextView) tagView.findViewById(R.id.tag_name);
- tagName.setText(value.getRootTitle());
+ root.setViewHolder(new RootNodeHolder(activity));
- return tagView;
+ for (Tag tag : nbt.getTags()) {
+ if (tag != null)
+ root.addChild(new TreeNode(new ChainTag(null, tag)).setViewHolder(new NBTNodeHolder(nbt, activity)));
}
- @Override
- public void toggle(boolean active) {
- }
+ FrameLayout frame = rootView.findViewById(R.id.nbt_editor_frame);
- @Override
- public int getContainerStyle() {
- return R.style.TreeNodeStyleCustomRoot;
- }
- }
+ final AndroidTreeView tree = new AndroidTreeView(getActivity(), superRoot);
+ tree.setUse2dScroll(true);
+ final View treeView = tree.getView();
- public static class NBTNodeHolder extends TreeNode.BaseNodeViewHolder {
+ treeView.setScrollContainer(true);
- private final EditableNBT nbt;
+ tree.setDefaultNodeLongClickListener(new TreeNode.TreeNodeLongClickListener() {
+ @Override
+ public boolean onLongClick(final TreeNode node, final Object value) {
- public NBTNodeHolder(EditableNBT nbt, Context context) {
- super(context);
- this.nbt = nbt;
- }
+ Log.d(this, "NBT editor: Long click!");
- @SuppressLint("SetTextI18n")
- @Override
- public View createNodeView(TreeNode node, final ChainTag chain) {
- if(chain == null) return null;
- Tag tag = chain.self;
- if(tag == null) return null;
+ //root tag has nbt as value
+ if (value instanceof EditableNBT) {
- final LayoutInflater inflater = LayoutInflater.from(context);
+ if (!nbt.enableRootModifications) {
+ Toast.makeText(activity, R.string.cannot_edit_root_NBT_tag, Toast.LENGTH_LONG).show();
+ return true;
+ }
- int layoutID;
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- switch (tag.getType()) {
- case COMPOUND: {
- List value = ((CompoundTag) tag).getValue();
- if (value != null) {
- for (Tag child : value) {
- node.addChild(new TreeNode(new ChainTag(tag, child)).setViewHolder(new NBTNodeHolder(nbt, context)));
- }
- }
+ builder.setTitle(R.string.root_NBT_options)
+ .setItems(getRootNBTEditOptions(), new DialogInterface.OnClickListener() {
- layoutID = R.layout.tag_compound_layout;
- break;
- }
- case LIST: {
- List value = ((ListTag) tag).getValue();
+ private void showMsg(int msg) {
+ Toast.makeText(activity, msg, Toast.LENGTH_LONG).show();
+ }
- if (value != null) {
- for (Tag child : value) {
- node.addChild(new TreeNode(new ChainTag(tag, child)).setViewHolder(new NBTNodeHolder(nbt, context)));
- }
- }
+ public void onClick(DialogInterface dialog, int which) {
+ try {
+ RootNBTEditOption option = RootNBTEditOption.values()[which];
- layoutID = R.layout.tag_list_layout;
- break;
- }
- case BYTE_ARRAY: {
- layoutID = R.layout.tag_default_layout;
- break;
- }
- case BYTE: {
- String name = tag.getName().toLowerCase();
+ switch (option) {
+ case ADD_NBT_TAG: {
+ final EditText nameText = new EditText(activity);
+ nameText.setHint(R.string.hint_tag_name_here);
- //TODO differentiate boolean tags from byte tags better
- if (name.startsWith("has") || name.startsWith("is")) {
- layoutID = R.layout.tag_boolean_layout;
- } else {
- layoutID = R.layout.tag_byte_layout;
- }
- break;
- }
- case SHORT:
- layoutID = R.layout.tag_short_layout;
- break;
- case INT:
- layoutID = R.layout.tag_int_layout;
- break;
- case LONG:
- layoutID = R.layout.tag_long_layout;
- break;
- case FLOAT:
- layoutID = R.layout.tag_float_layout;
- break;
- case DOUBLE:
- layoutID = R.layout.tag_double_layout;
- break;
- case STRING:
- layoutID = R.layout.tag_string_layout;
- break;
- default:
- layoutID = R.layout.tag_default_layout;
- break;
- }
+ //NBT tag type spinner
+ final Spinner spinner = new Spinner(activity);
+ ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(
+ activity, android.R.layout.simple_spinner_item, NBTConstants.NBTType.editorOptions_asString);
- final View tagView = inflater.inflate(layoutID, null, false);
- TextView tagName = (TextView) tagView.findViewById(R.id.tag_name);
- tagName.setText(tag.getName());
+ spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(spinnerArrayAdapter);
- switch (layoutID){
- case R.layout.tag_boolean_layout: {
- final CheckBox checkBox = (CheckBox) tagView.findViewById(R.id.checkBox);
- final ByteTag byteTag = (ByteTag) tag;
- checkBox.setChecked(byteTag.getValue() == (byte) 1);
- checkBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
- /**
- * Called when the checked state of a compound button has changed.
- *
- * @param buttonView The compound button view whose state has changed.
- * @param isChecked The new checked state of buttonView.
- */
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- byteTag.setValue(isChecked ? (byte) 1 : (byte) 0);
- nbt.setModified();
- }
- });
- break;
- }
- case R.layout.tag_byte_layout: {
- final EditText editText = (EditText) tagView.findViewById(R.id.byteField);
- final ByteTag byteTag = (ByteTag) tag;
- //parse the byte as an unsigned byte
- editText.setText(""+(((int) byteTag.getValue()) & 0xFF));
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
+ //wrap editText and spinner in linear layout
+ LinearLayout linearLayout = new LinearLayout(activity);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+ linearLayout.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ Gravity.BOTTOM));
+ linearLayout.addView(nameText);
+ linearLayout.addView(spinner);
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
+ //wrap layout in alert
+ AlertDialog.Builder alert = new AlertDialog.Builder(activity);
+ alert.setTitle(R.string.create_nbt_tag);
+ alert.setView(linearLayout);
- @Override
- public void afterTextChanged(Editable s) {
- String sValue = s.toString();
- try {
- int value = Integer.parseInt(sValue);
- if(value < 0 || value > 0xff)
- throw new NumberFormatException("No unsigned byte.");
- byteTag.setValue((byte) value);
- nbt.setModified();
- } catch (NumberFormatException e){
- editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
- }
- }
- });
- break;
- }
- case R.layout.tag_short_layout: {
- final EditText editText = (EditText) tagView.findViewById(R.id.shortField);
- final ShortTag shortTag = (ShortTag) tag;
- editText.setText(shortTag.getValue().toString());
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
+ //alert can create a new tag
+ alert.setPositiveButton(R.string.create, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
+ //new tag name
+ Editable newNameEditable = nameText.getText();
+ String newName = (newNameEditable == null || newNameEditable.toString().equals("")) ? null : newNameEditable.toString();
- @Override
- public void afterTextChanged(Editable s) {
- String sValue = s.toString();
- try {
- shortTag.setValue(Short.valueOf(sValue));
- nbt.setModified();
- } catch (NumberFormatException e){
- editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
- }
- }
- });
- break;
- }
- case R.layout.tag_int_layout: {
- final EditText editText = (EditText) tagView.findViewById(R.id.intField);
- final IntTag intTag = (IntTag) tag;
- editText.setText(intTag.getValue().toString());
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
+ //new tag type
+ int spinnerIndex = spinner.getSelectedItemPosition();
+ NBTConstants.NBTType nbtType = NBTConstants.NBTType.editorOptions_asType[spinnerIndex];
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
+ //create new tag
+ Tag newTag = NBTConstants.NBTType.newInstance(newName, nbtType);
- @Override
- public void afterTextChanged(Editable s) {
- String sValue = s.toString();
- try {
- intTag.setValue(Integer.valueOf(sValue));
- nbt.setModified();
- } catch (NumberFormatException e){
- editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
- }
- }
- });
- break;
- }
- case R.layout.tag_long_layout: {
- final EditText editText = (EditText) tagView.findViewById(R.id.longField);
- final LongTag longTag = (LongTag) tag;
- editText.setText(longTag.getValue().toString());
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
+ //add tag to nbt
+ nbt.addRootTag(newTag);
+ tree.addNode(node, new TreeNode(new ChainTag(null, newTag)).setViewHolder(new NBTNodeHolder(nbt, activity)));
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
-
- @Override
- public void afterTextChanged(Editable s) {
- String sValue = s.toString();
- try {
- longTag.setValue(Long.valueOf(sValue));
- nbt.setModified();
- } catch (NumberFormatException e){
- editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
- }
- }
- });
- break;
- }
- case R.layout.tag_float_layout: {
- final EditText editText = (EditText) tagView.findViewById(R.id.floatField);
- final FloatTag floatTag = (FloatTag) tag;
- editText.setText(floatTag.getValue().toString());
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
-
- @Override
- public void afterTextChanged(Editable s) {
- String sValue = s.toString();
- try {
- floatTag.setValue(Float.valueOf(sValue));
- nbt.setModified();
- } catch (NumberFormatException e){
- editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
- }
- }
- });
- break;
- }
- case R.layout.tag_double_layout: {
- final EditText editText = (EditText) tagView.findViewById(R.id.doubleField);
- final DoubleTag doubleTag = (DoubleTag) tag;
- editText.setText(doubleTag.getValue().toString());
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
-
- @Override
- public void afterTextChanged(Editable s) {
- String sValue = s.toString();
- try {
- doubleTag.setValue(Double.valueOf(sValue));
- nbt.setModified();
- } catch (NumberFormatException e){
- editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
- }
- }
- });
- break;
- }
- case R.layout.tag_string_layout: {
- final EditText editText = (EditText) tagView.findViewById(R.id.stringField);
- final StringTag stringTag = (StringTag) tag;
- editText.setText(stringTag.getValue());
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
-
- @Override
- public void afterTextChanged(Editable s) {
- nbt.setModified();
- stringTag.setValue(s.toString());
- }
- });
- break;
- }
- default:
- break;
-
- }
-
- return tagView;
- }
-
- @Override
- public void toggle(boolean active) {
- }
-
- @Override
- public int getContainerStyle() {
- return R.style.TreeNodeStyleCustom;
- }
-
- }
-
- public enum NBTEditOption {
-
- CANCEL(R.string.edit_cancel),
- COPY(R.string.edit_copy),
- PASTE_OVERWRITE(R.string.edit_paste_overwrite),
- PASTE_SUBTAG(R.string.edit_paste_sub_tag),
- DELETE(R.string.edit_delete),
- RENAME(R.string.edit_rename),
- ADD_SUBTAG(R.string.edit_add_sub_tag);
-
- public final int stringId;
-
- NBTEditOption(int stringId){
- this.stringId = stringId;
- }
- }
-
- public String[] getNBTEditOptions(){
- NBTEditOption[] values = NBTEditOption.values();
- int len = values.length;
- String[] options = new String[len];
- for(int i = 0; i < len; i++){
- options[i] = getString(values[i].stringId);
- }
- return options;
- }
-
- public enum RootNBTEditOption {
-
- ADD_NBT_TAG(R.string.edit_root_add),
- PASTE_SUB_TAG(R.string.edit_root_paste_sub_tag),
- REMOVE_ALL_TAGS(R.string.edit_root_remove_all);
-
- public final int stringId;
-
- RootNBTEditOption(int stringId){
- this.stringId = stringId;
- }
-
- }
-
- public String[] getRootNBTEditOptions(){
- RootNBTEditOption[] values = RootNBTEditOption.values();
- int len = values.length;
- String[] options = new String[len];
- for(int i = 0; i < len; i++){
- options[i] = getString(values[i].stringId);
- }
- return options;
- }
-
-
- public static Tag clipboard;
-
-
- //returns true if there is a tag in content with a name equals to key.
- boolean checkKeyCollision(String key, List content){
- if(content == null || content.isEmpty()) return false;
- if(key == null) key = "";
- String tagName;
- for(Tag tag : content) {
- tagName = tag.getName();
- if(tagName == null) tagName = "";
- if(tagName.equals(key)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
-
- if(nbt == null){
- new Exception("No NBT data provided").printStackTrace();
- getActivity().finish();
-
- return null;
- }
-
- final View rootView = inflater.inflate(R.layout.nbt_editor, container, false);
-
- // edit functionality
- // ================================
-
- TreeNode superRoot = TreeNode.root();
- TreeNode root = new TreeNode(nbt);
- superRoot.addChild(root);
- root.setExpanded(true);
- root.setSelectable(false);
-
-
- final Activity activity = getActivity();
-
- root.setViewHolder(new RootNodeHolder(activity));
-
- for(Tag tag : nbt.getTags()){
- root.addChild(new TreeNode(new ChainTag(null, tag)).setViewHolder(new NBTNodeHolder(nbt, activity)));
- }
-
- FrameLayout frame = (FrameLayout) rootView.findViewById(R.id.nbt_editor_frame);
-
- final AndroidTreeView tree = new AndroidTreeView(getActivity(), superRoot);
- tree.setUse2dScroll(true);
-
- final View treeView = tree.getView();
-
- treeView.setScrollContainer(true);
-
- tree.setDefaultNodeLongClickListener(new TreeNode.TreeNodeLongClickListener() {
- @Override
- public boolean onLongClick(final TreeNode node, final Object value) {
-
- Log.d("NBT editor: Long click!");
-
-
- //root tag has nbt as value
- if(value instanceof EditableNBT){
-
- if(!nbt.enableRootModifications){
- Toast.makeText(activity, R.string.cannot_edit_root_NBT_tag, Toast.LENGTH_LONG).show();
- return true;
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
-
- builder.setTitle(R.string.root_NBT_options)
- .setItems(getRootNBTEditOptions(), new DialogInterface.OnClickListener() {
-
- private void showMsg(int msg){
- Toast.makeText(activity, msg, Toast.LENGTH_LONG).show();
- }
-
- public void onClick(DialogInterface dialog, int which) {
- try {
- RootNBTEditOption option = RootNBTEditOption.values()[which];
-
- switch (option){
- case ADD_NBT_TAG:{
- final EditText nameText = new EditText(activity);
- nameText.setHint(R.string.hint_tag_name_here);
-
- //NBT tag type spinner
- final Spinner spinner = new Spinner(activity);
- ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(
- activity, android.R.layout.simple_spinner_item, NBTConstants.NBTType.editorOptions_asString);
-
- spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- spinner.setAdapter(spinnerArrayAdapter);
-
- //wrap editText and spinner in linear layout
- LinearLayout linearLayout = new LinearLayout(activity);
- linearLayout.setOrientation(LinearLayout.VERTICAL);
- linearLayout.setLayoutParams(
- new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT,
- Gravity.BOTTOM));
- linearLayout.addView(nameText);
- linearLayout.addView(spinner);
-
- //wrap layout in alert
- AlertDialog.Builder alert = new AlertDialog.Builder(activity);
- alert.setTitle(R.string.create_nbt_tag);
- alert.setView(linearLayout);
-
- //alert can create a new tag
- alert.setPositiveButton(R.string.create, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
-
- //new tag name
- Editable newNameEditable = nameText.getText();
- String newName = (newNameEditable == null || newNameEditable.toString().equals("")) ? null : newNameEditable.toString();
-
- //new tag type
- int spinnerIndex = spinner.getSelectedItemPosition();
- NBTConstants.NBTType nbtType = NBTConstants.NBTType.editorOptions_asType[spinnerIndex];
-
- //create new tag
- Tag newTag = NBTConstants.NBTType.newInstance(newName, nbtType);
-
- //add tag to nbt
- nbt.addRootTag(newTag);
- tree.addNode(node, new TreeNode(new ChainTag(null, newTag)).setViewHolder(new NBTNodeHolder(nbt, activity)));
-
- nbt.setModified();
+ nbt.setModified();
}
});
@@ -592,7 +194,7 @@ public void onClick(DialogInterface dialog, int whichButton) {
//or alert is cancelled
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
- Log.d("NBT tag creation cancelled");
+ Log.d(this, "NBT tag creation cancelled");
}
});
@@ -601,7 +203,7 @@ public void onClick(DialogInterface dialog, int whichButton) {
return;
}
case PASTE_SUB_TAG: {
- if(clipboard == null){
+ if (clipboard == null) {
showMsg(R.string.clipboard_is_empty);
return;
}
@@ -613,7 +215,7 @@ public void onClick(DialogInterface dialog, int whichButton) {
return;
}
- case REMOVE_ALL_TAGS:{
+ case REMOVE_ALL_TAGS: {
//wrap layout in alert
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
@@ -626,10 +228,10 @@ public void onClick(DialogInterface dialog, int whichButton) {
List children = new ArrayList<>(node.getChildren());
//new tag name
- for(TreeNode child : children){
+ for (TreeNode child : children) {
tree.removeNode(child);
Object childValue = child.getValue();
- if(childValue != null && childValue instanceof ChainTag)
+ if (childValue instanceof ChainTag)
nbt.removeRootTag(((ChainTag) childValue).self);
}
nbt.setModified();
@@ -640,7 +242,7 @@ public void onClick(DialogInterface dialog, int whichButton) {
//or alert is cancelled
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
- Log.d("NBT tag creation cancelled");
+ Log.d(this, "NBT tag creation cancelled");
}
});
@@ -649,10 +251,10 @@ public void onClick(DialogInterface dialog, int whichButton) {
break;
}
default: {
- Log.d("User clicked unknown NBTEditOption! "+option.name());
+ Log.d(this, "User clicked unknown NBTEditOption! " + option.name());
}
}
- } catch (Exception e){
+ } catch (Exception e) {
showMsg(R.string.failed_to_do_NBT_change);
}
}
@@ -662,7 +264,7 @@ public void onClick(DialogInterface dialog, int whichButton) {
return true;
- } else if(value instanceof ChainTag){
+ } else if (value instanceof ChainTag) {
//other tags have a chain-tag as value
@@ -671,23 +273,23 @@ public void onClick(DialogInterface dialog, int whichButton) {
builder.setTitle(R.string.nbt_tag_options)
.setItems(getNBTEditOptions(), new DialogInterface.OnClickListener() {
- private void showMsg(int msg){
+ private void showMsg(int msg) {
Toast.makeText(activity, msg, Toast.LENGTH_LONG).show();
}
@SuppressWarnings("unchecked")
public void onClick(DialogInterface dialog, int which) {
- try{
+ try {
NBTEditOption editOption = NBTEditOption.values()[which];
final Tag parent = ((ChainTag) value).parent;
final Tag self = ((ChainTag) value).self;
- if(self == null) return;//WTF?
+ if (self == null) return;//WTF?
- if(editOption == null) return;//WTF?
+ if (editOption == null) return;//WTF?
- switch (editOption){
+ switch (editOption) {
case CANCEL: {
return;
}
@@ -696,12 +298,12 @@ public void onClick(DialogInterface dialog, int which) {
return;
}
case PASTE_OVERWRITE: {
- if(clipboard == null){
+ if (clipboard == null) {
showMsg(R.string.clipboard_is_empty);
return;
}
- if(parent == null){
+ if (parent == null) {
//it is one of the children of the root node
nbt.removeRootTag(self);
Tag copy = clipboard.getDeepCopy();
@@ -720,7 +322,7 @@ public void onClick(DialogInterface dialog, int which) {
}
case COMPOUND: {
content = ((CompoundTag) parent).getValue();
- if(checkKeyCollision(clipboard.getName(), content)){
+ if (checkKeyCollision(clipboard.getName(), content)) {
showMsg(R.string.clipboard_key_exists_in_compound);
return;
}
@@ -731,7 +333,7 @@ public void onClick(DialogInterface dialog, int which) {
return;
}
}
- if(content != null){
+ if (content != null) {
content.remove(self);
Tag copy = clipboard.getDeepCopy();
content.add(copy);
@@ -739,13 +341,13 @@ public void onClick(DialogInterface dialog, int which) {
tree.removeNode(node);
nbt.setModified();
return;
- }
- else showMsg(R.string.error_cannot_overwrite_in_empty_parent);
+ } else
+ showMsg(R.string.error_cannot_overwrite_in_empty_parent);
return;
}
}
case PASTE_SUBTAG: {
- if(clipboard == null){
+ if (clipboard == null) {
showMsg(R.string.clipboard_is_empty);
return;
}
@@ -758,7 +360,7 @@ public void onClick(DialogInterface dialog, int which) {
}
case COMPOUND: {
content = ((CompoundTag) self).getValue();
- if(checkKeyCollision(clipboard.getName(), content)){
+ if (checkKeyCollision(clipboard.getName(), content)) {
showMsg(R.string.clipboard_key_exists_in_compound);
return;
}
@@ -769,7 +371,7 @@ public void onClick(DialogInterface dialog, int which) {
return;
}
}
- if(content == null){
+ if (content == null) {
content = new ArrayList<>();
self.setValue(content);
}
@@ -782,7 +384,7 @@ public void onClick(DialogInterface dialog, int which) {
return;
}
case DELETE: {
- if(parent == null){
+ if (parent == null) {
//it is one of the children of the root node
tree.removeNode(node);
nbt.removeRootTag(self);
@@ -791,26 +393,26 @@ public void onClick(DialogInterface dialog, int which) {
}
ArrayList content;
- switch (parent.getType()){
- case LIST:{
+ switch (parent.getType()) {
+ case LIST: {
content = ((ListTag) parent).getValue();
break;
}
- case COMPOUND:{
+ case COMPOUND: {
content = ((CompoundTag) parent).getValue();
break;
}
- default:{
+ default: {
showMsg(R.string.error_cannot_overwrite_tag_unknow_parent_type);
return;
}
}
- if(content != null){
+ if (content != null) {
content.remove(self);
tree.removeNode(node);
nbt.setModified();
- }
- else showMsg(R.string.error_cannot_remove_from_empty_list);
+ } else
+ showMsg(R.string.error_cannot_remove_from_empty_list);
return;
}
case RENAME: {
@@ -827,9 +429,8 @@ public void onClick(DialogInterface dialog, int whichButton) {
Editable newNameEditable = edittext.getText();
String newName = (newNameEditable == null || newNameEditable.toString().equals("")) ? null : newNameEditable.toString();
- if(parent != null
- && parent instanceof CompoundTag
- && checkKeyCollision(newName, ((CompoundTag) parent).getValue())){
+ if (parent instanceof CompoundTag
+ && checkKeyCollision(newName, ((CompoundTag) parent).getValue())) {
showMsg(R.string.error_parent_already_contains_child_with_same_key);
return;
}
@@ -846,7 +447,7 @@ && checkKeyCollision(newName, ((CompoundTag) parent).getValue())){
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
- Log.d("Cancelled rename NBT tag");
+ Log.d(this, "Cancelled rename NBT tag");
}
});
@@ -855,9 +456,9 @@ public void onClick(DialogInterface dialog, int whichButton) {
return;
}
case ADD_SUBTAG: {
- switch (self.getType()){
+ switch (self.getType()) {
case LIST:
- case COMPOUND:{
+ case COMPOUND: {
final EditText nameText = new EditText(activity);
nameText.setHint(R.string.hint_tag_name_here);
@@ -899,21 +500,19 @@ public void onClick(DialogInterface dialog, int whichButton) {
ArrayList content;
- if(self instanceof CompoundTag) {
+ if (self instanceof CompoundTag) {
content = ((CompoundTag) self).getValue();
- if(checkKeyCollision(newName, content)){
+ if (checkKeyCollision(newName, content)) {
showMsg(R.string.error_key_already_exists_in_compound);
return;
}
- }
- else if(self instanceof ListTag){
+ } else if (self instanceof ListTag) {
content = ((ListTag) self).getValue();
- }
- else return;//WTF?
+ } else return;//WTF?
- if(content == null){
+ if (content == null) {
content = new ArrayList<>();
self.setValue(content);
}
@@ -922,10 +521,12 @@ else if(self instanceof ListTag){
Tag newTag = NBTConstants.NBTType.newInstance(newName, nbtType);
//add tag to nbt
- content.add(newTag);
- tree.addNode(node, new TreeNode(new ChainTag(self, newTag)).setViewHolder(new NBTNodeHolder(nbt, activity)));
+ if (newTag != null) {
+ content.add(newTag);
+ tree.addNode(node, new TreeNode(new ChainTag(self, newTag)).setViewHolder(new NBTNodeHolder(nbt, activity)));
- nbt.setModified();
+ nbt.setModified();
+ }
}
});
@@ -933,7 +534,7 @@ else if(self instanceof ListTag){
//or alert is cancelled
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
- Log.d("NBT tag creation cancelled");
+ Log.d(this, "NBT tag creation cancelled");
}
});
@@ -942,14 +543,14 @@ public void onClick(DialogInterface dialog, int whichButton) {
return;
}
- default:{
+ default: {
showMsg(R.string.sub_tags_only_add_compound_list);
return;
}
}
}
default: {
- Log.d("User clicked unknown NBTEditOption! "+editOption.name());
+ Log.d(this, "User clicked unknown NBTEditOption! " + editOption.name());
}
}
@@ -969,16 +570,15 @@ public void onClick(DialogInterface dialog, int whichButton) {
frame.addView(treeView, 0);
-
// save functionality
// ================================
- FloatingActionButton fabSaveNBT = (FloatingActionButton) rootView.findViewById(R.id.fab_save_nbt);
+ FloatingActionButton fabSaveNBT = rootView.findViewById(R.id.fab_save_nbt);
assert fabSaveNBT != null;
fabSaveNBT.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
- if(!nbt.isModified()){
+ if (!nbt.isModified()) {
Snackbar.make(view, R.string.no_data_changed_nothing_to_save, Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
} else {
@@ -988,22 +588,23 @@ public void onClick(final View view) {
.setIcon(R.drawable.ic_action_save_b)
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- Snackbar.make(view, "Saving NBT data...", Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- if(nbt.save()){
- //nbt is not "modified" anymore, in respect to the new saved data
- nbt.modified = false;
-
- Snackbar.make(view, "Saved NBT data!", Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- ((WorldActivityInterface) activity).logFirebaseEvent(WorldActivity.CustomFirebaseEvent.NBT_EDITOR_SAVE);
- } else {
- Snackbar.make(view, "Error: failed to save the NBT data.", Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
- }})
- .setNegativeButton(android.R.string.no, null).show();
+ public void onClick(DialogInterface dialog, int whichButton) {
+ Snackbar.make(view, "Saving NBT data...", Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ if (nbt.save()) {
+ //nbt is not "modified" anymore, in respect to the new saved data
+ nbt.modified = false;
+
+ Snackbar.make(view, "Saved NBT data!", Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ Log.logFirebaseEvent(activity, Log.CustomFirebaseEvent.NBT_EDITOR_SAVE);
+ } else {
+ Snackbar.make(view, "Error: failed to save the NBT data.", Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ }
+ }
+ })
+ .setNegativeButton(android.R.string.no, null).show();
}
}
@@ -1012,6 +613,425 @@ public void onClick(DialogInterface dialog, int whichButton) {
return rootView;
}
+ public static class RootNodeHolder extends TreeNode.BaseNodeViewHolder {
+
+
+ public RootNodeHolder(Context context) {
+ super(context);
+ }
+
+ @Override
+ public View createNodeView(TreeNode node, EditableNBT value) {
+
+ final LayoutInflater inflater = LayoutInflater.from(context);
+
+ final View tagView = inflater.inflate(R.layout.tag_root_layout, null, false);
+ TextView tagName = tagView.findViewById(R.id.tag_name);
+ tagName.setText(value.getRootTitle());
+
+ return tagView;
+ }
+
+ @Override
+ public void toggle(boolean active) {
+ }
+
+ @Override
+ public int getContainerStyle() {
+ return R.style.TreeNodeStyleCustomRoot;
+ }
+ }
+
+
+ public static class NBTNodeHolder extends TreeNode.BaseNodeViewHolder {
+
+ private final EditableNBT nbt;
+
+ public NBTNodeHolder(EditableNBT nbt, Context context) {
+ super(context);
+ this.nbt = nbt;
+ }
+
+ @SuppressLint("SetTextI18n")
+ @Override
+ public View createNodeView(TreeNode node, final ChainTag chain) {
+
+ if (chain == null) return null;
+ Tag tag = chain.self;
+ if (tag == null) return null;
+
+ final LayoutInflater inflater = LayoutInflater.from(context);
+
+ int layoutID;
+
+ switch (tag.getType()) {
+ case COMPOUND: {
+ List value = ((CompoundTag) tag).getValue();
+ if (value != null) {
+ for (Tag child : value) {
+ node.addChild(new TreeNode(new ChainTag(tag, child)).setViewHolder(new NBTNodeHolder(nbt, context)));
+ }
+ }
+
+ layoutID = R.layout.tag_compound_layout;
+ break;
+ }
+ case LIST: {
+ List value = ((ListTag) tag).getValue();
+
+ if (value != null) {
+ for (Tag child : value) {
+ node.addChild(new TreeNode(new ChainTag(tag, child)).setViewHolder(new NBTNodeHolder(nbt, context)));
+ }
+ }
+
+ layoutID = R.layout.tag_list_layout;
+ break;
+ }
+ case BYTE_ARRAY: {
+ layoutID = R.layout.tag_default_layout;
+ break;
+ }
+ case BYTE: {
+ String name = tag.getName();
+ if (name == null) name = "";
+ else name = name.toLowerCase();
+
+ //TODO differentiate boolean tags from byte tags better
+ if (name.startsWith("has") || name.startsWith("is")) {
+ layoutID = R.layout.tag_boolean_layout;
+ } else {
+ layoutID = R.layout.tag_byte_layout;
+ }
+ break;
+ }
+ case SHORT:
+ layoutID = R.layout.tag_short_layout;
+ break;
+ case INT:
+ layoutID = R.layout.tag_int_layout;
+ break;
+ case LONG:
+ layoutID = R.layout.tag_long_layout;
+ break;
+ case FLOAT:
+ layoutID = R.layout.tag_float_layout;
+ break;
+ case DOUBLE:
+ layoutID = R.layout.tag_double_layout;
+ break;
+ case STRING:
+ layoutID = R.layout.tag_string_layout;
+ break;
+ default:
+ layoutID = R.layout.tag_default_layout;
+ break;
+ }
+
+ final View tagView = inflater.inflate(layoutID, null, false);
+ TextView tagName = tagView.findViewById(R.id.tag_name);
+ tagName.setText(tag.getName());
+
+ switch (layoutID) {
+ case R.layout.tag_boolean_layout: {
+ final CheckBox checkBox = tagView.findViewById(R.id.checkBox);
+ final ByteTag byteTag = (ByteTag) tag;
+ checkBox.setChecked(byteTag.getValue() == (byte) 1);
+ checkBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
+ /**
+ * Called when the checked state of a compound button has changed.
+ *
+ * @param buttonView The compound button view whose state has changed.
+ * @param isChecked The new checked state of buttonView.
+ */
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ byteTag.setValue(isChecked ? (byte) 1 : (byte) 0);
+ nbt.setModified();
+ }
+ });
+ break;
+ }
+ case R.layout.tag_byte_layout: {
+ final EditText editText = tagView.findViewById(R.id.byteField);
+ final ByteTag byteTag = (ByteTag) tag;
+ //parse the byte as an unsigned byte
+ editText.setText("" + (((int) byteTag.getValue()) & 0xFF));
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String sValue = s.toString();
+ try {
+ int value = Integer.parseInt(sValue);
+ if (value < 0 || value > 0xff)
+ throw new NumberFormatException("No unsigned byte.");
+ byteTag.setValue((byte) value);
+ nbt.setModified();
+ } catch (NumberFormatException e) {
+ editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
+ }
+ }
+ });
+ break;
+ }
+ case R.layout.tag_short_layout: {
+ final EditText editText = tagView.findViewById(R.id.shortField);
+ final ShortTag shortTag = (ShortTag) tag;
+ editText.setText(shortTag.getValue().toString());
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String sValue = s.toString();
+ try {
+ shortTag.setValue(Short.valueOf(sValue));
+ nbt.setModified();
+ } catch (NumberFormatException e) {
+ editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
+ }
+ }
+ });
+ break;
+ }
+ case R.layout.tag_int_layout: {
+ final EditText editText = tagView.findViewById(R.id.intField);
+ final IntTag intTag = (IntTag) tag;
+ editText.setText(intTag.getValue().toString());
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String sValue = s.toString();
+ try {
+ intTag.setValue(Integer.valueOf(sValue));
+ nbt.setModified();
+ } catch (NumberFormatException e) {
+ editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
+ }
+ }
+ });
+ break;
+ }
+ case R.layout.tag_long_layout: {
+ final EditText editText = tagView.findViewById(R.id.longField);
+ final LongTag longTag = (LongTag) tag;
+ editText.setText(longTag.getValue().toString());
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String sValue = s.toString();
+ try {
+ longTag.setValue(Long.valueOf(sValue));
+ nbt.setModified();
+ } catch (NumberFormatException e) {
+ editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
+ }
+ }
+ });
+ break;
+ }
+ case R.layout.tag_float_layout: {
+ final EditText editText = tagView.findViewById(R.id.floatField);
+ final FloatTag floatTag = (FloatTag) tag;
+ editText.setText(floatTag.getValue().toString());
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String sValue = s.toString();
+ try {
+ floatTag.setValue(Float.valueOf(sValue));
+ nbt.setModified();
+ } catch (NumberFormatException e) {
+ editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
+ }
+ }
+ });
+ break;
+ }
+ case R.layout.tag_double_layout: {
+ final EditText editText = tagView.findViewById(R.id.doubleField);
+ final DoubleTag doubleTag = (DoubleTag) tag;
+ editText.setText(doubleTag.getValue().toString());
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String sValue = s.toString();
+ try {
+ doubleTag.setValue(Double.valueOf(sValue));
+ nbt.setModified();
+ } catch (NumberFormatException e) {
+ editText.setError(String.format(context.getString(R.string.x_is_invalid), sValue));
+ }
+ }
+ });
+ break;
+ }
+ case R.layout.tag_string_layout: {
+ final EditText editText = tagView.findViewById(R.id.stringField);
+ final StringTag stringTag = (StringTag) tag;
+ editText.setText(stringTag.getValue());
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ nbt.setModified();
+ stringTag.setValue(s.toString());
+ }
+ });
+ break;
+ }
+ default:
+ break;
+
+ }
+
+ return tagView;
+ }
+
+ @Override
+ public void toggle(boolean active) {
+ }
+
+ @Override
+ public int getContainerStyle() {
+ return R.style.TreeNodeStyleCustom;
+ }
+
+ }
+
+ public enum NBTEditOption {
+
+ CANCEL(R.string.edit_cancel),
+ COPY(R.string.edit_copy),
+ PASTE_OVERWRITE(R.string.edit_paste_overwrite),
+ PASTE_SUBTAG(R.string.edit_paste_sub_tag),
+ DELETE(R.string.edit_delete),
+ RENAME(R.string.edit_rename),
+ ADD_SUBTAG(R.string.edit_add_sub_tag);
+
+ public final int stringId;
+
+ NBTEditOption(int stringId) {
+ this.stringId = stringId;
+ }
+ }
+
+ public String[] getNBTEditOptions() {
+ NBTEditOption[] values = NBTEditOption.values();
+ int len = values.length;
+ String[] options = new String[len];
+ for (int i = 0; i < len; i++) {
+ options[i] = getString(values[i].stringId);
+ }
+ return options;
+ }
+
+ public enum RootNBTEditOption {
+
+ ADD_NBT_TAG(R.string.edit_root_add),
+ PASTE_SUB_TAG(R.string.edit_root_paste_sub_tag),
+ REMOVE_ALL_TAGS(R.string.edit_root_remove_all);
+
+ public final int stringId;
+
+ RootNBTEditOption(int stringId) {
+ this.stringId = stringId;
+ }
+
+ }
+
+ public String[] getRootNBTEditOptions() {
+ RootNBTEditOption[] values = RootNBTEditOption.values();
+ int len = values.length;
+ String[] options = new String[len];
+ for (int i = 0; i < len; i++) {
+ options[i] = getString(values[i].stringId);
+ }
+ return options;
+ }
+
+
+ public static Tag clipboard;
+
+
+ //returns true if there is a tag in content with a name equals to key.
+ boolean checkKeyCollision(String key, List content) {
+ if (content == null || content.isEmpty()) return false;
+ if (key == null) key = "";
+ String tagName;
+ for (Tag tag : content) {
+ tagName = tag.getName();
+ if (tagName == null) tagName = "";
+ if (tagName.equals(key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static class ChainTag {
+
+ public Tag parent, self;
+
+ public ChainTag(Tag parent, @NonNull Tag self) {
+ this.parent = parent;
+ this.self = self;
+ }
+ }
+
@Override
public void onStart() {
@@ -1022,7 +1042,7 @@ public void onStart() {
Bundle bundle = new Bundle();
bundle.putString("title", nbt.getRootTitle());
- ((WorldActivityInterface) getActivity()).logFirebaseEvent(WorldActivity.CustomFirebaseEvent.NBT_EDITOR_OPEN, bundle);
+ Log.logFirebaseEvent(getActivity(), Log.CustomFirebaseEvent.NBT_EDITOR_OPEN, bundle);
}
@Override
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/InventoryHolder.java b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/InventoryHolder.java
new file mode 100644
index 00000000..3b0332ba
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/InventoryHolder.java
@@ -0,0 +1,159 @@
+package com.mithrilmania.blocktopograph.nbt;
+
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.nbt.tags.ByteTag;
+import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
+import com.mithrilmania.blocktopograph.nbt.tags.ListTag;
+import com.mithrilmania.blocktopograph.nbt.tags.ShortTag;
+import com.mithrilmania.blocktopograph.nbt.tags.StringTag;
+import com.mithrilmania.blocktopograph.nbt.tags.Tag;
+
+public final class InventoryHolder {
+
+ private ListTag mContent;
+
+ public static InventoryHolder readFromPlayer(CompoundTag player) {
+ Tag tag = player.getChildTagByKey(Keys.INVENTORY);
+ if (!(tag instanceof ListTag)) return null;
+ InventoryHolder ret = new InventoryHolder();
+ ret.mContent = (ListTag) tag;
+ return ret;
+ }
+
+ private InventoryHolder() {
+ }
+
+ public ListTag getContent() {
+ return mContent;
+ }
+
+ @Nullable
+ public Item getItemOfSlot(short slot) {
+ for (Tag tag : mContent.getValue()) {
+ if (!(tag instanceof CompoundTag)) continue;
+ CompoundTag itemTag = (CompoundTag) tag;
+ Tag sub = itemTag.getChildTagByKey(Keys.INV_SLOT);
+// if(sub instanceof ShortTag) {
+// Short sh = ((ShortTag) sub).getValue();
+// if (sh == null) continue;
+// if (slot == sh) return new Item(itemTag);
+// }
+// else
+ if (sub instanceof ByteTag) {
+ Byte by = ((ByteTag) sub).getValue();
+ if (by == null) continue;
+ if (slot == by) return new Item(itemTag);
+ }
+ }
+ return null;
+ }
+
+ public static class Item {
+
+ private final CompoundTag mContent;
+
+ private Item(CompoundTag content) {
+ mContent = content;
+ }
+
+// private Item() {
+// mContent = new CompoundTag(Keys.INVENTORY, new ArrayList<>(5));
+// //mContent.
+// }
+
+ @Nullable
+ public String getName() {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_NAME);
+ if (!(tag instanceof StringTag)) return null;
+ StringTag curr = (StringTag) tag;
+ return curr.getValue();
+ }
+
+ public boolean setName(String name) {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_NAME);
+ if (!(tag instanceof StringTag)) return false;
+ StringTag curr = (StringTag) tag;
+ curr.setValue(name);
+ return true;
+ }
+
+ @Nullable
+ public Short getId() {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_ID);
+ if (!(tag instanceof ShortTag)) return null;
+ ShortTag curr = (ShortTag) tag;
+ return curr.getValue();
+ }
+
+ public boolean setId(short id) {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_ID);
+ if (!(tag instanceof ShortTag)) return false;
+ ShortTag curr = (ShortTag) tag;
+ curr.setValue(id);
+ return true;
+ }
+
+ @Nullable
+ public Byte getCount() {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_COUNT);
+ if (!(tag instanceof ByteTag)) return null;
+ ByteTag curr = (ByteTag) tag;
+ return curr.getValue();
+ }
+
+ public boolean setCount(byte count) {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_COUNT);
+ if (!(tag instanceof ByteTag)) return false;
+ ByteTag curr = (ByteTag) tag;
+ curr.setValue(count);
+ return true;
+ }
+
+ @Nullable
+ public Short getDamage() {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_DAMAGE);
+ if (!(tag instanceof ShortTag)) return null;
+ ShortTag curr = (ShortTag) tag;
+ return curr.getValue();
+ }
+
+ public boolean setDamage(short damage) {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_DAMAGE);
+ if (!(tag instanceof ShortTag)) return false;
+ ShortTag curr = (ShortTag) tag;
+ curr.setValue(damage);
+ return true;
+ }
+
+// @Nullable
+// public Short getSlot() {
+// Tag tag = mContent.getChildTagByKey(Keys.INV_SLOT);
+// if (!(tag instanceof ShortTag)) return null;
+// ShortTag curr = (ShortTag) tag;
+// return curr.getValue();
+// }
+//
+// public boolean setSlot(short slot) {
+// Tag tag = mContent.getChildTagByKey(Keys.INV_SLOT);
+// if (!(tag instanceof ShortTag)) return false;
+// ShortTag curr = (ShortTag) tag;
+// curr.setValue(slot);
+// return true;
+// }
+
+ @Nullable
+ public ItemTag getItemTag() {
+ Tag tag = mContent.getChildTagByKey(Keys.INV_TAG);
+ if (tag == null) {
+ ItemTag itemTag = new ItemTag();
+ mContent.getValue().add(itemTag.getContent());
+ return itemTag;
+ }
+ if (!(tag instanceof CompoundTag)) return null;
+ CompoundTag curr = (CompoundTag) tag;
+ return new ItemTag(curr);
+ }
+
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/ItemTag.java b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/ItemTag.java
new file mode 100644
index 00000000..d26bf23d
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/ItemTag.java
@@ -0,0 +1,179 @@
+package com.mithrilmania.blocktopograph.nbt;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mithrilmania.blocktopograph.nbt.tags.CompoundTag;
+import com.mithrilmania.blocktopograph.nbt.tags.IntTag;
+import com.mithrilmania.blocktopograph.nbt.tags.ListTag;
+import com.mithrilmania.blocktopograph.nbt.tags.LongTag;
+import com.mithrilmania.blocktopograph.nbt.tags.StringTag;
+import com.mithrilmania.blocktopograph.nbt.tags.Tag;
+
+import java.util.ArrayList;
+
+public class ItemTag {
+
+ private final CompoundTag mContent;
+ private ListTag mPages;
+
+ ItemTag() {
+ ArrayList tags = new ArrayList<>();
+ mContent = new CompoundTag(Keys.INV_TAG, tags);
+ }
+
+ ItemTag(CompoundTag content) {
+ mContent = content;
+ }
+
+ @Nullable
+ private String getStringEntry(@NonNull String key) {
+ Tag tag = mContent.getChildTagByKey(key);
+ if (!(tag instanceof StringTag)) return null;
+ return ((StringTag) tag).getValue();
+ }
+
+ private static boolean setStringEntry(@NonNull CompoundTag parent, @NonNull String key, @NonNull String val) {
+ Tag tag = parent.getChildTagByKey(key);
+ if (tag == null) {
+ StringTag curr = new StringTag(key, val);
+ parent.getValue().add(curr);
+ return true;
+ }
+ if (!(tag instanceof StringTag)) return false;
+ ((StringTag) tag).setValue(val);
+ return true;
+ }
+
+ @Nullable
+ public Long getId() {
+ Tag tag = mContent.getChildTagByKey(Keys.I_BOOK_ID);
+ if (!(tag instanceof LongTag)) return null;
+ return ((LongTag) tag).getValue();
+ }
+
+ public boolean setId(long id) {
+ Tag tag = mContent.getChildTagByKey(Keys.I_BOOK_ID);
+ if (tag == null) {
+ LongTag curr = new LongTag(Keys.I_BOOK_ID, id);
+ mContent.getValue().add(curr);
+ return true;
+ }
+ if (!(tag instanceof LongTag)) return false;
+ ((LongTag) tag).setValue(id);
+ return true;
+ }
+
+ @Nullable
+ public Integer getGeneration() {
+ Tag tag = mContent.getChildTagByKey(Keys.I_BOOK_GENERATION);
+ if (!(tag instanceof IntTag)) return null;
+ return ((IntTag) tag).getValue();
+ }
+
+ public boolean setGeneration(int generation) {
+ Tag tag = mContent.getChildTagByKey(Keys.I_BOOK_GENERATION);
+ if (tag == null) {
+ LongTag curr = new LongTag(Keys.I_BOOK_GENERATION, generation);
+ mContent.getValue().add(curr);
+ return true;
+ }
+ if (!(tag instanceof IntTag)) return false;
+ ((IntTag) tag).setValue(generation);
+ return true;
+ }
+
+ @Nullable
+ public String getAuthor() {
+ return getStringEntry(Keys.I_BOOK_AUTHOR);
+ }
+
+ public boolean setAuthor(String author) {
+ return setStringEntry(mContent, Keys.I_BOOK_AUTHOR, author);
+ }
+
+ @Nullable
+ public String getTitle() {
+ return getStringEntry(Keys.I_BOOK_TITLE);
+ }
+
+ public boolean setTitle(String title) {
+ return setStringEntry(mContent, Keys.I_BOOK_TITLE, title);
+ }
+
+ @Nullable
+ public String getXuid() {
+ return getStringEntry(Keys.I_BOOK_XUID);
+ }
+
+ public boolean setXuid(String xuid) {
+ return setStringEntry(mContent, Keys.I_BOOK_XUID, xuid);
+ }
+
+ /**
+ * Try to load pages of a book item.
+ *
+ * @return false if the same tag of wrong type exists, otherwise true.
+ */
+ private boolean preparePages() {
+ if (mPages != null) return true;
+ Tag tag = mContent.getChildTagByKey(Keys.I_BOOK_PAGES);
+ if (tag instanceof ListTag) {
+ mPages = (ListTag) tag;
+ return true;
+ } else return tag == null;
+ }
+
+ public int getPagesCount() {
+ preparePages();
+ if (mPages == null) return -1;
+ return mPages.getValue().size();
+ }
+
+ private static void addPage(ArrayList list) {
+ ArrayList subs = new ArrayList<>(4);
+ CompoundTag tag = new CompoundTag("", subs);
+ setStringEntry(tag, Keys.I_BOOK_PAGES_PHOTONAME, "");
+ setStringEntry(tag, Keys.I_BOOK_PAGES_TEXT, "");
+ list.add(tag);
+ }
+
+ @Nullable
+ public CompoundTag getPage(int index) {
+ if (!preparePages()) return null;
+ if (mPages == null) {
+ mPages = new ListTag(Keys.I_BOOK_PAGES, new ArrayList<>(Math.max(index, 4)));
+ mContent.getValue().add(mPages);
+ }
+ ArrayList pages = mPages.getValue();
+ for (int i = pages.size(); i <= index; i++) addPage(pages);
+ Tag tag = pages.get(index);
+ if (tag instanceof CompoundTag) return (CompoundTag) tag;
+ return null;
+ }
+
+ public static boolean setPageText(CompoundTag page, String text) {
+ return setStringEntry(page, Keys.I_BOOK_PAGES_TEXT, text);
+ }
+
+ public static boolean setPageUrl(@NonNull CompoundTag page, @NonNull String url) {
+ Tag tag = page.getChildTagByKey(Keys.I_BOOK_PAGES_CLICK);
+ CompoundTag event;
+ if (tag == null) {
+ event = new CompoundTag(Keys.I_BOOK_PAGES_CLICK, new ArrayList<>(2));
+ page.getValue().add(event);
+ } else {
+ if (!(tag instanceof CompoundTag)) return false;
+ event = (CompoundTag) tag;
+ }
+ if (!setStringEntry(event, Keys.I_BOOK_PAGES_CLICK_ACTION, Keys.I_BOOK_PAGES_CLICK_ACTION_URL))
+ return false;
+ if (!setStringEntry(event, Keys.I_BOOK_PAGES_CLICK_VALUE, url)) return false;
+ return true;
+ }
+
+ @NonNull
+ public CompoundTag getContent() {
+ return mContent;
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/Keys.java b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/Keys.java
new file mode 100644
index 00000000..377ca823
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/Keys.java
@@ -0,0 +1,30 @@
+package com.mithrilmania.blocktopograph.nbt;
+
+public final class Keys {
+
+ public static final String LEVEL_NAME = "LevelName";
+ public static final String FLAT_WORLD_LAYERS = "FlatWorldLayers";
+ public static final String LAST_PLAYED = "LastPlayed";
+ public static final String INVENTORY = "Inventory";
+ public static final String INV_NAME = "Name";
+ public static final String INV_ID = "id";
+ public static final String INV_DAMAGE = "Damage";
+ public static final String INV_COUNT = "Count";
+ public static final String INV_SLOT = "Slot";
+ public static final String INV_TAG = "tag";
+ public static final String I_BOOK_AUTHOR = "author";
+ public static final String I_BOOK_GENERATION = "generation";
+ public static final String I_BOOK_ID = "id";
+ public static final String I_BOOK_PAGES = "pages";
+ public static final String I_BOOK_TITLE = "title";
+ public static final String I_BOOK_XUID = "xuid";
+ public static final String I_BOOK_PAGES_PHOTONAME = "photoname";
+ public static final String I_BOOK_PAGES_TEXT = "text";
+ public static final String I_BOOK_PAGES_CLICK = "clickEvent";
+ public static final String I_BOOK_PAGES_CLICK_ACTION = "action";
+ public static final String I_BOOK_PAGES_CLICK_ACTION_URL = "open_url";
+ public static final String I_BOOK_PAGES_CLICK_VALUE = "value";
+
+ //public static final String ="";
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/convert/LevelDataConverter.java b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/convert/LevelDataConverter.java
index cb5c6331..7d3d8171 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/convert/LevelDataConverter.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/convert/LevelDataConverter.java
@@ -16,6 +16,15 @@ public final class LevelDataConverter {
public static final byte[] header = {0x04, 0x00, 0x00, 0x00};
+ public static CompoundTag read(InputStream inputStream) throws IOException {
+ skip(inputStream, 8);
+ // Skip the length? Yeah I know it's redundant but...
+ NBTInputStream in = new NBTInputStream(inputStream);
+ CompoundTag levelTag = (CompoundTag) in.readTag();
+ in.close();
+ return levelTag;
+ }
+
public static CompoundTag read(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
BufferedInputStream is = new BufferedInputStream(fis);
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/convert/NBTInputStream.java b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/convert/NBTInputStream.java
index 937b9894..b4eeb62d 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/convert/NBTInputStream.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/convert/NBTInputStream.java
@@ -14,6 +14,8 @@ public final class NBTInputStream
private final DataInputStream is;
private final boolean littleEndian;
+ private int readCount;
+
public NBTInputStream(InputStream is)
throws IOException {
this(is, false, true);
@@ -28,6 +30,7 @@ public NBTInputStream(InputStream is, boolean compressed, boolean littleEndian)
throws IOException {
this.littleEndian = littleEndian;
this.is = new DataInputStream(compressed ? new GZIPInputStream(is) : is);
+ this.readCount = 0;
}
public ArrayList readTopLevelTags() {
@@ -52,12 +55,15 @@ public Tag readTag()
private Tag readTag(int depth)
throws IOException {
int type = this.is.readByte() & 0xFF;
+ readCount++;
String name;
if (type != NBTConstants.NBTType.END.id) {
short shLen = this.is.readShort();
+ readCount += 2;
int nameLength = (this.littleEndian ? Short.reverseBytes(shLen) : shLen) & 0xFFFF;
byte[] nameBytes = new byte[nameLength];
this.is.readFully(nameBytes);
+ readCount += nameLength;
name = new String(nameBytes, NBTConstants.CHARSET.name());
} else {
name = "";
@@ -70,7 +76,7 @@ private Tag readTagPayload(int type, String name, int depth)
NBTConstants.NBTType nbtType = NBTConstants.NBTType.typesByID.get(type);
- if(nbtType == null) throw new IOException("Invalid tag type: " + type + ".");
+ if (nbtType == null) throw new IOException("Invalid tag type: " + type + ".");
int length;
byte[] bytes;
@@ -81,35 +87,47 @@ private Tag readTagPayload(int type, String name, int depth)
}
return new EndTag();
case BYTE:
+ readCount++;
return new ByteTag(name, this.is.readByte());
case SHORT:
+ readCount += 2;
return new ShortTag(name, this.littleEndian ? Short.reverseBytes(this.is.readShort()) : this.is.readShort());
case INT:
+ readCount += 4;
return new IntTag(name, this.littleEndian ? Integer.reverseBytes(this.is.readInt()) : this.is.readInt());
case LONG:
+ readCount += 8;
return new LongTag(name, this.littleEndian ? Long.reverseBytes(this.is.readLong()) : this.is.readLong());
case FLOAT:
+ readCount += 4;
return new FloatTag(name, this.littleEndian ? Float.intBitsToFloat(Integer.reverseBytes(this.is.readInt())) : this.is.readFloat());
case DOUBLE:
+ readCount += 8;
return new DoubleTag(name, this.littleEndian ? Double.longBitsToDouble(Long.reverseBytes(this.is.readLong())) : this.is.readDouble());
case BYTE_ARRAY: {
length = this.littleEndian ? Integer.reverseBytes(this.is.readInt()) : this.is.readInt();
+ readCount += 4;
bytes = new byte[length];
this.is.readFully(bytes);
+ readCount += length;
return new ByteArrayTag(name, bytes);
}
case STRING: {
length = this.littleEndian ? Short.reverseBytes(this.is.readShort()) : this.is.readShort();
+ readCount+=2;
bytes = new byte[length];
this.is.readFully(bytes);
+ readCount += length;
return new StringTag(name, new String(bytes, NBTConstants.CHARSET.name()));
}
case LIST: {
int childType = this.is.readByte();
+ readCount++;
length = this.littleEndian ? Integer.reverseBytes(this.is.readInt()) : this.is.readInt();
+ readCount += 4;
NBTConstants.NBTType childNbtType = NBTConstants.NBTType.typesByID.get(childType);
- if(childNbtType.id == 0) return new ListTag(name, new ArrayList());
+ if (childNbtType.id == 0) return new ListTag(name, new ArrayList());
Class extends Tag> clazz = childNbtType.tagClazz;
ArrayList tagList = new ArrayList<>();
for (int i = 0; i < length; i++) {
@@ -134,26 +152,32 @@ private Tag readTagPayload(int type, String name, int depth)
}
case INT_ARRAY: {
length = this.littleEndian ? Integer.reverseBytes(this.is.readInt()) : this.is.readInt();
+ readCount += 4;
int[] ints = new int[length];
- if(this.littleEndian) for (int i = 0; i < length; i++) {
+ readCount += length << 2;
+ if (this.littleEndian) for (int i = 0; i < length; i++) {
ints[i] = Integer.reverseBytes(this.is.readInt());
- } else for (int i = 0; i < length; i++) {
+ }
+ else for (int i = 0; i < length; i++) {
ints[i] = this.is.readInt();
}
return new IntArrayTag(name, ints);
}
case SHORT_ARRAY: {
length = this.littleEndian ? Integer.reverseBytes(this.is.readInt()) : this.is.readInt();
+ readCount += 4;
short[] shorts = new short[length];
- if(this.littleEndian) for (int i = 0; i < length; i++) {
+ readCount += length << 1;
+ if (this.littleEndian) for (int i = 0; i < length; i++) {
shorts[i] = Short.reverseBytes(this.is.readShort());
- } else for (int i = 0; i < length; i++) {
+ }
+ else for (int i = 0; i < length; i++) {
shorts[i] = this.is.readShort();
}
return new ShortArrayTag(name, shorts);
}
default: {
- throw new IOException("Unhandled NBT type!!! type: "+type);
+ throw new IOException("Unhandled NBT type!!! type: " + type);
}
}
}
@@ -163,6 +187,14 @@ public void close()
this.is.close();
}
+ public int getReadCount() {
+ return readCount;
+ }
+
+ public void resetReadCount() {
+ readCount = 0;
+ }
+
public boolean isLittleEndian() {
return this.littleEndian;
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/tags/Tag.java b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/tags/Tag.java
index f06823d2..664c7314 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/nbt/tags/Tag.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/nbt/tags/Tag.java
@@ -1,8 +1,13 @@
package com.mithrilmania.blocktopograph.nbt.tags;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.mithrilmania.blocktopograph.nbt.convert.NBTConstants;
import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
public abstract class Tag implements Serializable {
@@ -29,26 +34,72 @@ public void setName(String name) {
this.name = name;
}
- public T getValue(){
- return value;
+ private static boolean areCompoundTagsEqual(@NonNull List tags1, @NonNull List tags2) {
+ if (tags1.size() != tags2.size()) return false;
+ boolean[] notCompared = new boolean[tags2.size()];
+ for (Tag tagof1 : tags1) {
+ boolean found = false;
+ for (int i = 0; i < tags2.size(); i++)
+ if (!notCompared[i] && tagof1.equals(tags2.get(i))) {
+ found = true;
+ notCompared[i] = true;
+ break;
+ }
+ if (!found) return false;
+ }
+ return true;
}
- public void setValue(T value){
- this.value = value;
+ public T getValue() {
+ return value;
}
public abstract NBTConstants.NBTType getType();
public abstract Tag getDeepCopy();
- public String toString(){
+ public void setValue(T value) {
+ this.value = value;
+ }
+
+ public String toString() {
String name = getName();
String type = getType().name();
T value = getValue();
- return (type == null ? "?" : ("TAG_"+type))
- + (name == null ? "(?)" : ("("+name+")"))
- + (value == null ? ":?" : (": "+value.toString()));
+ return (type == null ? "?" : ("TAG_" + type))
+ + (name == null ? "(?)" : ("(" + name + ")"))
+ + (value == null ? ":?" : (": " + value.toString()));
}
-
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof Tag)) return false;
+ Tag another = (Tag) obj;
+ if (!name.equals(another.name)) return false;
+ if (getType() != another.getType()) return false;
+ switch (getType()) {
+ case COMPOUND:
+ return areCompoundTagsEqual(((CompoundTag) this).value,
+ ((CompoundTag) another).value);
+ case INT:
+ case BYTE:
+ case LONG:
+ case FLOAT:
+ case SHORT:
+ case DOUBLE:
+ case STRING:
+ case LIST:
+ return value.equals(another.value);
+ case END:
+ return true;
+ case INT_ARRAY:
+ return Arrays.equals(((IntArrayTag) this).value, ((IntArrayTag) another).value);
+ case BYTE_ARRAY:
+ return Arrays.equals(((ByteArrayTag) this).value, ((ByteArrayTag) another).value);
+ case SHORT_ARRAY:
+ return Arrays.equals(((ShortArrayTag) this).value, ((ShortArrayTag) another).value);
+ default:
+ throw new RuntimeException("wtf????");
+ }
+ }
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/test/MainTestActivity.java b/app/src/main/java/com/mithrilmania/blocktopograph/test/MainTestActivity.java
new file mode 100644
index 00000000..51f0acc2
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/test/MainTestActivity.java
@@ -0,0 +1,522 @@
+package com.mithrilmania.blocktopograph.test;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.View;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.databinding.DataBindingUtil;
+
+import com.google.android.material.snackbar.Snackbar;
+import com.litl.leveldb.DB;
+import com.litl.leveldb.Iterator;
+import com.mithrilmania.blocktopograph.Log;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.World;
+import com.mithrilmania.blocktopograph.WorldData;
+import com.mithrilmania.blocktopograph.block.OldBlock;
+import com.mithrilmania.blocktopograph.block.OldBlockRegistry;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+import com.mithrilmania.blocktopograph.chunk.Chunk;
+import com.mithrilmania.blocktopograph.chunk.ChunkTag;
+import com.mithrilmania.blocktopograph.chunk.Version;
+import com.mithrilmania.blocktopograph.databinding.ActivityMainTestBinding;
+import com.mithrilmania.blocktopograph.map.Dimension;
+import com.mithrilmania.blocktopograph.nbt.convert.NBTConstants;
+import com.mithrilmania.blocktopograph.util.ConvertUtil;
+import com.mithrilmania.blocktopograph.util.IoUtil;
+import com.mithrilmania.blocktopograph.util.McUtil;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+public final class MainTestActivity extends AppCompatActivity {
+
+ private ActivityMainTestBinding mBinding;
+ private World mWorld;
+
+ /**
+ * https://stackoverflow.com/a/25659067/9399618
+ *
+ * @param data 123
+ * @param pattern 123
+ * @return 123
+ */
+ public static boolean arrContains(byte[] data, byte[] pattern, int[] failure) {
+
+ int j = 0;
+
+ for (byte datum : data) {
+ while (j > 0 && pattern[j] != datum) {
+ j = failure[j - 1];
+ }
+ if (pattern[j] == datum) {
+ j++;
+ }
+ if (j == pattern.length) {
+ return true;//i - pattern.length + 1;
+ }
+ }
+ return false;//-1;
+ }
+
+ /**
+ * Computes the failure function using a boot-strapping process,
+ * where the pattern is matched against itself.
+ */
+ private static int[] computeFailure(byte[] pattern) {
+ int[] failure = new int[pattern.length];
+
+ int j = 0;
+ for (int i = 1; i < pattern.length; i++) {
+ while (j > 0 && pattern[j] != pattern[i]) {
+ j = failure[j - 1];
+ }
+ if (pattern[j] == pattern[i]) {
+ j++;
+ }
+ failure[i] = j;
+ }
+
+ return failure;
+ }
+
+ private byte[] getDbKey() {
+ byte[] key;
+ String text = mBinding.searchBar.getText().toString();
+ switch (mBinding.rgForm.getCheckedRadioButtonId()) {
+ case R.id.rb_form_text:
+ key = text.getBytes(NBTConstants.CHARSET);
+ break;
+ case R.id.rb_form_hex: {
+ key = ConvertUtil.hexStringToBytes(text);
+ break;
+ }
+ default:
+ key = null;
+ }
+ return key;
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main_test);
+
+ if (savedInstanceState != null) {
+ Serializable ser = savedInstanceState.getSerializable(World.ARG_WORLD_SERIALIZED);
+ if (ser instanceof World) mWorld = (World) ser;
+ }
+ if (mWorld == null) {
+ Intent intent = getIntent();
+ if (intent != null) {
+ Serializable ser = intent.getSerializableExtra(World.ARG_WORLD_SERIALIZED);
+ if (ser instanceof World) mWorld = (World) ser;
+ }
+ if (mWorld == null) {
+ finish();
+ return;
+ }
+ }
+
+ try {
+ mWorld.getWorldData().load();
+ } catch (WorldData.WorldDataLoadException e) {
+ Log.d(this, e);
+ finish();
+ return;
+ }
+ File file = Environment.getExternalStorageDirectory();
+ file = McUtil.getBtgTestDir(file);
+ mBinding.fabMenuFixLdb.setOnClickListener(this::onClickFixLdb);
+ //mBinding.fabMenuGenerateAllBlocks.setOnClickListener(this::onClickGenAllBlocks);
+ //mBinding.fabMenuAnalyzeAllBlocks.setOnClickListener(this::onClickAnaAllBlocks);
+ //mBinding.fabMenuGenCodeAllBlocksState.setOnClickListener(this::onClickGenCodeAllBlocksState);
+ mBinding.setPath(file.getPath());
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putSerializable(World.ARG_WORLD_SERIALIZED, mWorld);
+ }
+
+ private byte[] readItem() {
+ return readItem(getDbKey());
+ }
+
+ private byte[] readItem(byte[] key) {
+ byte[] ret;
+ WorldData wdata = mWorld.getWorldData();
+ try {
+ wdata.openDB();
+ ret = wdata.db.get(key);
+ wdata.closeDB();
+ } catch (Exception e) {
+ Log.d(this, e);
+ ret = null;
+ }
+ try {
+ wdata.closeDB();
+ } catch (WorldData.WorldDBException e) {
+ Log.d(this, e);
+ }
+ return ret;
+ }
+
+ public void onClickSearch(View view) {
+ byte[] pattern = getDbKey();
+ WorldData wdata = mWorld.getWorldData();
+ try {
+ wdata.openDB();
+ List keys = new ArrayList<>();
+ List keyTypeText = new ArrayList<>();
+ List originalKeys = new ArrayList<>();
+ Iterator iter = wdata.db.iterator();
+ int[] failure = computeFailure(pattern);
+ for (iter.seekToFirst(); iter.isValid(); iter.next()) {
+ byte[] key = iter.getKey();
+ if (arrContains(key, pattern, failure)) {
+ String str = null;
+ boolean isText = false;
+ if (mBinding.rgForm.getCheckedRadioButtonId() == R.id.rb_form_text) {
+ try {
+ str = new String(key, NBTConstants.CHARSET);
+ isText = true;
+ } catch (Exception ignored) {
+ }
+ }
+ if (str == null)
+ str = ConvertUtil.bytesToHexStr(key);
+ keys.add(str);
+ originalKeys.add(key);
+ keyTypeText.add(isText);
+ }
+ }
+ iter.close();
+ wdata.closeDB();
+ String[] keyArr = new String[keys.size()];
+ keys.toArray(keyArr);
+ AlertDialog dia = new AlertDialog.Builder(this).setItems(keyArr, (di, i) -> {
+ mBinding.searchBar.setText(keyArr[i]);
+ if (keyTypeText.get(i))
+ mBinding.rbFormText.setChecked(true);
+ else
+ mBinding.rbFormHex.setChecked(true);
+ showData(readItem(originalKeys.get(i)));
+ }).create();
+ dia.show();
+ } catch (Exception e) {
+ Log.d(this, e);
+ printStackTraceInDialog(e);
+ }
+ try {
+ wdata.closeDB();
+ } catch (WorldData.WorldDBException e) {
+ Log.d(this, e);
+ }
+ }
+
+ private void showData(byte[] data) {
+ new AlertDialog.Builder(this)
+ .setMessage(ConvertUtil.bytesToHexStr(data))
+ .show();
+ }
+
+ private void printStackTraceInDialog(Exception e) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ e.printStackTrace(pw);
+ pw.close();
+ new AlertDialog.Builder(this).setMessage(sw.toString()).create().show();
+ }
+
+ public void onClickOpen(View view) {
+ showData(readItem());
+ }
+
+ public void onClickExport(View view) {
+ IoUtil.Errno errno;
+ flow:
+ {
+
+ byte[] item = readItem();
+
+ if (!IoUtil.hasWritePermission(this)) {
+ errno = IoUtil.Errno.PERMISSION_DENIED;
+ break flow;
+ }
+
+ File dir = new File(mBinding.textPath.getText().toString());
+
+ errno = IoUtil.makeSureDirIsDir(dir);
+ if (IoUtil.Errno.OK != errno) {
+ break flow;
+ }
+
+ String name = ConvertUtil.getLegalFileName(mBinding.searchBar.getText().toString());
+ File out = IoUtil.getFileWithFirstAvailableName(dir, name, ".dat", "(", ")");
+ if (out == null) {
+ errno = IoUtil.Errno.UNKNOWN;
+ break flow;
+ }
+
+ if (!IoUtil.writeBinaryFile(out, item)) errno = IoUtil.Errno.UNKNOWN;
+ }
+ if (errno == IoUtil.Errno.OK) Snackbar.make(getWindow().getDecorView(),
+ R.string.general_done, Snackbar.LENGTH_SHORT).show();
+ else Toast.makeText(this, errno.toString(), Toast.LENGTH_SHORT).show();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void onClickFixLdb(View view) {
+ new ForegroundTask(this).execute(() -> {
+ WorldData worldData = mWorld.getWorldData();
+ try {
+ worldData.closeDB();
+ } catch (WorldData.WorldDBException e) {
+ Log.d(this, e);
+ }
+ return DB.fixLdb(worldData.db.getPath().getAbsolutePath());
+ });
+ }
+
+ /*@SuppressWarnings("unchecked")
+ private void onClickGenAllBlocks(View view) {
+ new ForegroundTask(this).execute(() -> {
+ WorldData worldData = mWorld.getWorldData();
+ OldBlockRegistry registry = worldData.mOldBlockRegistry;
+ int pos = 0;
+ for (KnownBlockRepr oldBlock : KnownBlockRepr.values()) {
+ if (pos % 16 == 0)
+ worldData.removeChunkData(pos / 16, 0, ChunkTag.TERRAIN, Dimension.OVERWORLD, (byte) 0, true);
+ String pot = "------------X------------" +
+ "------XXX--XOX--XXX------" +
+ "XXXXXX---XX-?-XX---XXXXXX";
+ Chunk chunk = worldData.getChunk(pos / 16, 0, Dimension.OVERWORLD, true, Version.V1_2_PLUS);
+ int i = 0;
+ for (int y = 0; y < 3; y++)
+ for (int x = 0; x < 5; x++)
+ for (int z = 0; z < 5; z++) {
+ OldBlock blk;
+ switch (pot.charAt(i)) {
+ case 'X':
+ blk = registry.createBlock(KnownBlockRepr.B_42_0_IRON_BLOCK);
+ break;
+ case 'O':
+ blk = registry.createBlock(KnownBlockRepr.B_3_0_DIRT);
+ break;
+ case '?':
+ blk = registry.createBlock(oldBlock);
+ break;
+ default:
+ blk = null;
+ }
+ if (blk != null)
+ chunk.setBlock(pos % 16 + 1 + x, 12 + y, 3 + z, 0, blk);
+ i++;
+ }
+ for (int j = 0; j < 8; j++) {
+ chunk.setBlock(pos % 16 + j, 17, 9, 0,
+ registry.createBlock(KnownBlockRepr.B_12_0_SAND_DEFAULT));
+ chunk.setBlock(pos % 16 + j, 0, 9, 0,
+ registry.createBlock(KnownBlockRepr.B_42_0_IRON_BLOCK));
+ }
+ pos += 8;
+ }
+ worldData.resetCache();
+ worldData.closeDB();
+ return "meow";
+ });
+ }*/
+
+ @SuppressWarnings("unchecked")
+ private void onClickAnaAllBlocks(View view) {
+// new ForegroundTask(this).execute(() -> {
+// WorldData worldData = mWorld.getWorldData();
+// int pos = 0, valids = 0, invalids = 0, offs = 0;
+// StringBuilder sb = new StringBuilder();
+// CompoundTag[] tags = null;
+// for (KnownBlockRepr oldBlock : KnownBlockRepr.values()) {
+// Chunk chunk = worldData.getChunk(pos / 16, 0, Dimension.OVERWORLD, true, Version.V1_2_PLUS);
+// int ind;
+// if (pos % 16 == 0) {
+// tags = ((BedrockChunk) chunk).tempGetSubChunk().tempGetPalettes(3, 14, 5);
+// ind = 0;
+// } else ind = 1;
+// String name = ((StringTag) tags[ind].getChildTagByKey("name")).getValue().substring(10);
+// sb.append(oldBlock.identifier).append(":").append(oldBlock.subId).append("->").append(name).append(":");
+// CompoundTag states = ((CompoundTag) tags[ind].getChildTagByKey("states"));
+// sb.append("[");
+// ArrayList value = states.getValue();
+// for (int i = 0; i < value.size(); i++) {
+// Tag tag = value.get(i);
+// sb.append(tag.getType()).append(":").append(tag.getIdentifier()).append("=");
+// switch (tag.getType()) {
+// case INT:
+// sb.append(((IntTag) tag).getValue());
+// break;
+// case BYTE:
+// sb.append(((ByteTag) tag).getValue());
+// break;
+// case SHORT:
+// sb.append(((ShortTag) tag).getValue());
+// break;
+// case STRING:
+// sb.append(((StringTag) tag).getValue());
+// break;
+// }
+// if (i != value.size() - 1) sb.append(",");
+// }
+// sb.append("]\n");
+// pos += 8;
+// offs++;
+// }
+// worldData.resetCache();
+// worldData.closeDB();
+// IoUtil.writeTextFile(new File(McUtil.getBtgTestDir(Environment.getExternalStorageDirectory()), "blks.txt"), sb.toString());
+// return "meow";
+// });
+ }
+
+ @SuppressWarnings("unchecked")
+ private void onClickGenCodeAllBlocksState(View view) {
+// new ForegroundTask(this).execute(() -> {
+// WorldData worldData = mWorld.getWorldData();
+// int pos = 0, valids = 0, invalids = 0;
+// StringBuilder sb = new StringBuilder();
+// CompoundTag[] tags = null;
+// for (KnownBlockRepr oldBlock : KnownBlockRepr.values()) {
+// Chunk chunk = worldData.getChunk(pos / 16, 0, Dimension.OVERWORLD, true, Version.V1_2_PLUS);
+// int ind;
+// if (pos % 16 == 0) {
+// tags = ((BedrockChunk) chunk).tempGetSubChunk().tempGetPalettes(3, 14, 5);
+// ind = 0;
+// } else ind = 1;
+// String name = ((StringTag) tags[ind].getChildTagByKey("name")).getValue().substring(10);
+// if (name.equals(oldBlock.identifier)) {
+// CompoundTag states = ((CompoundTag) tags[ind].getChildTagByKey("states"));
+// sb.append("new BlockStateBuilder()");
+// Object[] value = states.getValue().toArray();
+// Arrays.sort(value, (o1, o2) -> {
+// String n1 = ((Tag) o1).getIdentifier();
+// String n2 = ((Tag) o2).getIdentifier();
+// if (n1.contains("color"))
+// return -1;
+// if (n2.contains("color"))
+// return 1;
+// if (n1.contains("type"))
+// return -1;
+// if (n2.contains("type"))
+// return 1;
+// if (n1.contains("direction"))
+// return -1;
+// if (n2.contains("direction"))
+// return 1;
+// return 0;
+// });
+// for (int i = 0; i < value.length; i++) {
+// Tag tag = (Tag) value[i];
+// String tagName = tag.getIdentifier();
+// switch (tag.getType()) {
+// case INT:
+// sb.append(".addInt(\"").append(tagName).append("\", ");
+// sb.append(((IntTag) tag).getValue());
+// break;
+// case BYTE:
+// sb.append(".addByte(\"").append(tagName).append("\", (byte)");
+// sb.append(((ByteTag) tag).getValue());
+// break;
+// case SHORT:
+// sb.append(".addShort(\"").append(tagName).append("\", (short)");
+// sb.append(((ShortTag) tag).getValue());
+// break;
+// case STRING:
+// sb.append(".addProperty(\"").append(tagName).append("\", \"");
+// sb.append(((StringTag) tag).getValue()).append("\"");
+// break;
+// }
+// sb.append(")");
+// }
+// sb.append(".build()\n");
+// valids++;
+// } else {
+// sb.append("new CompoundTag(\"\", new ArrayList())\n");
+// invalids++;
+// }
+// pos += 8;
+// }
+// worldData.resetCache();
+// worldData.closeDB();
+// IoUtil.writeTextFile(new File(McUtil.getBtgTestDir(Environment.getExternalStorageDirectory()), "blkStateCodes.txt"), sb.toString());
+// return "meow valids: " + valids + ", invalids: " + invalids;
+// });
+ }
+
+ private static class ForegroundTask extends AsyncTask, Void, Void> {
+
+ private WeakReference mContext;
+ private WeakReference mDialog;
+ private StringBuilder result;
+
+ ForegroundTask(Context context) {
+ mContext = new WeakReference<>(context);
+ result = new StringBuilder();
+ }
+
+ @Override
+ protected void onPreExecute() {
+ Context context = mContext.get();
+ if (context == null) return;
+ AlertDialog dialog = UiUtil.buildProgressWaitDialog(context, R.string.general_please_wait, null);
+ dialog.show();
+ mDialog = new WeakReference<>(dialog);
+ }
+
+ @SafeVarargs
+ @Override
+ protected final Void doInBackground(Callable... params) {
+ for (Callable callable : params) {
+ try {
+ result.append(callable.call());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ Dialog dialog;
+ if (mDialog != null && (dialog = mDialog.get()) != null) {
+ try {
+ dialog.dismiss();
+ } catch (Exception e) {
+ Log.e(this, e);
+ }
+ }
+ Context context = mContext.get();
+ if (context != null) {
+ new AlertDialog.Builder(context)
+ .setMessage(result.toString())
+ .create().show();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/test/VisualizationActivity.java b/app/src/main/java/com/mithrilmania/blocktopograph/test/VisualizationActivity.java
new file mode 100644
index 00000000..ddb88561
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/test/VisualizationActivity.java
@@ -0,0 +1,6 @@
+package com.mithrilmania.blocktopograph.test;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+public class VisualizationActivity extends AppCompatActivity {
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/Color.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/Color.java
deleted file mode 100644
index 8b3b701c..00000000
--- a/app/src/main/java/com/mithrilmania/blocktopograph/util/Color.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.mithrilmania.blocktopograph.util;
-
-
-public class Color {
-
- private static final int BIT_MASK = 0xff;
-
- public final int alpha;
-
- public final int red;
- public final int green;
- public final int blue;
-
- /**
- * Creates a new Color object from a red, green, and blue
- *
- * @param red integer from 0-255
- * @param green integer from 0-255
- * @param blue integer from 0-255
- * @return a new Color object for the red, green, blue
- * @throws IllegalArgumentException if any value is strictly >255 or <0
- */
- public static Color fromRGB(int red, int green, int blue) throws IllegalArgumentException {
- return new Color(0xff, red, green, blue);
- }
-
- /**
- * Creates a new color object from an integer that contains the red, green, and blue bytes in the lowest order 24 bits.
- *
- * @param rgb the integer storing the red, green, and blue values
- * @return a new color object for specified values
- * @throws IllegalArgumentException if any data is in the highest order 8 bits
- */
- public static Color fromRGB(int rgb) throws IllegalArgumentException {
- return fromRGB(rgb >> 16 & BIT_MASK, rgb >> 8 & BIT_MASK, rgb & BIT_MASK);
- }
-
- public static Color fromARGB(int alpha, int red, int green, int blue) throws IllegalArgumentException {
- return new Color(alpha, red, green, blue);
- }
-
- public static Color fromARGB(int argb) throws IllegalArgumentException {
- return fromARGB(argb >> 24 & BIT_MASK, argb >> 16 & BIT_MASK, argb >> 8 & BIT_MASK, argb & BIT_MASK);
- }
-
- public Color(int alpha, int red, int green, int blue) {
- this.alpha = alpha;
- this.red = red;
- this.green = green;
- this.blue = blue;
- }
-
- /**
- *
- * @return An integer representation of this color, as 0xRRGGBB
- */
- public int asRGB() {
- return red << 16 | green << 8 | blue;
- }
-
- public int asARGB() {
- return alpha << 24 | red << 16 | green << 8 | blue;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Color)) {
- return false;
- }
- final Color that = (Color) o;
- return this.alpha == that.alpha && this.red == that.red && this.green == that.green && this.blue == that.blue;
- }
-
- @Override
- public int hashCode() {
- return asRGB() ^ Color.class.hashCode();
- }
-
-
- @Override
- public String toString() {
- return "Color:[argb0x"
- + Integer.toHexString(alpha).toUpperCase()
- + Integer.toHexString(red).toUpperCase()
- + Integer.toHexString(green).toUpperCase()
- + Integer.toHexString(blue).toUpperCase()
- + "]";
- }
-}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/ColorUtil.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/ColorUtil.java
new file mode 100644
index 00000000..26ad2919
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/ColorUtil.java
@@ -0,0 +1,25 @@
+package com.mithrilmania.blocktopograph.util;
+
+import android.graphics.Color;
+
+public class ColorUtil {
+ public static int truncateArgb(int a, int r, int g, int b) {
+ return Color.argb(ensureColorRange(a),
+ ensureColorRange(r), ensureColorRange(g), ensureColorRange(b)
+ );
+ }
+
+ public static int truncateRgb(int r, int g, int b) {
+ return Color.rgb(
+ ensureColorRange(r), ensureColorRange(g), ensureColorRange(b)
+ );
+ }
+
+ private static int ensureRange(int val, int min, int max) {
+ return Math.min(Math.max(val, min), max);
+ }
+
+ private static int ensureColorRange(int val) {
+ return ensureRange(val, 0, 255);
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/ColorWrapper.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/ColorWrapper.java
new file mode 100644
index 00000000..cd7ba664
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/ColorWrapper.java
@@ -0,0 +1,91 @@
+package com.mithrilmania.blocktopograph.util;
+
+
+import androidx.annotation.NonNull;
+
+public class ColorWrapper {
+
+ private static final int BIT_MASK = 0xff;
+
+ public final int alpha;
+
+ public final int red;
+ public final int green;
+ public final int blue;
+
+ public ColorWrapper(int alpha, int red, int green, int blue) {
+ this.alpha = alpha;
+ this.red = red;
+ this.green = green;
+ this.blue = blue;
+ }
+
+ /**
+ * Creates a new ColorWrapper object from a red, green, and blue
+ *
+ * @param red integer from 0-255
+ * @param green integer from 0-255
+ * @param blue integer from 0-255
+ * @return a new ColorWrapper object for the red, green, blue
+ * @throws IllegalArgumentException if any value is strictly >255 or <0
+ */
+ public static ColorWrapper fromRGB(int red, int green, int blue) throws IllegalArgumentException {
+ return new ColorWrapper(0xff, red, green, blue);
+ }
+
+ /**
+ * Creates a new color object from an integer that contains the red, green, and blue bytes in the lowest order 24 bits.
+ *
+ * @param rgb the integer storing the red, green, and blue values
+ * @return a new color object for specified values
+ * @throws IllegalArgumentException if any data is in the highest order 8 bits
+ */
+ public static ColorWrapper fromRGB(int rgb) throws IllegalArgumentException {
+ return fromRGB(rgb >> 16 & BIT_MASK, rgb >> 8 & BIT_MASK, rgb & BIT_MASK);
+ }
+
+ public static ColorWrapper fromARGB(int alpha, int red, int green, int blue) throws IllegalArgumentException {
+ return new ColorWrapper(alpha, red, green, blue);
+ }
+
+ public static ColorWrapper fromARGB(int argb) throws IllegalArgumentException {
+ return fromARGB(argb >> 24 & BIT_MASK, argb >> 16 & BIT_MASK, argb >> 8 & BIT_MASK, argb & BIT_MASK);
+ }
+
+ /**
+ * @return An integer representation of this color, as 0xRRGGBB
+ */
+ public int asRGB() {
+ return red << 16 | green << 8 | blue;
+ }
+
+ public int asARGB() {
+ return alpha << 24 | red << 16 | green << 8 | blue;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ColorWrapper)) {
+ return false;
+ }
+ final ColorWrapper that = (ColorWrapper) o;
+ return this.alpha == that.alpha && this.red == that.red && this.green == that.green && this.blue == that.blue;
+ }
+
+ @Override
+ public int hashCode() {
+ return asRGB() ^ ColorWrapper.class.hashCode();
+ }
+
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "ColorWrapper:[argb0x"
+ + Integer.toHexString(alpha)
+ + Integer.toHexString(red)
+ + Integer.toHexString(green)
+ + Integer.toHexString(blue)
+ + "]";
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/Consumer.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/Consumer.java
new file mode 100644
index 00000000..6f9061f5
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/Consumer.java
@@ -0,0 +1,7 @@
+package com.mithrilmania.blocktopograph.util;
+
+@FunctionalInterface
+public interface Consumer {
+
+ void accept(T param);
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/ConvertUtil.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/ConvertUtil.java
index 18dabd50..7fe70928 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/util/ConvertUtil.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/ConvertUtil.java
@@ -1,18 +1,133 @@
package com.mithrilmania.blocktopograph.util;
+
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
/**
* Convert utils
*/
public class ConvertUtil {
public static String bytesToHexStr(byte[] in) {
- if(in == null) return "null";
+ if (in == null) return "null";
final StringBuilder builder = new StringBuilder();
- for(byte b : in) {
+ for (byte b : in) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
+ private static int hexCharToByte(char ch) {
+ switch (ch) {
+ case '0':
+ return 0;
+ case '1':
+ return 1;
+ case '2':
+ return 2;
+ case '3':
+ return 3;
+ case '4':
+ return 4;
+ case '5':
+ return 5;
+ case '6':
+ return 6;
+ case '7':
+ return 7;
+ case '8':
+ return 8;
+ case '9':
+ return 9;
+ case 'a':
+ return 10;
+ case 'b':
+ return 11;
+ case 'c':
+ return 12;
+ case 'd':
+ return 13;
+ case 'e':
+ return 14;
+ case 'f':
+ return 15;
+ case 'A':
+ return 10;
+ case 'B':
+ return 11;
+ case 'C':
+ return 12;
+ case 'D':
+ return 13;
+ case 'E':
+ return 14;
+ case 'F':
+ return 15;
+ default:
+ return -1;
+ }
+ }
+
+ @Nullable
+ public static byte[] hexStringToBytes(@NonNull String text) {
+ byte[] ret;
+ if (text.charAt(0) == '0' && (text.charAt(1) == 'x' || text.charAt(1) == 'X'))
+ text = text.substring(2);
+ flow:
+ {
+ int len = text.length();
+ if ((len & 1) != 0) {
+ ret = null;
+ break flow;
+ }
+ len = len >> 1;
+ ret = new byte[len];
+ for (int i = 0; i < len; i++) {
+ int h = hexCharToByte(text.charAt(i << 1)) << 4;
+ if (h < 0) break flow;
+ int l = hexCharToByte(text.charAt(i << 1 | 1));
+ if (l < 0) break flow;
+ ret[i] = (byte) (h | l);
+ }
+ }
+ return ret;
+ }
+
+ @NonNull
+ public static String getLegalFileName(@NonNull String text) {
+ return text.replaceAll("[\\\\/:*?\"<>|.]", "_");
+ }
+
+ @Nullable
+ public static String guessPictureMimeFromExtension(@NonNull String extension, boolean inLower) {
+ // assert extension.length()>0;
+ if (extension.charAt(0) == '.') extension = extension.substring(1);
+ if (!inLower) extension = extension.toLowerCase();
+ String MIME_PNG = "image/png";
+ String MIME_JPG = "image/jpg";
+ switch (extension) {
+ case "png":
+ return MIME_PNG;
+ case "jpg":
+ case "jpeg":
+ return MIME_JPG;
+ default:
+ return null;
+ }
+ }
+
+ public static float distance(float x1, float y1, float x2, float y2) {
+ float d1 = x2 - x1;
+ float d2 = y2 - y1;
+ return (float) Math.sqrt(d1 * d1 + d2 * d2);
+ }
+
+ public static double distance(double x1, double y1, double x2, double y2) {
+ double d1 = x2 - x1;
+ double d2 = y2 - y1;
+ return Math.sqrt(d1 * d1 + d2 * d2);
+ }
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/IoUtil.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/IoUtil.java
new file mode 100644
index 00000000..9476a9c6
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/IoUtil.java
@@ -0,0 +1,251 @@
+package com.mithrilmania.blocktopograph.util;
+
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
+
+import com.mithrilmania.blocktopograph.Log;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+public class IoUtil {
+
+ /**
+ * Extract file from app asset to file system.
+ *
+ * @param mgr Asset manager instance.
+ * @param name Asset path. No slash at beginning or end.
+ * @param mode Asset access mode used in AssetManager.open().
+ * @param out Output file path. Shall be accessible.
+ * @return Success or not.
+ */
+ public static boolean extractAsset(AssetManager mgr, String name, int mode, File out) {
+ InputStream is = null;
+ FileOutputStream fos = null;
+ boolean ret = false;
+ try {
+ is = mgr.open(name, AssetManager.ACCESS_BUFFER);
+ fos = new FileOutputStream(out);
+ //FileUtil.copyStream(is, fos);
+ ret = true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ if (is != null) is.close();
+ } catch (Exception ignored) {
+ }
+ try {
+ if (fos != null) fos.close();
+ } catch (Exception ignored) {
+ }
+ return ret;
+ }
+
+ /**
+ * Read first line of a text file. Designed for levelname.txt.
+ *
+ * @param txtFile File to be read.
+ * @return Read content. Null if failed.
+ */
+ public static String readTextFileFirstLine(File txtFile) {
+ String text = null;
+ BufferedReader br;
+ try {
+ br = new BufferedReader(new FileReader(txtFile));
+ text = br.readLine();
+ br.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return text;
+ }
+
+ /**
+ * Make sure a certain directory exists and is a directory instead of other types of file.
+ *
+ * Will create the directory if not exist.
+ *
+ *
+ * @param dir Directory to be verified or created.
+ * @return Whether it's verified or failed for a reason.
+ */
+ public static Errno makeSureDirIsDir(@NonNull File dir) {
+ if (dir.exists()) {
+ if (!dir.isDirectory()) return Errno.FILE_WITH_SAME_NAME_EXISTS;
+ } else {
+ if (!dir.mkdirs()) return Errno.CANNOT_MKDIRS;
+ }
+ return Errno.OK;
+ }
+
+ /**
+ * Given a target file, add some variation to avoid name conflicts with existing file.
+ *
+ * For instance "/sdcard/xxx/meow.txt" may be a wanted name,
+ * but there exist "meow.txt", "meow (1).txt" and then
+ * "meow (2).txt have to be used.
+ *
+ *
+ * @param parent Directory the target file would reside.
+ * @param lhalf Left half of file name. E.g. "meow" for "meow ($count).txt".
+ * @param rhalf Right half of file name. E.g. ".txt" for "meow ($count).txt".
+ * @param prefix Prefix for the dynamic part. E.g. "(" for "meow ($count).txt".
+ * @param suffix Suffix for the dynamic part. E.g. ")" for "meow ($count).txt".
+ * @return The available name, or null if failed too many times.
+ */
+ @Nullable
+ public static File getFileWithFirstAvailableName(@NonNull File parent, @NonNull String
+ lhalf,
+ @NonNull String rhalf, @NonNull String prefix,
+ @NonNull String suffix) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(lhalf).append(rhalf);
+ File target = new File(parent, sb.toString());
+ if (!target.exists()) return target;
+ int count = 0;
+ do {
+ count++;
+ if (count > 999) return null;
+ sb = new StringBuilder(256).append(lhalf).append(prefix)
+ .append(count).append(suffix).append(rhalf);
+ target = new File(parent, sb.toString());
+ } while (target.exists());
+ return target;
+ }
+
+ public static boolean writeTextFile(@NonNull File file, @NonNull String name) {
+ try {
+ FileUtils.writeStringToFile(file, name);
+ return true;
+ } catch (IOException ignored) {
+ return false;
+ }
+ }
+
+ public static boolean writeBinaryFile(@NonNull File file, @NonNull byte[] data) {
+ try {
+ FileUtils.writeByteArrayToFile(file, data);
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Simple helper function to get the size of a folder or file in text format,
+ *
+ * @param size size
+ * @return size, formatted with a "B", "MB, "GB" or "TB", precise to 2 decimals.
+ */
+ @NonNull
+ public static String getFileSizeInText(long size) {
+ if (size < 1024) return size + " B";
+ double v = size / 1024.0;
+ String suffix = "KB";
+ if (v > 1024.0) {
+ v /= 1024.0;
+ if (v > 1024.0) {
+ v /= 1024.0;
+ if (v > 1024.0) {
+ v /= 1024.0;
+ suffix = "TB";//very high end android device here
+ } else suffix = "GB";
+ } else suffix = "MB";
+ }
+
+ return String.format(Locale.ENGLISH, "%.2f %s", v, suffix);
+
+ }
+
+ public enum Errno {
+ OK, FILE_WITH_SAME_NAME_EXISTS, CANNOT_MKDIRS,
+ PERMISSION_DENIED, UNKNOWN
+ }
+
+ /**
+ * Check if app has storage write permission. Use after requested permission in a previous activity.
+ *
+ * @param context Context.
+ * @return True if has permission, otherwise false.
+ */
+ public static boolean hasWritePermission(@NonNull Context context) {
+ int permission = ActivityCompat.checkSelfPermission(
+ context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ return permission == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Save a bitmap to file using Android's compress methods.
+ *
+ * @param bmp bitmap to save.
+ * @param format format required by Android. Png, Jpeg and Webp supported.
+ * @param quality Quality if using Jpeg.
+ * @param dir Directory to save to, should be folder not ordinary file.
+ * @param baseName Name of the file, without extension.
+ * @param autoRename Should file be automatically renamed to "xxx (1).jpg" things
+ * if a conflict happened.
+ * @return The file the bitmap was saved to, null if failed.
+ */
+ @Nullable
+ public static File saveBitmap(@NonNull Bitmap bmp, @NonNull Bitmap.CompressFormat format,
+ int quality, @NonNull File dir, @NonNull String baseName,
+ boolean autoRename) {
+ String extension;
+ if (!dir.exists()) {
+ if (autoRename) {
+ // If allowed to auto rename lets assume mkdir's also reasonable.
+ if (makeSureDirIsDir(dir) != Errno.OK) return null;
+ } else return null;
+ }
+ switch (format) {
+ case JPEG:
+ extension = ".jpg";
+ break;
+ case PNG:
+ extension = ".png";
+ break;
+ case WEBP:
+ extension = ".webp";
+ break;
+ default:
+ return null;
+ }
+ File saveTo = autoRename ?
+ getFileWithFirstAvailableName(dir, baseName, extension, "(", ")")
+ : new File(dir, baseName + extension);
+ if (saveTo == null) return null;
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(saveTo);
+ bmp.compress(format, quality, fos);
+ fos.close();
+ return saveTo;
+ } catch (Exception e) {
+ Log.d(IoUtil.class, e);
+ if (fos != null) try {
+ fos.close();
+ } catch (Exception ignore) {
+ }
+ return null;
+ }
+ }
+
+ public static void rubbish() {
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/LittleEndianOutputStream.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/LittleEndianOutputStream.java
new file mode 100644
index 00000000..a0fbb8e5
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/LittleEndianOutputStream.java
@@ -0,0 +1,296 @@
+/*
+ * @(#)LittleEndianOutputStream.java 1.0.1 99/05/19
+ *
+ * Copyright 1998, 1999 Elliotte Rusty Harold
+ *
+ */
+
+package com.mithrilmania.blocktopograph.util;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UTFDataFormatException;
+
+/**
+ * A little endian output stream writes primitive Java numbers
+ * and characters to an output stream in a little endian format.
+ * The standard java.io.DataOutputStream class which this class
+ * imitates uses big-endian integers.
+ *
+ * @author Elliotte Rusty Harold
+ * @version 1.0.1, 19 May 1999
+ * see com.macfaq.io.LittleEndianInputStream
+ * @see java.io.DataOutputStream
+ */
+public class LittleEndianOutputStream extends FilterOutputStream {
+
+ /**
+ * The number of bytes written so far to the little endian output stream.
+ */
+ protected int written;
+
+ /**
+ * Creates a new little endian output stream and chains it to the
+ * output stream specified by the out argument.
+ *
+ * @param out the underlying output stream.
+ * @see java.io.FilterOutputStream#out
+ */
+ public LittleEndianOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ /**
+ * Writes the specified byte value to the underlying output stream.
+ *
+ * @param b the byte value to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public synchronized void write(int b) throws IOException {
+ out.write(b);
+ written++;
+ }
+
+ /**
+ * Writes length bytes from the specified byte array
+ * starting at offset to the underlying output stream.
+ *
+ * @param data the data.
+ * @param offset the start offset in the data.
+ * @param length the number of bytes to write.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public synchronized void write(byte[] data, int offset, int length)
+ throws IOException {
+ out.write(data, offset, length);
+ written += length;
+ }
+
+
+ /**
+ * Writes a boolean to the underlying output stream as
+ * a single byte. If the argument is true, the byte value 1 is written.
+ * If the argument is false, the byte value 0 in written.
+ *
+ * @param b the boolean value to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public void writeBoolean(boolean b) throws IOException {
+
+ if (b) this.write(1);
+ else this.write(0);
+
+ }
+
+ /**
+ * Writes out a byte to the underlying output stream
+ *
+ * @param b the byte value to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public void writeByte(int b) throws IOException {
+ out.write(b);
+ written++;
+ }
+
+ /**
+ * Writes a two byte short to the underlying output stream in
+ * little endian order, low byte first.
+ *
+ * @param s the short to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public void writeShort(int s) throws IOException {
+
+ out.write(s & 0xFF);
+ out.write((s >>> 8) & 0xFF);
+ written += 2;
+
+ }
+
+ /**
+ * Writes a two byte char to the underlying output stream
+ * in little endian order, low byte first.
+ *
+ * @param c the char value to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public void writeChar(int c) throws IOException {
+
+ out.write(c & 0xFF);
+ out.write((c >>> 8) & 0xFF);
+ written += 2;
+
+ }
+
+ /**
+ * Writes a four-byte int to the underlying output stream
+ * in little endian order, low byte first, high byte last
+ *
+ * @param i the int to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public void writeInt(int i) throws IOException {
+
+ out.write(i & 0xFF);
+ out.write((i >>> 8) & 0xFF);
+ out.write((i >>> 16) & 0xFF);
+ out.write((i >>> 24) & 0xFF);
+ written += 4;
+
+ }
+
+ /**
+ * Writes an eight-byte long to the underlying output stream
+ * in little endian order, low byte first, high byte last
+ *
+ * @param l the long to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public void writeLong(long l) throws IOException {
+
+ out.write((int) l & 0xFF);
+ out.write((int) (l >>> 8) & 0xFF);
+ out.write((int) (l >>> 16) & 0xFF);
+ out.write((int) (l >>> 24) & 0xFF);
+ out.write((int) (l >>> 32) & 0xFF);
+ out.write((int) (l >>> 40) & 0xFF);
+ out.write((int) (l >>> 48) & 0xFF);
+ out.write((int) (l >>> 56) & 0xFF);
+ written += 8;
+
+ }
+
+ /**
+ * Writes a 4 byte Java float to the underlying output stream in
+ * little endian order.
+ *
+ * @param f the float value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ public final void writeFloat(float f) throws IOException {
+
+ this.writeInt(Float.floatToIntBits(f));
+
+ }
+
+ /**
+ * Writes an 8 byte Java double to the underlying output stream in
+ * little endian order.
+ *
+ * @param d the double value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ public final void writeDouble(double d) throws IOException {
+
+ this.writeLong(Double.doubleToLongBits(d));
+
+ }
+
+ /**
+ * Writes a string to the underlying output stream as a sequence of
+ * bytes. Each character is written to the data output stream as
+ * if by the writeByte() method.
+ *
+ * @param s the String value to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ * see java.io.LittleEndianOutputStream#writeByte(int)
+ * see java.io.LittleEndianOutputStream#out
+ */
+ public void writeBytes(String s) throws IOException {
+
+ int length = s.length();
+ for (int i = 0; i < length; i++) {
+ out.write((byte) s.charAt(i));
+ }
+ written += length;
+ }
+
+ /**
+ * Writes a string to the underlying output stream as a sequence of
+ * characters. Each character is written to the data output stream as
+ * if by the writeChar method.
+ *
+ * @param s a String value to be written.
+ * @throws IOException if the underlying stream throws an IOException.
+ * see java.io.LittleEndianOutputStream#writeChar(int)
+ * see java.io.LittleEndianOutputStream#out
+ */
+ public void writeChars(String s) throws IOException {
+
+ int length = s.length();
+ for (int i = 0; i < length; i++) {
+ int c = s.charAt(i);
+ out.write(c & 0xFF);
+ out.write((c >>> 8) & 0xFF);
+ }
+ written += length * 2;
+
+ }
+
+ /**
+ * Writes a string of no more than 65,535 characters
+ * to the underlying output stream using UTF-8
+ * encoding. This method first writes a two byte short
+ * in big endian order as required by the
+ * UTF-8 specification. This gives the number of bytes in the
+ * UTF-8 encoded version of the string, not the number of characters
+ * in the string. Next each character of the string is written
+ * using the UTF-8 encoding for the character.
+ *
+ * @param s the string to be written.
+ * @throws UTFDataFormatException if the string is longer than
+ * 65,535 characters.
+ * @throws IOException if the underlying stream throws an IOException.
+ */
+ public void writeUTF(String s) throws IOException {
+
+ int numchars = s.length();
+ int numbytes = 0;
+
+ for (int i = 0; i < numchars; i++) {
+ int c = s.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F)) numbytes++;
+ else if (c > 0x07FF) numbytes += 3;
+ else numbytes += 2;
+ }
+
+ if (numbytes > 65535) throw new UTFDataFormatException();
+
+ out.write((numbytes >>> 8) & 0xFF);
+ out.write(numbytes & 0xFF);
+ for (int i = 0; i < numchars; i++) {
+ int c = s.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ out.write(c);
+ } else if (c > 0x07FF) {
+ out.write(0xE0 | ((c >> 12) & 0x0F));
+ out.write(0x80 | ((c >> 6) & 0x3F));
+ out.write(0x80 | (c & 0x3F));
+ written += 2;
+ } else {
+ out.write(0xC0 | ((c >> 6) & 0x1F));
+ out.write(0x80 | (c & 0x3F));
+ written += 1;
+ }
+ }
+
+ written += numchars + 2;
+
+ }
+
+ /**
+ * Returns the number of bytes written to this little endian output stream.
+ * (This class is not thread-safe with respect to this method. It is
+ * possible that this number is temporarily less than the actual
+ * number of bytes written.)
+ *
+ * @return the value of the written field.
+ * see java.io.LittleEndianOutputStream#written
+ */
+ public int size() {
+ return this.written;
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/McUtil.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/McUtil.java
new file mode 100644
index 00000000..230d1a2d
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/McUtil.java
@@ -0,0 +1,33 @@
+package com.mithrilmania.blocktopograph.util;
+
+import androidx.annotation.NonNull;
+
+import java.io.File;
+
+public final class McUtil {
+
+ @NonNull
+
+ public static File getMinecraftWorldsDir(File sdcard) {
+ return new File(sdcard, "games/com.mojang/minecraftWorlds");
+ }
+
+ @NonNull
+
+ public static File getBtgTestDir(File sdcard) {
+ return new File(sdcard, "games/com.mojang/btgTest");
+ }
+
+ @NonNull
+
+ public static File getLevelDatFile(File world) {
+ return new File(world, "level.dat");
+ }
+
+ @NonNull
+
+ public static File getLevelNameFile(File world) {
+ return new File(world, "levelname.txt");
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/NamedBitmapProvider.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/NamedBitmapProvider.java
index db81645e..be9f5fd6 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/util/NamedBitmapProvider.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/NamedBitmapProvider.java
@@ -1,7 +1,7 @@
package com.mithrilmania.blocktopograph.util;
import android.graphics.Bitmap;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
public interface NamedBitmapProvider {
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/NamedBitmapProviderHandle.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/NamedBitmapProviderHandle.java
index 5d4df6db..717dfef0 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/util/NamedBitmapProviderHandle.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/NamedBitmapProviderHandle.java
@@ -1,6 +1,6 @@
package com.mithrilmania.blocktopograph.util;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
public interface NamedBitmapProviderHandle {
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/UiUtil.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/UiUtil.java
new file mode 100644
index 00000000..b070b5d2
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/util/UiUtil.java
@@ -0,0 +1,156 @@
+package com.mithrilmania.blocktopograph.util;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.graphics.ColorUtils;
+import androidx.databinding.DataBindingUtil;
+
+import com.google.android.material.snackbar.Snackbar;
+import com.mithrilmania.blocktopograph.R;
+import com.mithrilmania.blocktopograph.block.BlockTemplate;
+import com.mithrilmania.blocktopograph.block.KnownBlockRepr;
+import com.mithrilmania.blocktopograph.block.ListingBlock;
+import com.mithrilmania.blocktopograph.databinding.GeneralWaitBinding;
+import com.mithrilmania.blocktopograph.map.Biome;
+
+
+public final class UiUtil {
+
+ public static void toastError(@NonNull Context context) {
+ Toast.makeText(context, R.string.error_general, Toast.LENGTH_SHORT).show();
+ }
+
+ public static void toast(@NonNull Context context, @NonNull String text) {
+ Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
+ }
+
+ public static void toast(@NonNull Context context, @StringRes int resId) {
+ Toast.makeText(context, resId, Toast.LENGTH_SHORT).show();
+ }
+
+ public static void snackError(@NonNull View view) {
+ Snackbar.make(view, R.string.error_general, Snackbar.LENGTH_SHORT).show();
+ }
+
+ public static void snack(@NonNull View view, @NonNull String text) {
+ Snackbar.make(view, text, Snackbar.LENGTH_SHORT).show();
+ }
+
+ public static void snack(@NonNull Activity activity, @NonNull String text) {
+ snack(activity.getWindow().getDecorView(), text);
+ }
+
+ public static void snack(@NonNull View view, @StringRes int resId) {
+ Snackbar.make(view, resId, Snackbar.LENGTH_SHORT).show();
+ }
+
+ public static void snack(@NonNull Activity activity, @StringRes int resId) {
+ snack(activity.getWindow().getDecorView(), resId);
+ }
+
+ public static void blendBlockColor(@NonNull View view, KnownBlockRepr block) {
+ Drawable drawable = view.getBackground();
+ if (!(drawable instanceof GradientDrawable)) return;
+ GradientDrawable gradientDrawable = (GradientDrawable) drawable;
+ int res = (block.id == 0) ? 0 : ColorUtils.blendARGB(block.color, 0x7f7f7f7f, 0.5f);
+ gradientDrawable.setColor(res);
+ }
+
+ public static void blendBlockColor(@NonNull View view, ListingBlock block) {
+ Drawable drawable = view.getBackground();
+ if (!(drawable instanceof GradientDrawable)) return;
+ GradientDrawable gradientDrawable = (GradientDrawable) drawable;
+ int color = block.getColor();
+ if (color != Color.TRANSPARENT)
+ color = ColorUtils.blendARGB(color, 0x7f7f7f7f, 0.5f);
+ gradientDrawable.setColor(color);
+ }
+
+ public static void blendBlockColor(@NonNull View view, BlockTemplate block) {
+ Drawable drawable = view.getBackground();
+ if (!(drawable instanceof GradientDrawable)) return;
+ GradientDrawable gradientDrawable = (GradientDrawable) drawable;
+ int color = block.getColor();
+ if (color != Color.TRANSPARENT)
+ color = ColorUtils.blendARGB(color, 0x7f7f7f7f, 0.5f);
+ gradientDrawable.setColor(color);
+ }
+
+ public static void blendBlockColor(@NonNull View view, Biome biome) {
+ Drawable drawable = view.getBackground();
+ if (!(drawable instanceof GradientDrawable)) return;
+ GradientDrawable gradientDrawable = (GradientDrawable) drawable;
+ int res = ColorUtils.blendARGB(biome.color.asARGB(), 0x7f7f7f7f, 0.5f);
+ gradientDrawable.setColor(res);
+ }
+
+ @Nullable
+ public static Integer readIntFromView(@NonNull EditText editText, boolean emptyAsZero) {
+ String string = editText.getText().toString();
+ if (emptyAsZero && string.isEmpty()) return 0;
+ try {
+ return Integer.parseInt(string);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+ public static int readIntFromView(@NonNull EditText editText) {
+ String string = editText.getText().toString();
+ try {
+ return Integer.parseInt(string);
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
+ public static int readIntFromViewWithDefault(@NonNull EditText editText, int defaultVal) {
+ String string = editText.getText().toString();
+ if (string.trim().isEmpty()) return defaultVal;
+ try {
+ return Integer.parseInt(string);
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
+
+ public static AlertDialog buildProgressWaitDialog(
+ @NonNull Context context, @StringRes int text,
+ @Nullable DialogInterface.OnCancelListener onCancelListener) {
+ GeneralWaitBinding binding = DataBindingUtil.inflate(
+ LayoutInflater.from(context),
+ R.layout.general_wait, null, false
+ );
+ binding.setText(text);
+ AlertDialog dialog = new AlertDialog.Builder(context)
+ .setView(binding.getRoot())
+ .setCancelable(onCancelListener != null)
+ .create();
+ if (onCancelListener != null) dialog.setOnCancelListener(onCancelListener);
+ else dialog.setCancelable(false);
+ dialog.setCanceledOnTouchOutside(false);
+ return dialog;
+ }
+
+ public static float dpToPx(@NonNull Context context, float dp) {
+ return context.getResources().getDisplayMetrics().density * dp;
+ }
+
+ public static int dpToPxInt(@NonNull Context context, int dp) {
+ return (int) (context.getResources().getDisplayMetrics().density * dp);
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/io/IOUtil.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/io/IOUtil.java
deleted file mode 100644
index fdad558f..00000000
--- a/app/src/main/java/com/mithrilmania/blocktopograph/util/io/IOUtil.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.mithrilmania.blocktopograph.util.io;
-
-
-import java.io.File;
-import java.util.Locale;
-
-public class IOUtil {
-
- /**
- * Returns the size of a folder (total of contents) in number of bytes.
- * Returns 0 if it doesn't exist.
- * @param f folder to get size of.
- * @return size of folder f in bytes.
- */
- public static long getFolderSize(File f) {
- long size = 0;
- if (f.isDirectory()) {
- for (File file : f.listFiles()) {
- size += getFolderSize(file);
- }
- } else {
- size = f.length();
- }
- return size;
- }
-
- /**
- * Simple helper function to get the size of a folder or file in text format,
- * @param f file to return size of
- * @return size, formatted with a "B", "MB, "GB" or "TB", precise to 2 decimals.
- */
- public static String getFileSizeInText(File f){
- long size = getFolderSize(f);
- if(size < 1024) return size + " B";
- double v = size / 1024.0;
- String suffix = "KB";
- if(v > 1024.0){
- v /= 1024.0;
- if(v > 1024.0){
- v /= 1024.0;
- if(v > 1024.0){
- v /= 1024.0;
- suffix = "TB";//very high end android device here
- }
- else suffix = "GB";
- }
- else suffix = "MB";
- }
-
- return String.format(Locale.ENGLISH, "%.2f %s", v, suffix);
-
- }
-}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/util/io/TextFile.java b/app/src/main/java/com/mithrilmania/blocktopograph/util/io/TextFile.java
deleted file mode 100644
index ec53a145..00000000
--- a/app/src/main/java/com/mithrilmania/blocktopograph/util/io/TextFile.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.mithrilmania.blocktopograph.util.io;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-
-public class TextFile {
-
- /** Read text file in sync, only use this when appropriate... not in UI **/
- public static String readTextFile(File txtFile){
- StringBuilder text = new StringBuilder();
- BufferedReader br;
- try {
- br = new BufferedReader(new FileReader(txtFile));
- String line;
- while ((line = br.readLine()) != null) {
- text.append(line).append('\n');
- }
- br.close();
- }
- catch (IOException e) {
- e.printStackTrace();
-
- }
- return text.toString();
- }
-
- public static String readTextFileFirstLine(File txtFile){
- String text = null;
- BufferedReader br;
- try {
- br = new BufferedReader(new FileReader(txtFile));
- text = br.readLine();
- br.close();
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- return text;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/view/MeowExpansionLayout.java b/app/src/main/java/com/mithrilmania/blocktopograph/view/MeowExpansionLayout.java
new file mode 100644
index 00000000..2075dd87
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/view/MeowExpansionLayout.java
@@ -0,0 +1,174 @@
+package com.mithrilmania.blocktopograph.view;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.EdgeEffect;
+
+import com.github.florent37.expansionpanel.ExpansionLayout;
+import com.mithrilmania.blocktopograph.Log;
+
+import java.lang.reflect.Field;
+
+import androidx.core.widget.NestedScrollView;
+
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+/**
+ * The class serves two purpose, for layout height fix and edge effect on expansion.
+ *
+ *
+ * Unlike a usual use case of the ExpansionLayout as nested scrollable component,
+ * a "wrap content if space, or match parent if not" behavior was wanted here.
+ * So a fix/workaround at expansion time and after expansion was needed.
+ *
+ * Also a glowing edge effect at the top was wanted, in order to indicate
+ * that the current view was scrollable, and there're content below.
+ *
+ */
+public class MeowExpansionLayout extends ExpansionLayout {
+
+ /**
+ * Top edge effect of the underlying NestedScrollView.
+ */
+ private EdgeEffect mEdgeEffect;
+
+ public MeowExpansionLayout(Context context) {
+ super(context);
+ init();
+ }
+
+ public MeowExpansionLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public MeowExpansionLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private void init() {
+ Class clazz = NestedScrollView.class;
+ try {
+ Field edgeGlowField = clazz.getDeclaredField("mEdgeGlowTop");
+ edgeGlowField.setAccessible(true);
+ Context context = getContext();
+ EdgeEffect edge = new EdgeEffect(context);
+ edgeGlowField.set(this, edge);
+ //mEdgeEffect = (EdgeEffect) edgeGlowField.get(this);
+ edgeGlowField.setAccessible(false);
+ edgeGlowField = clazz.getDeclaredField("mEdgeGlowBottom");
+ edgeGlowField.setAccessible(true);
+ edgeGlowField.set(this, new EdgeEffect(context));
+ edgeGlowField.setAccessible(false);
+ edge.setSize(20, 20);
+ mEdgeEffect = edge;
+ //post(this::doOverScroll);
+ } catch (Exception e) {
+ Log.d(this, e);
+ }
+ }
+
+ /**
+ * Extended to fix display bug.
+ *
+ *
+ * ScrollViews does not fit well in a limited space without a preset height.
+ * This was used to apply a "wrap content if space, or match parent if not" rule.
+ *
+ *
+ * @param animated Whether display expansion animation. Always true.
+ */
+ @Override
+ public void expand(boolean animated) {
+ if (!isEnabled() || isExpanded()) {
+ return;
+ }
+
+ if (animated) {
+ final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, getChildAt(0).getHeight());
+ valueAnimator.addUpdateListener(valueAnimator1 ->
+ setHeightValue((Float) valueAnimator1.getAnimatedValue()));
+ valueAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ setHeight(WRAP_CONTENT);
+ setAnimator(null);
+ doOverScroll();
+ }
+ });
+ setExpanded(true);
+ setAnimator(valueAnimator);
+ valueAnimator.start();
+ } else {
+ // Behavior w/o animation was unchanged.
+ setHeightValue(getChildAt(0).getHeight());
+ setExpanded(true);
+ }
+ }
+
+ /**
+ * Set height with given value if space, or max remaining value if not.
+ *
+ *
+ * This must be the last child of a vertical LinearLayout with match_parent height.
+ *
+ *
+ * @param height desired height, might not be the final actual height of the view.
+ */
+ private void setHeightValue(float height) {
+ ViewParent parent = getParent();
+ if (parent instanceof ViewGroup) {
+ float remaining = ((ViewGroup) parent).getMeasuredHeight() - getY();
+ height = Math.min(remaining, height);
+ //Log.d(this, "remaining: " + remaining + ", requested: " + height);
+ setHeight((int) height);
+ }
+ }
+
+ private void setHeight(int height) {
+ final ViewGroup.LayoutParams layoutParams = getLayoutParams();
+ if (layoutParams != null) {
+ layoutParams.height = height;
+ setLayoutParams(layoutParams);
+ }
+ }
+
+ private void setAnimator(Animator animator) {
+ try {
+ Class clazz = ExpansionLayout.class;
+ Field fieldAnimator = clazz.getDeclaredField("animator");
+ fieldAnimator.setAccessible(true);
+ fieldAnimator.set(this, animator);
+ fieldAnimator.setAccessible(false);
+ } catch (Throwable e) {
+ Log.d(this, e);
+ }
+ }
+
+ private void setExpanded(boolean expanded) {
+ try {
+ Class clazz = ExpansionLayout.class;
+ Field fieldAnimator = clazz.getDeclaredField("expanded");
+ fieldAnimator.setAccessible(true);
+ fieldAnimator.setBoolean(this, expanded);
+ fieldAnimator.setAccessible(false);
+ } catch (Throwable e) {
+ Log.d(this, e);
+ }
+ }
+
+ public void doOverScroll() {
+ if (mEdgeEffect != null) {
+ mEdgeEffect.onPull(200);
+ invalidate();
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/view/MeowScrollView.java b/app/src/main/java/com/mithrilmania/blocktopograph/view/MeowScrollView.java
new file mode 100644
index 00000000..b5c5a823
--- /dev/null
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/view/MeowScrollView.java
@@ -0,0 +1,64 @@
+package com.mithrilmania.blocktopograph.view;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.widget.EdgeEffect;
+import android.widget.ScrollView;
+
+import com.mithrilmania.blocktopograph.Log;
+
+import java.lang.reflect.Field;
+
+public class MeowScrollView extends ScrollView {
+
+ /**
+ * Top glowing effect of the underlying scrollView.
+ *
+ * It was retrieved via reflection and used later.
+ */
+ private EdgeEffect mEdgeEffect;
+
+ public MeowScrollView(Context context) {
+ super(context);
+ init();
+ }
+
+ public MeowScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public MeowScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public MeowScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ Class clazz = ScrollView.class;
+ try {
+ Field edgeGlowField = clazz.getDeclaredField("mEdgeGlowTop");
+ edgeGlowField.setAccessible(true);
+ mEdgeEffect = (EdgeEffect) edgeGlowField.get(this);
+ edgeGlowField.setAccessible(false);
+ mEdgeEffect.setSize(20, 20);
+ post(this::doOverScroll);
+ } catch (Exception e) {
+ Log.d(this, e);
+ }
+ }
+
+ public void doOverScroll() {
+ if (mEdgeEffect != null) {
+ mEdgeEffect.onPull(200);
+ invalidate();
+ }
+ }
+}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemDetailActivity.java b/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemDetailActivity.java
index 93227237..c0c72ee9 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemDetailActivity.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemDetailActivity.java
@@ -3,9 +3,9 @@
import android.content.Intent;
import android.os.Bundle;
-import android.support.v7.widget.Toolbar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.app.ActionBar;
+import androidx.appcompat.widget.Toolbar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.app.ActionBar;
import android.view.MenuItem;
import com.mithrilmania.blocktopograph.R;
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemDetailFragment.java b/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemDetailFragment.java
index 0df821b8..dd7b8b15 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemDetailFragment.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemDetailFragment.java
@@ -1,28 +1,36 @@
package com.mithrilmania.blocktopograph.worldlist;
+import android.annotation.SuppressLint;
import android.app.Activity;
-import android.content.Context;
import android.content.Intent;
-import android.support.design.widget.CollapsingToolbarLayout;
+import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.design.widget.FloatingActionButton;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.TextView;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.Fragment;
+import com.google.android.material.appbar.CollapsingToolbarLayout;
+import com.google.android.material.snackbar.Snackbar;
+import com.mithrilmania.blocktopograph.BackupActivity;
+import com.mithrilmania.blocktopograph.Log;
import com.mithrilmania.blocktopograph.R;
import com.mithrilmania.blocktopograph.World;
import com.mithrilmania.blocktopograph.WorldActivity;
-import com.mithrilmania.blocktopograph.util.io.IOUtil;
+import com.mithrilmania.blocktopograph.backup.WorldBackups;
+import com.mithrilmania.blocktopograph.databinding.WorlditemDetailBinding;
+import com.mithrilmania.blocktopograph.test.MainTestActivity;
+import com.mithrilmania.blocktopograph.util.IoUtil;
+import com.mithrilmania.blocktopograph.util.UiUtil;
+
+import org.apache.commons.io.FileUtils;
+
+import java.util.Arrays;
+import java.util.Date;
/**
* A fragment representing a single WorldItem detail screen.
@@ -30,12 +38,15 @@
* in two-pane mode (on tablets) or a {@link WorldItemDetailActivity}
* on handsets.
*/
-public class WorldItemDetailFragment extends Fragment {
+public class WorldItemDetailFragment extends Fragment implements View.OnClickListener {
/**
* The dummy content this fragment is presenting.
*/
- private World world;
+ private static final byte[] SEQ_TEST = {0, 1, 1, 0};
+
+ private World mWorld;
+ private byte[] mSequence;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
@@ -44,150 +55,125 @@ public class WorldItemDetailFragment extends Fragment {
public WorldItemDetailFragment() {
}
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- }
-
- private String getDate(long time) {
- Calendar cal = Calendar.getInstance();
- TimeZone tz = cal.getTimeZone();//get your local time zone.
- SimpleDateFormat sdf = new SimpleDateFormat(getString(R.string.full_date_format), Locale.ENGLISH);
- sdf.setTimeZone(tz);//set time zone.
- return sdf.format(new Date(time * 1000));
- }
+// private String getDate(long time) {
+// Calendar cal = Calendar.getInstance();
+// TimeZone tz = cal.getTimeZone();//get your local time zone.
+// SimpleDateFormat sdf = new SimpleDateFormat(getString(R.string.full_date_format), Locale.ENGLISH);
+// sdf.setTimeZone(tz);//set time zone.
+// return sdf.format(new Date(time * 1000));
+// }
+ @SuppressLint("StaticFieldLeak")
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
+ WorlditemDetailBinding binding = DataBindingUtil.inflate(inflater, R.layout.worlditem_detail, container, false);
Activity activity = this.getActivity();
+ assert activity != null;
String barTitle;
- if(!getArguments().containsKey(World.ARG_WORLD_SERIALIZED)){
- Snackbar.make(activity.findViewById(R.id.worlditem_detail),
+ Bundle arguments = getArguments();
+ if (arguments == null || !arguments.containsKey(World.ARG_WORLD_SERIALIZED)) {
+ Snackbar.make(binding.worlditemDetail,
R.string.error_could_not_open_world_details_lost_track_world, Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
barTitle = activity.getString(R.string.error_could_not_open_world);
} else {
-
- world = (World) getArguments().getSerializable(World.ARG_WORLD_SERIALIZED);
- barTitle = world ==null ? activity.getString(R.string.error_could_not_open_world) : world.getWorldDisplayName();
+ mWorld = (World) arguments.getSerializable(World.ARG_WORLD_SERIALIZED);
+ barTitle = mWorld == null ? activity.getString(R.string.error_could_not_open_world) : mWorld.getWorldDisplayName();
}
- CollapsingToolbarLayout appBarLayout = (CollapsingToolbarLayout) activity.findViewById(R.id.toolbar_layout);
+ CollapsingToolbarLayout appBarLayout = activity.findViewById(R.id.toolbar_layout);
if (appBarLayout != null) {
appBarLayout.setTitle(barTitle);
}
-
- View rootView = inflater.inflate(R.layout.worlditem_detail, container, false);
-
try {
- if (world != null && world.level != null){
- TextView worldName = (TextView) rootView.findViewById(R.id.detail_world_name);
- worldName.setText(world.getWorldDisplayName());
- TextView worldSize = (TextView) rootView.findViewById(R.id.detail_world_size);
- worldSize.setText(IOUtil.getFileSizeInText(world.worldFolder));
-
- TextView worldGameMode = (TextView) rootView.findViewById(R.id.detail_world_gamemode);
- worldGameMode.setText(WorldListUtil.getWorldGamemodeText(activity, world));
-
- TextView lastPlayed = (TextView) rootView.findViewById(R.id.detail_last_played);
- lastPlayed.setText(WorldListUtil.getLastPlayedText(activity, world));
-
- TextView worldSeed = (TextView) rootView.findViewById(R.id.detail_world_seed);
- worldSeed.setText(String.valueOf(world.getWorldSeed()));
-
- TextView worldPath = (TextView) rootView.findViewById(R.id.detail_world_path);
- worldPath.setText(world.levelFile.getAbsolutePath());
+ if (mWorld != null && mWorld.getLevel() != null) {
+ binding.setName(mWorld.getWorldDisplayName());
+ binding.setSize(IoUtil.getFileSizeInText(FileUtils.sizeOf(mWorld.worldFolder)));
+ binding.setMode(WorldListUtil.getWorldGamemodeText(activity, mWorld));
+ binding.setTime(WorldListUtil.getLastPlayedText(activity, mWorld));
+ binding.setSeed(String.valueOf(mWorld.getWorldSeed()));
+ binding.setPath(mWorld.levelFile.getAbsolutePath());
}
- } catch (Exception e){
- e.printStackTrace();
+ } catch (Exception e) {
+ Log.d(this, e);
}
+ binding.fabOpenWorld.setOnClickListener(view -> {
+ WorldBackups worldBackups = new WorldBackups(mWorld);
+ worldBackups.loadConfig();
+ if (worldBackups.autoBackup) {
+ AlertDialog dia = UiUtil.buildProgressWaitDialog(view.getContext(),
+ R.string.auto_backup_caption, null);
+ dia.show();
+ new AsyncTask() {
+ @Override
+ protected Boolean doInBackground(WorldBackups... worldBackups) {
+ return worldBackups[0].createNewBackup(getString(R.string.auto_backup_name), new Date());
+ }
- FloatingActionButton fabOpenWorld = (FloatingActionButton) rootView.findViewById(R.id.fab_open_world);
- assert fabOpenWorld != null;
- fabOpenWorld.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Snackbar.make(view, R.string.loading_world, Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
-
- Context context = view.getContext();
- Intent intent = new Intent(context, WorldActivity.class);
- intent.putExtra(World.ARG_WORLD_SERIALIZED, world);
-
- context.startActivity(intent);
- }
- });
-
- // Debug button to write small worlds in an easily readable format
- // WARNING: DO NOT USE ON LARGE WORLDS (The debug output will get way larger than the world!)
- /*
- FloatingActionButton fabDevMode = (FloatingActionButton) rootView.findViewById(R.id.fab_dev_mode);
- assert fabDevMode != null;
- fabDevMode.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Snackbar.make(view, "Outputting world...", Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
-
- WorldData wData = world.getWorldData();
-
-
-
- File outputFile = new File(world.worldFolder, "debug_hex_out.txt");
-
- try {
-
- wData.load();
- wData.openDB();
- Iterator it = wData.db.iterator();
-
- BufferedWriter buf = new BufferedWriter(new FileWriter(outputFile, false), 1024);
-
- for(it.seekToFirst(); it.isValid(); it.next()){
- byte[] key = it.getKey();
- byte[] value = it.getValue();
-
- buf.newLine();
- buf.newLine();
- buf.write("========================");
- buf.newLine();
- buf.write("key: " + new String(key));
- buf.newLine();
- buf.write("key in Hex: " + WorldData.bytesToHex(key, 0, key.length));
- buf.newLine();
- buf.write("------------------------");
- buf.newLine();
- for(int i =0; i < value.length; i += 256){
- buf.write(WorldData.bytesToHex(value, i, Math.min(i + 256, value.length)));
- buf.newLine();
+ @Override
+ protected void onPostExecute(Boolean aBoolean) {
+ if (!aBoolean) {
+ Activity activity1 = getActivity();
+ if (activity1 != null)
+ UiUtil.snack(activity1, R.string.general_failed);
}
-
+ synchronized (dia) {
+ if (dia.isShowing()) dia.dismiss();
+ }
+ startWorldActivity();
}
+ }.execute(worldBackups);
+ } else startWorldActivity();
+ });
- buf.close();
+ mSequence = new byte[]{-1, -1, -1, -1};
+ binding.buttonLeft.setOnClickListener(this);
+ binding.buttonRight.setOnClickListener(this);
+ binding.buttonBackup.setOnClickListener(this);
- it.close();
- wData.closeDB();
+ return binding.getRoot();
+ }
- }
- catch (Exception e) {
- Log.e("Failed writing debug file to "+outputFile.getAbsolutePath()+"\n" + e.toString());
- }
+ private void startWorldActivity() {
- Snackbar.make(view, "Done outputting world!!! Path: "+outputFile.getAbsolutePath(), Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
+ Activity activity = getActivity();
+ assert activity != null;
+ activity.startActivity(
+ new Intent(activity, WorldActivity.class)
+ .putExtra(World.ARG_WORLD_SERIALIZED, mWorld));
+ }
- }
- });*/
+ private void sequence(byte code) {
+ int pos = mSequence.length - 1;
+ System.arraycopy(mSequence, 1, mSequence, 0, pos);
+ mSequence[pos] = code;
+ if (Arrays.equals(mSequence, SEQ_TEST)) {
+ startActivity(
+ new Intent(getActivity(), MainTestActivity.class)
+ .putExtra(World.ARG_WORLD_SERIALIZED, mWorld)
+ );
+ }
+ }
- return rootView;
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.button_left:
+ sequence((byte) 0);
+ break;
+ case R.id.button_right:
+ sequence((byte) 1);
+ break;
+ case R.id.button_backup:
+ startActivity(new Intent(getActivity(), BackupActivity.class).putExtra(World.ARG_WORLD_SERIALIZED, mWorld));
+ break;
+ }
}
}
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemListActivity.java b/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemListActivity.java
index 088e17f8..a5d3e0ec 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemListActivity.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldItemListActivity.java
@@ -3,23 +3,15 @@
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
-import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
-import android.support.annotation.NonNull;
-import android.support.design.widget.FloatingActionButton;
-import android.support.design.widget.NavigationView;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.ActivityCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
import android.text.Editable;
-import android.text.Html;
+import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -29,41 +21,118 @@
import android.widget.EditText;
import android.widget.TextView;
-import com.mithrilmania.blocktopograph.BuildConfig;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.core.app.ActivityCompat;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.android.material.snackbar.Snackbar;
+import com.mithrilmania.blocktopograph.CreateWorldActivity;
import com.mithrilmania.blocktopograph.Log;
-import com.mithrilmania.blocktopograph.MenuHelper;
import com.mithrilmania.blocktopograph.R;
import com.mithrilmania.blocktopograph.World;
-import com.mithrilmania.blocktopograph.WorldActivity;
-import com.mithrilmania.blocktopograph.util.io.IOUtil;
+import com.mithrilmania.blocktopograph.backup.WorldBackups;
+import com.mithrilmania.blocktopograph.util.IoUtil;
+
+import org.apache.commons.io.FileUtils;
import java.io.File;
-import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
-public class WorldItemListActivity extends AppCompatActivity implements MenuHelper.MenuContext {
+public class WorldItemListActivity extends AppCompatActivity {
+ // Storage Permissions
+ private static final int REQUEST_EXTERNAL_STORAGE = 4242;
+ private static final String[] PERMISSIONS_STORAGE = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE
+ };
+ public static final int REQUEST_CODE_CREATE_WORLD = 2012;
+ public static final String PREF_KEY_ACCEPT_DATA_USAGE = "accept_data_usage";
/**
- * Whether or not the activity is in two-pane mode, i.e. running on a tablet
- * device.
+ * Whether or not the activity is in two-pane mode, d.e. running on a tablet.
*/
private boolean mTwoPane;
-
private WorldItemRecyclerViewAdapter worldItemAdapter;
+ /**
+ * Checks if the app has permission to write to device storage
+ *
+ * If the app does not has permission then the user will be prompted to grant permissions
+ *
+ */
+ public static boolean verifyStoragePermissions(Activity activity) {
+ // Check if we have write permission
+ boolean hasPermission = true;
+ for (String permission : PERMISSIONS_STORAGE) {
+ int state = ActivityCompat.checkSelfPermission(activity, permission);
+ if (state != PackageManager.PERMISSION_GRANTED) {
+ hasPermission = false;
+ break;
+ }
+ }
+
+ if (!hasPermission) {
+ // We don't have permission so prompt the user
+ ActivityCompat.requestPermissions(
+ activity,
+ PERMISSIONS_STORAGE,
+ REQUEST_EXTERNAL_STORAGE
+ );
+ return false;
+ } else return true;
+ }
+
+ private void showFeedbackRequestDialogIfNeeded() {
+ SharedPreferences prefs = getPreferences(MODE_PRIVATE);
+ if (prefs.getInt(PREF_KEY_ACCEPT_DATA_USAGE, 0) == 1) {
+ Log.enableCrashlytics();
+ Log.enableFirebaseAnalytics(this);
+ return;
+ }
+ AlertDialog dialog = new AlertDialog.Builder(this)
+ .setTitle(R.string.privacy_promo_title)
+ .setMessage(R.string.privacy_promo_text)
+ .setPositiveButton(R.string.privacy_promo_accept_btn, this::onAcceptedRequestDialog)
+ .setNegativeButton(R.string.privacy_promo_reject_btn, this::onRejectedRequestDialog)
+ .setCancelable(false)
+ .create();
+ dialog.setCanceledOnTouchOutside(false);
+ dialog.show();
+ View view = dialog.findViewById(android.R.id.message);
+ if (view instanceof TextView)
+ ((TextView) view).setMovementMethod(LinkMovementMethod.getInstance());
+ else Log.d(this, "cannot find android.R.id.message for privacy request dialog.");
+ }
+
+ private void onAcceptedRequestDialog(DialogInterface dialogInterface, int i) {
+ Log.enableFirebaseAnalytics(this);
+ Log.enableCrashlytics();
+ getPreferences(MODE_PRIVATE).edit().putInt(PREF_KEY_ACCEPT_DATA_USAGE, 1).apply();
+ }
+
+ private void onRejectedRequestDialog(DialogInterface dialogInterface, int i) {
+ finishAffinity();
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
setContentView(R.layout.activity_worldlist);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
- assert toolbar != null;
toolbar.setTitle(getTitle());
setSupportActionBar(toolbar);
+ showFeedbackRequestDialogIfNeeded();
if (findViewById(R.id.worlditem_detail_container) != null) {
// The detail container view will be present only in the
@@ -73,37 +142,118 @@ protected void onCreate(Bundle savedInstanceState) {
mTwoPane = true;
}
-
- FloatingActionButton fabRefreshWorlds = (FloatingActionButton) findViewById(R.id.fab_refresh_worlds);
- assert fabRefreshWorlds != null;
- fabRefreshWorlds.setOnClickListener(new View.OnClickListener() {
+ FloatingActionButton fabChooseWorldFile = findViewById(R.id.fab_create);
+ fabChooseWorldFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
+ onClickCreateWorld();
+ }
+ });
- if(worldItemAdapter != null){
- if(worldItemAdapter.reloadWorldList()) {
- Snackbar.make(view, R.string.reloaded_world_list, Snackbar.LENGTH_SHORT)
- .setAction("Action", null).show();
- } else {
- Snackbar.make(view, R.string.could_not_find_worlds, Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
- } else {
- Snackbar.make(view, R.string.no_read_write_access, Snackbar.LENGTH_LONG)
- .setAction("Action", null).show();
- }
+ RecyclerView recyclerView = findViewById(R.id.worlditem_list);
+ worldItemAdapter = new WorldItemRecyclerViewAdapter();
+ recyclerView.setAdapter(this.worldItemAdapter);
+
+ if (verifyStoragePermissions(this)) {
+ //directly open the world list if we already have access
+ worldItemAdapter.enable();
+ }
+
+
+ }
+ private void onClickCreateWorld() {
+ if (worldItemAdapter.isDisabled()) {
+ Snackbar.make(getWindow().getDecorView(), R.string.no_read_write_access, Snackbar.LENGTH_SHORT).show();
+ return;
+ }
+ startActivityForResult(new Intent(this, CreateWorldActivity.class), REQUEST_CODE_CREATE_WORLD);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ if (resultCode == RESULT_OK) {
+ switch (requestCode) {
+ case REQUEST_CODE_CREATE_WORLD:
+ worldItemAdapter.loadWorldList();
+ return;
}
- });
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ private boolean checkPermissions(@NonNull int[] grantResults) {
+ for (int result : grantResults)
+ if (result != PackageManager.PERMISSION_GRANTED) return false;
+ return true;
+ }
- FloatingActionButton fabChooseWorldFile = (FloatingActionButton) findViewById(R.id.fab_choose_worldfile);
- assert fabChooseWorldFile != null;
- fabChooseWorldFile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(final View view) {
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ @NonNull String[] permissions, @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case REQUEST_EXTERNAL_STORAGE: {
+ // If request is cancelled, the result arrays are empty.
+ if (grantResults.length == PERMISSIONS_STORAGE.length && checkPermissions(grantResults)) {
+
+ // permission was granted, yay!
+ this.worldItemAdapter.enable();
+ } else {
+ // permission denied, boo! Disable the
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ TextView msg = new TextView(this);
+ float dpi = this.getResources().getDisplayMetrics().density;
+ msg.setPadding((int) (19 * dpi), (int) (5 * dpi), (int) (14 * dpi), (int) (5 * dpi));
+ msg.setMaxLines(20);
+ msg.setMovementMethod(LinkMovementMethod.getInstance());
+ msg.setText(R.string.no_sdcard_access);
+ builder.setView(msg)
+ .setTitle(R.string.action_help)
+ .setCancelable(true)
+ .setNeutralButton(android.R.string.ok, null)
+ .show();
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.world, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+
+ Bundle params = new Bundle();
+ int type;
+ switch (item.getItemId()) {
+ case R.id.action_open:
+ type = Log.ANA_PARAM_MAINACT_MENU_TYPE_OPEN;
+ break;
+ case R.id.action_help:
+ type = Log.ANA_PARAM_MAINACT_MENU_TYPE_HELP;
+ break;
+ case R.id.action_about:
+ type = Log.ANA_PARAM_MAINACT_MENU_TYPE_ABOUT;
+ break;
+ default:
+ type = 0;
+ }
+ params.putInt(Log.ANA_PARAM_MAINACT_MENU_TYPE, type);
+ Log.logFirebaseEvent(this, Log.CustomFirebaseEvent.MAINACT_MENU_OPEN, params);
+
+ //some text pop-up dialogs, some with simple HTML tags.
+ switch (item.getItemId()) {
+ case R.id.action_open: {
+ if (worldItemAdapter.isDisabled()) {
+ Snackbar.make(getWindow().getDecorView(), R.string.no_read_write_access, Snackbar.LENGTH_SHORT).show();
+ return true;
+ }
final EditText pathText = new EditText(WorldItemListActivity.this);
pathText.setHint(R.string.storage_path_here);
@@ -117,29 +267,29 @@ public void onClick(DialogInterface dialog, int whichButton) {
//new tag name
Editable pathEditable = pathText.getText();
String path = (pathEditable == null || pathEditable.toString().equals("")) ? null : pathEditable.toString();
- if(path == null){
+ if (path == null) {
return;//no path, no world
}
String levelDat = "/level.dat";
int levelIndex = path.lastIndexOf(levelDat);
//if the path ends with /level.dat, remove it!
- if(levelIndex >= 0 && path.endsWith(levelDat))
+ if (levelIndex >= 0 && path.endsWith(levelDat))
path = path.substring(0, levelIndex);
- String defaultPath = Environment.getExternalStorageDirectory().toString()+"/games/com.mojang/minecraftWorlds/";
+ String defaultPath = Environment.getExternalStorageDirectory().toString() + "/games/com.mojang/minecraftWorlds/";
File worldFolder = new File(path);
String errTitle = null, errMsg = String.format(getString(R.string.report_path_and_previous_search), path, defaultPath);
- if(!worldFolder.exists()){
+ if (!worldFolder.exists()) {
errTitle = getString(R.string.no_file_folder_found_at_path);
}
- if(!worldFolder.isDirectory()){
+ if (!worldFolder.isDirectory()) {
errTitle = getString(R.string.worldpath_is_not_directory);
}
- if(!(new File(worldFolder, "level.dat").exists())){
+ if (!(new File(worldFolder, "level.dat").exists())) {
errTitle = getString(R.string.no_level_dat_found);
}
- if(errTitle != null) {
+ if (errTitle != null) {
new AlertDialog.Builder(WorldItemListActivity.this)
.setTitle(errTitle)
.setMessage(errMsg)
@@ -149,7 +299,7 @@ public void onClick(DialogInterface dialog, int whichButton) {
} else {
try {
- World world = new World(worldFolder);
+ World world = new World(worldFolder, null, WorldItemListActivity.this);
if (mTwoPane) {
Bundle arguments = new Bundle();
@@ -166,8 +316,8 @@ public void onClick(DialogInterface dialog, int whichButton) {
WorldItemListActivity.this.startActivity(intent);
}
- } catch (Exception e){
- Snackbar.make(view, R.string.error_opening_world, Snackbar.LENGTH_SHORT)
+ } catch (Exception e) {
+ Snackbar.make(getWindow().getDecorView(), R.string.error_opening_world, Snackbar.LENGTH_SHORT)
.setAction("Action", null).show();
}
}
@@ -183,175 +333,145 @@ public void onClick(DialogInterface dialog, int whichButton) {
alert.show();
//TODO: browse for custom located world file, not everybody understands filesystem paths
+ //Then it also cannot find a world. --rbq2012.
+ return true;
}
- });
-
-
-
- if(verifyStoragePermissions(this)){
- //directly open the world list if we already have access
- initWorldList();
- }
-
-
- }
-
- public void initWorldList(){
-
- View recyclerView = findViewById(R.id.worlditem_list);
- assert recyclerView != null;
- boolean hasWorlds = setupRecyclerView((RecyclerView) recyclerView);
- if(!hasWorlds){
- Snackbar.make(recyclerView, R.string.could_not_find_worlds, Snackbar.LENGTH_SHORT)
- .setAction("Action", null).show();
- }
-
- }
-
-
- @Override
- public void onRequestPermissionsResult(int requestCode,
- @NonNull String permissions[], @NonNull int[] grantResults) {
- switch (requestCode) {
- case REQUEST_EXTERNAL_STORAGE: {
- // If request is cancelled, the result arrays are empty.
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-
- // permission was granted, yay!
- initWorldList();
-
- } else {
-
- // permission denied, boo! Disable the
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- TextView msg = new TextView(this);
- float dpi = this.getResources().getDisplayMetrics().density;
- msg.setPadding((int)(19*dpi), (int)(5*dpi), (int)(14*dpi), (int)(5*dpi));
- msg.setMaxLines(20);
- msg.setMovementMethod(LinkMovementMethod.getInstance());
- msg.setText(R.string.no_sdcard_access);
- builder.setView(msg)
- .setTitle(R.string.action_help)
- .setCancelable(true)
- .setNeutralButton(android.R.string.ok, null)
- .show();
- }
+ case R.id.action_about: {
+
+ android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this);
+ TextView msg = new TextView(this);
+ msg.setEllipsize(TextUtils.TruncateAt.MARQUEE);
+ float dpi = getResources().getDisplayMetrics().density;
+ msg.setPadding((int) (19 * dpi), (int) (5 * dpi), (int) (14 * dpi), (int) (5 * dpi));
+ msg.setMaxLines(20);
+ msg.setMovementMethod(LinkMovementMethod.getInstance());
+ msg.setText(R.string.app_about);
+ builder.setView(msg)
+ .setTitle(R.string.action_about)
+ .setCancelable(true)
+ .setNeutralButton(android.R.string.ok, null)
+ .show();
+
+ return true;
+ }
+ case R.id.action_help: {
+ android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this);
+ TextView msg = new TextView(this);
+ float dpi = getResources().getDisplayMetrics().density;
+ msg.setPadding((int) (19 * dpi), (int) (5 * dpi), (int) (14 * dpi), (int) (5 * dpi));
+ msg.setMaxLines(20);
+ msg.setMovementMethod(LinkMovementMethod.getInstance());
+ msg.setText(R.string.app_help);
+ builder.setView(msg)
+ .setTitle(R.string.action_help)
+ .setCancelable(true)
+ .setNeutralButton(android.R.string.ok, null)
+ .show();
+
+ return true;
+ }
+// case R.id.action_changelog: {
+// AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
+// TextView msg = new TextView(ctx);
+// float dpi = ctx.getResources().getDisplayMetrics().density;
+// msg.setPadding((int) (19 * dpi), (int) (5 * dpi), (int) (14 * dpi), (int) (5 * dpi));
+// msg.setMaxLines(20);
+// msg.setMovementMethod(LinkMovementMethod.getInstance());
+// String content = String.format(ctx.getResources().getString(R.string.app_changelog), BuildConfig.VERSION_NAME);
+// //noinspection deprecation
+// msg.setText(Html.fromHtml(content));
+// builder.setView(msg)
+// .setTitle(R.string.action_changelog)
+// .setCancelable(true)
+// .setNeutralButton(android.R.string.ok, null)
+// .show();
+//
+// return true;
+// }
+ default: {
+ return false;
}
}
}
-
-
- // Storage Permissions
- private static final int REQUEST_EXTERNAL_STORAGE = 4242;
- private static String[] PERMISSIONS_STORAGE = {
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE
- };
-
- /**
- * Checks if the app has permission to write to device storage
- *
- * If the app does not has permission then the user will be prompted to grant permissions
- *
- */
- public static boolean verifyStoragePermissions(Activity activity) {
- // Check if we have write permission
- int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
-
- if (permission != PackageManager.PERMISSION_GRANTED) {
- // We don't have permission so prompt the user
- ActivityCompat.requestPermissions(
- activity,
- PERMISSIONS_STORAGE,
- REQUEST_EXTERNAL_STORAGE
- );
- return false;
- } else return true;
- }
-
-
- //returns true if the list of worlds is not empty
- private boolean setupRecyclerView(@NonNull RecyclerView recyclerView) {
- this.worldItemAdapter = new WorldItemRecyclerViewAdapter();
- boolean hasWorlds = this.worldItemAdapter.reloadWorldList();
- recyclerView.setAdapter(this.worldItemAdapter);
- return hasWorlds;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.world, menu);
- return true;
- }
-
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
- return MenuHelper.onOptionsItemSelected(this, item);
- }
-
- @Override
- public Context getContext() {
- return this;
- }
-
- @Override
- public boolean propagateOnOptionsItemSelected(MenuItem item) {
- return super.onOptionsItemSelected(item);
+ protected void onResume() {
+ super.onResume();
+ worldItemAdapter.loadWorldList();
}
public class WorldItemRecyclerViewAdapter extends RecyclerView.Adapter {
- private final List mValues;
+ private final List mWorlds;
- private final File savesFolder;
+ private boolean disabled;
WorldItemRecyclerViewAdapter() {
- mValues = new ArrayList<>();
+ mWorlds = new ArrayList<>(16);
+ disabled = true;
+ }
- String path = Environment.getExternalStorageDirectory().toString()+"/games/com.mojang/minecraftWorlds/";
- Log.d("minecraftWorlds path: " + path);
+ void enable() {
+ disabled = false;
+ }
- this.savesFolder = new File(path);
+ public boolean isDisabled() {
+ return disabled;
}
//returns true if it has loaded a new list of worlds, false otherwise
- boolean reloadWorldList(){
- mValues.clear();
- File[] saves = savesFolder.exists() ? savesFolder.listFiles(new FileFilter() {
- @Override
- public boolean accept(File pathname) {
- return new File(pathname + "/level.dat").exists();
- }
- }) : null;
-
- if(saves != null) {
- Log.d("Number of minecraft worlds: " + saves.length);
-
- for (File save : saves) {
- //debug if we see all worlds
- Log.d("FileName: " + save.getName());
+ void loadWorldList() {
+ if (disabled) return;
+ mWorlds.clear();
+ List saveFolders;
+ List marks;
+ saveFolders = new ArrayList<>(4);
+ marks = new ArrayList<>(4);
+
+ File sd = Environment.getExternalStorageDirectory();
+
+ saveFolders.add(new File(sd, "games/com.mojang/minecraftWorlds"));
+ marks.add(null);
+
+ //noinspection ResultOfMethodCallIgnored
+ new File(sd, "Android/data").listFiles(
+ file -> {
+ if (file.getName().startsWith("com.netease")) {
+ File worldsFolder = new File(file, "files/minecraftWorlds");
+ if (worldsFolder.exists()) {
+ saveFolders.add(worldsFolder);
+ marks.add(getString(R.string.world_mark_neteas));
+ }
+ }
+ return false;
+ }
+ );
+ for (int i = 0, saveFoldersSize = saveFolders.size(); i < saveFoldersSize; i++) {
+ File dir = saveFolders.get(i);
+ File[] files = dir.listFiles(file -> {
+ if (!file.isDirectory()) return false;
+ return (new File(file, "level.dat").exists()
+ || new File(file, WorldBackups.BTG_BACKUPS).exists());
+ });
+ if (files != null) for (File f : files) {
try {
- mValues.add(new World(save));
+ mWorlds.add(new World(f, marks.get(i), WorldItemListActivity.this));
} catch (World.WorldLoadException e) {
- e.printStackTrace();
- Log.d("Skipping world while reloading world list: "
- + save.getName() + ", loading failed somehow, check stack trace");
+ Log.d(this, e);
}
}
}
- Collections.sort(mValues, new Comparator() {
+ Collections.sort(mWorlds, new Comparator() {
@Override
public int compare(World a, World b) {
try {
long tA = WorldListUtil.getLastPlayedTimestamp(a);
long tB = WorldListUtil.getLastPlayedTimestamp(b);
- return tA > tB ? -1 : (tA == tB ? 0 : 1);
+ return Long.compare(tB, tA);
} catch (Exception e) {
+ Log.d(this, e);
return 0;
}
}
@@ -360,72 +480,82 @@ public int compare(World a, World b) {
//load data into view
this.notifyDataSetChanged();
- return mValues.size() > 0;
+ if (mWorlds.size() == 0) {
+ AlertDialog dia = new AlertDialog.Builder(WorldItemListActivity.this)
+ .setTitle(R.string.err_noworld_1)
+ .setView(R.layout.dialog_noworlds)
+ .setPositiveButton(android.R.string.ok, null)
+ .create();
+ dia.show();
+ }
}
-
+ @NonNull
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.worlditem_list_content, parent, false);
return new ViewHolder(view);
}
-
@SuppressLint("SetTextI18n")
@Override
- public void onBindViewHolder(final ViewHolder holder, int position) {
- holder.mWorld = mValues.get(position);
+ public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
+ holder.mWorld = mWorlds.get(position);
holder.mWorldNameView.setText(holder.mWorld.getWorldDisplayName());
- holder.mWorldSize.setText(IOUtil.getFileSizeInText(holder.mWorld.worldFolder));
+ holder.mWorldSize.setText(IoUtil.getFileSizeInText(FileUtils.sizeOf(holder.mWorld.worldFolder)));
holder.mWorldGamemode.setText(WorldListUtil.getWorldGamemodeText(WorldItemListActivity.this, holder.mWorld));
holder.mWorldLastPlayed.setText(WorldListUtil.getLastPlayedText(WorldItemListActivity.this, holder.mWorld));
- holder.mWorldPath.setText(holder.mWorld.levelFile.getAbsolutePath());
-
+ holder.mWorldPath.setText(holder.mWorld.worldFolder.getName());
+ holder.mWorldMark.setText(holder.mWorld.mark);
+
+
+ holder.mView.setOnClickListener(v -> {
+ if (mTwoPane) {
+ Bundle arguments = new Bundle();
+ arguments.putSerializable(World.ARG_WORLD_SERIALIZED, holder.mWorld);
+ WorldItemDetailFragment fragment = new WorldItemDetailFragment();
+ fragment.setArguments(arguments);
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.worlditem_detail_container, fragment)
+ .commit();
+ } else {
+ Context context = v.getContext();
+ Intent intent = new Intent(context, WorldItemDetailActivity.class);
+ intent.putExtra(World.ARG_WORLD_SERIALIZED, holder.mWorld);
- holder.mView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mTwoPane) {
- Bundle arguments = new Bundle();
- arguments.putSerializable(World.ARG_WORLD_SERIALIZED, holder.mWorld);
- WorldItemDetailFragment fragment = new WorldItemDetailFragment();
- fragment.setArguments(arguments);
- getSupportFragmentManager().beginTransaction()
- .replace(R.id.worlditem_detail_container, fragment)
- .commit();
- } else {
- Context context = v.getContext();
- Intent intent = new Intent(context, WorldItemDetailActivity.class);
- intent.putExtra(World.ARG_WORLD_SERIALIZED, holder.mWorld);
-
- context.startActivity(intent);
- }
+ context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
- return mValues.size();
+ return mWorlds.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
final View mView;
- final TextView mWorldNameView, mWorldSize, mWorldGamemode, mWorldLastPlayed, mWorldPath;
+ final TextView mWorldNameView;
+ final TextView mWorldMark;
+ final TextView mWorldSize;
+ final TextView mWorldGamemode;
+ final TextView mWorldLastPlayed;
+ final TextView mWorldPath;
World mWorld;
ViewHolder(View view) {
super(view);
mView = view;
- mWorldNameView = (TextView) view.findViewById(R.id.world_name);
- mWorldSize = (TextView) view.findViewById(R.id.world_size);
- mWorldGamemode = (TextView) view.findViewById(R.id.world_gamemode);
- mWorldLastPlayed = (TextView) view.findViewById(R.id.world_last_played);
- mWorldPath = (TextView) view.findViewById(R.id.world_path);
+ mWorldNameView = view.findViewById(R.id.world_name);
+ mWorldMark = view.findViewById(R.id.world_mark);
+ mWorldSize = view.findViewById(R.id.world_size);
+ mWorldGamemode = view.findViewById(R.id.world_gamemode);
+ mWorldLastPlayed = view.findViewById(R.id.world_last_played);
+ mWorldPath = view.findViewById(R.id.world_path);
}
@Override
diff --git a/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldListUtil.java b/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldListUtil.java
index 523f88dc..db2efc5b 100644
--- a/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldListUtil.java
+++ b/app/src/main/java/com/mithrilmania/blocktopograph/worldlist/WorldListUtil.java
@@ -3,6 +3,7 @@
import android.content.Context;
+import com.mithrilmania.blocktopograph.Log;
import com.mithrilmania.blocktopograph.R;
import com.mithrilmania.blocktopograph.World;
@@ -10,41 +11,46 @@
public class WorldListUtil {
- public static long getLastPlayedTimestamp(World world){
+ public static long getLastPlayedTimestamp(World world) {
try {
- return (long) world.level.getChildTagByKey("LastPlayed").getValue();
- } catch (Exception e){
+ return (long) world.getLevel().getChildTagByKey("LastPlayed").getValue();
+ } catch (Exception e) {
+ Log.d(WorldListUtil.class, e);
return 0;
}
}
- public static String getLastPlayedText(Context context, World world){
+ public static String getLastPlayedText(Context context, World world) {
long lastPlayed = getLastPlayedTimestamp(world);
- if(lastPlayed == 0) return "?";
+ if (lastPlayed == 0) return "?";
DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context);
return dateFormat.format(lastPlayed * 1000);
}
- public static String getWorldGamemodeText(Context context, World world){
+ public static String getWorldGamemodeText(Context context, World world) {
String gameMode;
try {
- int gameType = (int) world.level.getChildTagByKey("GameType").getValue();
- switch (gameType){
- case 0: gameMode = context.getString(R.string.gamemode_survival);
+ int gameType = (int) world.getLevel().getChildTagByKey("GameType").getValue();
+ switch (gameType) {
+ case 0:
+ gameMode = context.getString(R.string.gamemode_survival);
break;
- case 1: gameMode = context.getString(R.string.gamemode_creative);
+ case 1:
+ gameMode = context.getString(R.string.gamemode_creative);
break;
- case 2: gameMode = context.getString(R.string.gamemode_adventure);
+ case 2:
+ gameMode = context.getString(R.string.gamemode_adventure);
break;
default:
gameMode = "?";
}
- } catch (Exception e){
- gameMode = "?";
+ } catch (Exception e) {
+ Log.d(WorldListUtil.class, e);
+ gameMode = "??";
}
return gameMode;
}
-
-
+
+
}
diff --git a/app/src/main/res/drawable-anydpi-v26/ic_launcher.xml b/app/src/main/res/drawable-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..bbd3e021
--- /dev/null
+++ b/app/src/main/res/drawable-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/drawable-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..bbd3e021
--- /dev/null
+++ b/app/src/main/res/drawable-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-hdpi/ic_action_arrow_right.png b/app/src/main/res/drawable-hdpi/ic_action_arrow_right.png
deleted file mode 100644
index 2a284516..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_arrow_right.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_compass.png b/app/src/main/res/drawable-hdpi/ic_action_compass.png
deleted file mode 100644
index 80f0034d..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_compass.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_exit.png b/app/src/main/res/drawable-hdpi/ic_action_exit.png
deleted file mode 100644
index 708c14ca..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_exit.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_filter.png b/app/src/main/res/drawable-hdpi/ic_action_filter.png
deleted file mode 100644
index f741f0f2..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_filter.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_home.png b/app/src/main/res/drawable-hdpi/ic_action_home.png
deleted file mode 100644
index 2d78b078..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_home.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_home_b.png b/app/src/main/res/drawable-hdpi/ic_action_home_b.png
deleted file mode 100644
index ba1e885b..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_home_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_list.png b/app/src/main/res/drawable-hdpi/ic_action_list.png
deleted file mode 100644
index b5f08e02..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_list.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_map.png b/app/src/main/res/drawable-hdpi/ic_action_map.png
deleted file mode 100644
index 39348d9b..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_map.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_map_b.png b/app/src/main/res/drawable-hdpi/ic_action_map_b.png
deleted file mode 100644
index f5f3b629..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_map_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_puzzle.png b/app/src/main/res/drawable-hdpi/ic_action_puzzle.png
deleted file mode 100644
index 3ed2e5a7..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_puzzle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_save.png b/app/src/main/res/drawable-hdpi/ic_action_save.png
deleted file mode 100644
index fe33819e..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_save.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_save_b.png b/app/src/main/res/drawable-hdpi/ic_action_save_b.png
deleted file mode 100644
index c06324e2..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_save_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_search.png b/app/src/main/res/drawable-hdpi/ic_action_search.png
deleted file mode 100644
index cf650604..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_search.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_action_settings.png b/app/src/main/res/drawable-hdpi/ic_action_settings.png
deleted file mode 100644
index b155a92c..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_action_settings.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_add_location.png b/app/src/main/res/drawable-hdpi/ic_add_location.png
deleted file mode 100644
index 9465d585..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_add_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_broken_image.png b/app/src/main/res/drawable-hdpi/ic_broken_image.png
deleted file mode 100644
index 5442156e..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_broken_image.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_bubble_chart.png b/app/src/main/res/drawable-hdpi/ic_bubble_chart.png
deleted file mode 100644
index e4f0c0e9..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_bubble_chart.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_developer_mode.png b/app/src/main/res/drawable-hdpi/ic_developer_mode.png
deleted file mode 100644
index 6b1df6f3..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_developer_mode.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_emoticon.png b/app/src/main/res/drawable-hdpi/ic_emoticon.png
deleted file mode 100644
index eb10be9b..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_emoticon.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_emoticon_b.png b/app/src/main/res/drawable-hdpi/ic_emoticon_b.png
deleted file mode 100644
index 82cf2090..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_emoticon_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_folder.png b/app/src/main/res/drawable-hdpi/ic_folder.png
deleted file mode 100644
index 018f1a3e..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_folder.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_folder_open.png b/app/src/main/res/drawable-hdpi/ic_folder_open.png
deleted file mode 100644
index 80dadb5a..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_folder_open.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_gps_fixed.png b/app/src/main/res/drawable-hdpi/ic_gps_fixed.png
deleted file mode 100644
index 70f10358..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_gps_fixed.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_gradient.png b/app/src/main/res/drawable-hdpi/ic_gradient.png
deleted file mode 100644
index 59cd3327..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_gradient.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_grid_on.png b/app/src/main/res/drawable-hdpi/ic_grid_on.png
deleted file mode 100644
index bb112cc4..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_grid_on.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_inventory.png b/app/src/main/res/drawable-hdpi/ic_inventory.png
deleted file mode 100644
index 6707c1c4..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_inventory.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_layers.png b/app/src/main/res/drawable-hdpi/ic_layers.png
deleted file mode 100644
index d44f2e79..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_layers.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_location.png b/app/src/main/res/drawable-hdpi/ic_location.png
deleted file mode 100644
index 20398c5a..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_nature_people.png b/app/src/main/res/drawable-hdpi/ic_nature_people.png
deleted file mode 100644
index 377c66f8..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_nature_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_people.png b/app/src/main/res/drawable-hdpi/ic_people.png
deleted file mode 100644
index 2eef401f..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_people_outline.png b/app/src/main/res/drawable-hdpi/ic_people_outline.png
deleted file mode 100644
index f52c4c24..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_people_outline.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_person.png b/app/src/main/res/drawable-hdpi/ic_person.png
deleted file mode 100644
index faad1f66..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_person.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_person_pin_circle.png b/app/src/main/res/drawable-hdpi/ic_person_pin_circle.png
deleted file mode 100644
index d5ea7161..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_person_pin_circle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_place.png b/app/src/main/res/drawable-hdpi/ic_place.png
deleted file mode 100644
index c214dc24..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_place.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_player.png b/app/src/main/res/drawable-hdpi/ic_player.png
deleted file mode 100644
index 65974a22..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_player.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_priority_high.png b/app/src/main/res/drawable-hdpi/ic_priority_high.png
deleted file mode 100644
index 54ddd735..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_priority_high.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_refresh.png b/app/src/main/res/drawable-hdpi/ic_refresh.png
deleted file mode 100644
index ac7f012e..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_refresh.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_satellite.png b/app/src/main/res/drawable-hdpi/ic_satellite.png
deleted file mode 100644
index 37c0c546..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_satellite.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_settings_brightness.png b/app/src/main/res/drawable-hdpi/ic_settings_brightness.png
deleted file mode 100644
index 19058a99..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_settings_brightness.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_terrain.png b/app/src/main/res/drawable-hdpi/ic_terrain.png
deleted file mode 100644
index 3b8492c8..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_terrain.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_visibility.png b/app/src/main/res/drawable-hdpi/ic_visibility.png
deleted file mode 100644
index 8d7ba24b..00000000
Binary files a/app/src/main/res/drawable-hdpi/ic_visibility.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_arrow_right.png b/app/src/main/res/drawable-mdpi/ic_action_arrow_right.png
deleted file mode 100644
index e52be1e4..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_arrow_right.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_compass.png b/app/src/main/res/drawable-mdpi/ic_action_compass.png
deleted file mode 100644
index e8bce9dd..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_compass.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_exit.png b/app/src/main/res/drawable-mdpi/ic_action_exit.png
deleted file mode 100644
index b58f15aa..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_exit.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_filter.png b/app/src/main/res/drawable-mdpi/ic_action_filter.png
deleted file mode 100644
index e2a95775..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_filter.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_home.png b/app/src/main/res/drawable-mdpi/ic_action_home.png
deleted file mode 100644
index 723db82c..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_home.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_home_b.png b/app/src/main/res/drawable-mdpi/ic_action_home_b.png
deleted file mode 100644
index 12915c6c..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_home_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_list.png b/app/src/main/res/drawable-mdpi/ic_action_list.png
deleted file mode 100644
index 13305ef3..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_list.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_map.png b/app/src/main/res/drawable-mdpi/ic_action_map.png
deleted file mode 100644
index a2aa7501..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_map.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_map_b.png b/app/src/main/res/drawable-mdpi/ic_action_map_b.png
deleted file mode 100644
index 3adc16ee..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_map_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_puzzle.png b/app/src/main/res/drawable-mdpi/ic_action_puzzle.png
deleted file mode 100644
index 71261860..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_puzzle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_save.png b/app/src/main/res/drawable-mdpi/ic_action_save.png
deleted file mode 100644
index 59037c47..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_save.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_save_b.png b/app/src/main/res/drawable-mdpi/ic_action_save_b.png
deleted file mode 100644
index 4ba840e2..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_save_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_search.png b/app/src/main/res/drawable-mdpi/ic_action_search.png
deleted file mode 100644
index b0127b46..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_search.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_settings.png b/app/src/main/res/drawable-mdpi/ic_action_settings.png
deleted file mode 100644
index a79b3eeb..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_action_settings.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_add_location.png b/app/src/main/res/drawable-mdpi/ic_add_location.png
deleted file mode 100644
index 4f6e90b6..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_add_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_broken_image.png b/app/src/main/res/drawable-mdpi/ic_broken_image.png
deleted file mode 100644
index 0b5500b7..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_broken_image.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_bubble_chart.png b/app/src/main/res/drawable-mdpi/ic_bubble_chart.png
deleted file mode 100644
index b3589859..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_bubble_chart.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_developer_mode.png b/app/src/main/res/drawable-mdpi/ic_developer_mode.png
deleted file mode 100644
index 25ec6743..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_developer_mode.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_emoticon.png b/app/src/main/res/drawable-mdpi/ic_emoticon.png
deleted file mode 100644
index f8e42f43..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_emoticon.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_emoticon_b.png b/app/src/main/res/drawable-mdpi/ic_emoticon_b.png
deleted file mode 100644
index c1907699..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_emoticon_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_folder.png b/app/src/main/res/drawable-mdpi/ic_folder.png
deleted file mode 100644
index ddf9a2b8..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_folder.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_folder_open.png b/app/src/main/res/drawable-mdpi/ic_folder_open.png
deleted file mode 100644
index 93d392a5..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_folder_open.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_gps_fixed.png b/app/src/main/res/drawable-mdpi/ic_gps_fixed.png
deleted file mode 100644
index bf843aef..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_gps_fixed.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_gradient.png b/app/src/main/res/drawable-mdpi/ic_gradient.png
deleted file mode 100644
index e8270ab7..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_gradient.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_grid_on.png b/app/src/main/res/drawable-mdpi/ic_grid_on.png
deleted file mode 100644
index 26be8f6e..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_grid_on.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_inventory.png b/app/src/main/res/drawable-mdpi/ic_inventory.png
deleted file mode 100644
index 94a3cebb..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_inventory.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_layers.png b/app/src/main/res/drawable-mdpi/ic_layers.png
deleted file mode 100644
index ce0a1d66..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_layers.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_location.png b/app/src/main/res/drawable-mdpi/ic_location.png
deleted file mode 100644
index ea09c20c..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_nature_people.png b/app/src/main/res/drawable-mdpi/ic_nature_people.png
deleted file mode 100644
index 3bd7331d..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_nature_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_people.png b/app/src/main/res/drawable-mdpi/ic_people.png
deleted file mode 100644
index f96ff97c..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_people_outline.png b/app/src/main/res/drawable-mdpi/ic_people_outline.png
deleted file mode 100644
index f21b20f4..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_people_outline.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_person.png b/app/src/main/res/drawable-mdpi/ic_person.png
deleted file mode 100644
index bf0a0a9b..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_person.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_person_pin_circle.png b/app/src/main/res/drawable-mdpi/ic_person_pin_circle.png
deleted file mode 100644
index 7f65e98d..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_person_pin_circle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_place.png b/app/src/main/res/drawable-mdpi/ic_place.png
deleted file mode 100644
index 0eab6f62..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_place.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_player.png b/app/src/main/res/drawable-mdpi/ic_player.png
deleted file mode 100644
index bb8eb79c..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_player.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_priority_high.png b/app/src/main/res/drawable-mdpi/ic_priority_high.png
deleted file mode 100644
index 6e16c7e6..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_priority_high.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_refresh.png b/app/src/main/res/drawable-mdpi/ic_refresh.png
deleted file mode 100644
index 52b28511..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_refresh.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_satellite.png b/app/src/main/res/drawable-mdpi/ic_satellite.png
deleted file mode 100644
index d7a874a9..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_satellite.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_settings_brightness.png b/app/src/main/res/drawable-mdpi/ic_settings_brightness.png
deleted file mode 100644
index 8959ff56..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_settings_brightness.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_terrain.png b/app/src/main/res/drawable-mdpi/ic_terrain.png
deleted file mode 100644
index a50bd547..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_terrain.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_visibility.png b/app/src/main/res/drawable-mdpi/ic_visibility.png
deleted file mode 100644
index 77f9881e..00000000
Binary files a/app/src/main/res/drawable-mdpi/ic_visibility.png and /dev/null differ
diff --git a/app/src/main/res/drawable-v21/sel_item_flat_layer.xml b/app/src/main/res/drawable-v21/sel_item_flat_layer.xml
new file mode 100644
index 00000000..fd29166d
--- /dev/null
+++ b/app/src/main/res/drawable-v21/sel_item_flat_layer.xml
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_arrow_right.png b/app/src/main/res/drawable-xhdpi/ic_action_arrow_right.png
deleted file mode 100644
index 8754506f..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_arrow_right.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_compass.png b/app/src/main/res/drawable-xhdpi/ic_action_compass.png
deleted file mode 100644
index a898960c..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_compass.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_exit.png b/app/src/main/res/drawable-xhdpi/ic_action_exit.png
deleted file mode 100644
index a6c2c626..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_exit.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_filter.png b/app/src/main/res/drawable-xhdpi/ic_action_filter.png
deleted file mode 100644
index 8a38718c..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_filter.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_home.png b/app/src/main/res/drawable-xhdpi/ic_action_home.png
deleted file mode 100644
index 0da2557a..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_home.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_home_b.png b/app/src/main/res/drawable-xhdpi/ic_action_home_b.png
deleted file mode 100644
index 4417d8fc..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_home_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_list.png b/app/src/main/res/drawable-xhdpi/ic_action_list.png
deleted file mode 100644
index b82b76a2..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_list.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_map.png b/app/src/main/res/drawable-xhdpi/ic_action_map.png
deleted file mode 100644
index b9dfeaf5..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_map.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_map_b.png b/app/src/main/res/drawable-xhdpi/ic_action_map_b.png
deleted file mode 100644
index f357cc2f..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_map_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_puzzle.png b/app/src/main/res/drawable-xhdpi/ic_action_puzzle.png
deleted file mode 100644
index 074a6bea..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_puzzle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_save.png b/app/src/main/res/drawable-xhdpi/ic_action_save.png
deleted file mode 100644
index d71055b9..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_save.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_save_b.png b/app/src/main/res/drawable-xhdpi/ic_action_save_b.png
deleted file mode 100644
index e4edfce6..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_save_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_search.png b/app/src/main/res/drawable-xhdpi/ic_action_search.png
deleted file mode 100644
index 565bf1c0..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_search.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_settings.png b/app/src/main/res/drawable-xhdpi/ic_action_settings.png
deleted file mode 100644
index ce6d809e..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_action_settings.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_add_location.png b/app/src/main/res/drawable-xhdpi/ic_add_location.png
deleted file mode 100644
index 68a65cd2..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_add_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_broken_image.png b/app/src/main/res/drawable-xhdpi/ic_broken_image.png
deleted file mode 100644
index ebc326cf..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_broken_image.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_bubble_chart.png b/app/src/main/res/drawable-xhdpi/ic_bubble_chart.png
deleted file mode 100644
index 728d9f23..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_bubble_chart.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_developer_mode.png b/app/src/main/res/drawable-xhdpi/ic_developer_mode.png
deleted file mode 100644
index 0099487f..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_developer_mode.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_emoticon.png b/app/src/main/res/drawable-xhdpi/ic_emoticon.png
deleted file mode 100644
index 8eb98cc0..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_emoticon.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_emoticon_b.png b/app/src/main/res/drawable-xhdpi/ic_emoticon_b.png
deleted file mode 100644
index 4095695a..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_emoticon_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_folder.png b/app/src/main/res/drawable-xhdpi/ic_folder.png
deleted file mode 100644
index 9d443177..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_folder.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_open.png b/app/src/main/res/drawable-xhdpi/ic_folder_open.png
deleted file mode 100644
index fc368ae0..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_folder_open.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_gps_fixed.png b/app/src/main/res/drawable-xhdpi/ic_gps_fixed.png
deleted file mode 100644
index c2d95aab..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_gps_fixed.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_gradient.png b/app/src/main/res/drawable-xhdpi/ic_gradient.png
deleted file mode 100644
index ebfe3690..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_gradient.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_grid_on.png b/app/src/main/res/drawable-xhdpi/ic_grid_on.png
deleted file mode 100644
index 513094a3..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_grid_on.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_inventory.png b/app/src/main/res/drawable-xhdpi/ic_inventory.png
deleted file mode 100644
index f3346fcb..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_inventory.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_layers.png b/app/src/main/res/drawable-xhdpi/ic_layers.png
deleted file mode 100644
index 068ca079..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_layers.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_location.png b/app/src/main/res/drawable-xhdpi/ic_location.png
deleted file mode 100644
index a04ea84c..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_nature_people.png b/app/src/main/res/drawable-xhdpi/ic_nature_people.png
deleted file mode 100644
index e4a3189e..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_nature_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_people.png b/app/src/main/res/drawable-xhdpi/ic_people.png
deleted file mode 100644
index 3c31252a..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_people_outline.png b/app/src/main/res/drawable-xhdpi/ic_people_outline.png
deleted file mode 100644
index 9de962a9..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_people_outline.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_person.png b/app/src/main/res/drawable-xhdpi/ic_person.png
deleted file mode 100644
index ae93a3f0..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_person.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_person_pin_circle.png b/app/src/main/res/drawable-xhdpi/ic_person_pin_circle.png
deleted file mode 100644
index 8fb27e29..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_person_pin_circle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_place.png b/app/src/main/res/drawable-xhdpi/ic_place.png
deleted file mode 100644
index b21efe74..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_place.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_player.png b/app/src/main/res/drawable-xhdpi/ic_player.png
deleted file mode 100644
index d9f5151b..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_player.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_priority_high.png b/app/src/main/res/drawable-xhdpi/ic_priority_high.png
deleted file mode 100644
index 775a376f..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_priority_high.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_refresh.png b/app/src/main/res/drawable-xhdpi/ic_refresh.png
deleted file mode 100644
index 6d4481ff..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_refresh.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_satellite.png b/app/src/main/res/drawable-xhdpi/ic_satellite.png
deleted file mode 100644
index e4ab18d2..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_satellite.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_settings_brightness.png b/app/src/main/res/drawable-xhdpi/ic_settings_brightness.png
deleted file mode 100644
index 00bbe1ee..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_settings_brightness.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_terrain.png b/app/src/main/res/drawable-xhdpi/ic_terrain.png
deleted file mode 100644
index ca568725..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_terrain.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_visibility.png b/app/src/main/res/drawable-xhdpi/ic_visibility.png
deleted file mode 100644
index 8027ea01..00000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_visibility.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_arrow_right.png b/app/src/main/res/drawable-xxhdpi/ic_action_arrow_right.png
deleted file mode 100644
index be62f58d..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_arrow_right.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_compass.png b/app/src/main/res/drawable-xxhdpi/ic_action_compass.png
deleted file mode 100644
index 2e6094b0..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_compass.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_exit.png b/app/src/main/res/drawable-xxhdpi/ic_action_exit.png
deleted file mode 100644
index 85c41bfa..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_exit.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_filter.png b/app/src/main/res/drawable-xxhdpi/ic_action_filter.png
deleted file mode 100644
index 105aeb87..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_filter.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_home.png b/app/src/main/res/drawable-xxhdpi/ic_action_home.png
deleted file mode 100644
index 34b925fe..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_home.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_home_b.png b/app/src/main/res/drawable-xxhdpi/ic_action_home_b.png
deleted file mode 100644
index 378a25f4..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_home_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_list.png b/app/src/main/res/drawable-xxhdpi/ic_action_list.png
deleted file mode 100644
index cfc2e129..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_list.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_map.png b/app/src/main/res/drawable-xxhdpi/ic_action_map.png
deleted file mode 100644
index 8c379b0d..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_map.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_map_b.png b/app/src/main/res/drawable-xxhdpi/ic_action_map_b.png
deleted file mode 100644
index c431e66f..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_map_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_puzzle.png b/app/src/main/res/drawable-xxhdpi/ic_action_puzzle.png
deleted file mode 100644
index 1d6404e7..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_puzzle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_save.png b/app/src/main/res/drawable-xxhdpi/ic_action_save.png
deleted file mode 100644
index 272e2b67..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_save.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_save_b.png b/app/src/main/res/drawable-xxhdpi/ic_action_save_b.png
deleted file mode 100644
index 3ede5aa3..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_save_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_search.png b/app/src/main/res/drawable-xxhdpi/ic_action_search.png
deleted file mode 100644
index dab65748..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_search.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_settings.png b/app/src/main/res/drawable-xxhdpi/ic_action_settings.png
deleted file mode 100644
index fa688070..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_action_settings.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_add_location.png b/app/src/main/res/drawable-xxhdpi/ic_add_location.png
deleted file mode 100644
index e447a33b..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_add_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_broken_image.png b/app/src/main/res/drawable-xxhdpi/ic_broken_image.png
deleted file mode 100644
index 6e43d542..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_broken_image.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_bubble_chart.png b/app/src/main/res/drawable-xxhdpi/ic_bubble_chart.png
deleted file mode 100644
index 81a9f543..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_bubble_chart.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_developer_mode.png b/app/src/main/res/drawable-xxhdpi/ic_developer_mode.png
deleted file mode 100644
index d0e74a90..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_developer_mode.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_emoticon.png b/app/src/main/res/drawable-xxhdpi/ic_emoticon.png
deleted file mode 100644
index 872afdf7..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_emoticon.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_emoticon_b.png b/app/src/main/res/drawable-xxhdpi/ic_emoticon_b.png
deleted file mode 100644
index e38b00e8..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_emoticon_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder.png b/app/src/main/res/drawable-xxhdpi/ic_folder.png
deleted file mode 100644
index 5f6849d9..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_folder.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_open.png b/app/src/main/res/drawable-xxhdpi/ic_folder_open.png
deleted file mode 100644
index 2b4080b3..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_folder_open.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_gps_fixed.png b/app/src/main/res/drawable-xxhdpi/ic_gps_fixed.png
deleted file mode 100644
index 9eaa5c24..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_gps_fixed.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_gradient.png b/app/src/main/res/drawable-xxhdpi/ic_gradient.png
deleted file mode 100644
index 935aa3e7..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_gradient.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_grid_on.png b/app/src/main/res/drawable-xxhdpi/ic_grid_on.png
deleted file mode 100644
index da4bb8ef..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_grid_on.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_inventory.png b/app/src/main/res/drawable-xxhdpi/ic_inventory.png
deleted file mode 100644
index c68ec1af..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_inventory.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_layers.png b/app/src/main/res/drawable-xxhdpi/ic_layers.png
deleted file mode 100644
index 35f9641c..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_layers.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_location.png b/app/src/main/res/drawable-xxhdpi/ic_location.png
deleted file mode 100644
index b910fa7e..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_nature_people.png b/app/src/main/res/drawable-xxhdpi/ic_nature_people.png
deleted file mode 100644
index a4a92605..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_nature_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_people.png b/app/src/main/res/drawable-xxhdpi/ic_people.png
deleted file mode 100644
index 178fb0f9..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_people_outline.png b/app/src/main/res/drawable-xxhdpi/ic_people_outline.png
deleted file mode 100644
index 61fd11b7..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_people_outline.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_person.png b/app/src/main/res/drawable-xxhdpi/ic_person.png
deleted file mode 100644
index 17739498..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_person.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_person_pin_circle.png b/app/src/main/res/drawable-xxhdpi/ic_person_pin_circle.png
deleted file mode 100644
index 531f52c2..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_person_pin_circle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_place.png b/app/src/main/res/drawable-xxhdpi/ic_place.png
deleted file mode 100644
index 96274de7..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_place.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_player.png b/app/src/main/res/drawable-xxhdpi/ic_player.png
deleted file mode 100644
index 512bb670..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_player.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_priority_high.png b/app/src/main/res/drawable-xxhdpi/ic_priority_high.png
deleted file mode 100644
index cd331e9e..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_priority_high.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_refresh.png b/app/src/main/res/drawable-xxhdpi/ic_refresh.png
deleted file mode 100644
index f65e33f7..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_refresh.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_satellite.png b/app/src/main/res/drawable-xxhdpi/ic_satellite.png
deleted file mode 100644
index 2eeae828..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_satellite.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_settings_brightness.png b/app/src/main/res/drawable-xxhdpi/ic_settings_brightness.png
deleted file mode 100644
index d1b1e8d5..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_settings_brightness.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_terrain.png b/app/src/main/res/drawable-xxhdpi/ic_terrain.png
deleted file mode 100644
index a3ba2b30..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_terrain.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_visibility.png b/app/src/main/res/drawable-xxhdpi/ic_visibility.png
deleted file mode 100644
index 89bfc0f0..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_visibility.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_arrow_right.png b/app/src/main/res/drawable-xxxhdpi/ic_action_arrow_right.png
deleted file mode 100644
index 7141d106..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_arrow_right.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_compass.png b/app/src/main/res/drawable-xxxhdpi/ic_action_compass.png
deleted file mode 100644
index 6b655b7a..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_compass.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_exit.png b/app/src/main/res/drawable-xxxhdpi/ic_action_exit.png
deleted file mode 100644
index 11ff926d..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_exit.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_filter.png b/app/src/main/res/drawable-xxxhdpi/ic_action_filter.png
deleted file mode 100644
index 502a25c9..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_filter.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_home.png b/app/src/main/res/drawable-xxxhdpi/ic_action_home.png
deleted file mode 100644
index 7d06055e..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_home.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_home_b.png b/app/src/main/res/drawable-xxxhdpi/ic_action_home_b.png
deleted file mode 100644
index 2ff62077..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_home_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_list.png b/app/src/main/res/drawable-xxxhdpi/ic_action_list.png
deleted file mode 100644
index cddbeb4f..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_list.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_map.png b/app/src/main/res/drawable-xxxhdpi/ic_action_map.png
deleted file mode 100644
index a18b2c53..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_map.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_map_b.png b/app/src/main/res/drawable-xxxhdpi/ic_action_map_b.png
deleted file mode 100644
index 6ed462d7..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_map_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_puzzle.png b/app/src/main/res/drawable-xxxhdpi/ic_action_puzzle.png
deleted file mode 100644
index 81951bd3..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_puzzle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_save.png b/app/src/main/res/drawable-xxxhdpi/ic_action_save.png
deleted file mode 100644
index efe6b14f..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_save.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_save_b.png b/app/src/main/res/drawable-xxxhdpi/ic_action_save_b.png
deleted file mode 100644
index abc8499c..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_save_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_search.png b/app/src/main/res/drawable-xxxhdpi/ic_action_search.png
deleted file mode 100644
index c461e244..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_search.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_settings.png b/app/src/main/res/drawable-xxxhdpi/ic_action_settings.png
deleted file mode 100644
index a1168939..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_action_settings.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_add_location.png b/app/src/main/res/drawable-xxxhdpi/ic_add_location.png
deleted file mode 100644
index 5f540f42..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_add_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_broken_image.png b/app/src/main/res/drawable-xxxhdpi/ic_broken_image.png
deleted file mode 100644
index 68c4b97c..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_broken_image.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_bubble_chart.png b/app/src/main/res/drawable-xxxhdpi/ic_bubble_chart.png
deleted file mode 100644
index f6ec6a56..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_bubble_chart.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_developer_mode.png b/app/src/main/res/drawable-xxxhdpi/ic_developer_mode.png
deleted file mode 100644
index d01db080..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_developer_mode.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_emoticon.png b/app/src/main/res/drawable-xxxhdpi/ic_emoticon.png
deleted file mode 100644
index 1597b695..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_emoticon.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_emoticon_b.png b/app/src/main/res/drawable-xxxhdpi/ic_emoticon_b.png
deleted file mode 100644
index 2287afb0..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_emoticon_b.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder.png b/app/src/main/res/drawable-xxxhdpi/ic_folder.png
deleted file mode 100644
index 16e9e093..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_folder.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_open.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_open.png
deleted file mode 100644
index a14d8952..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_folder_open.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_gps_fixed.png b/app/src/main/res/drawable-xxxhdpi/ic_gps_fixed.png
deleted file mode 100644
index 7f588a26..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_gps_fixed.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_gradient.png b/app/src/main/res/drawable-xxxhdpi/ic_gradient.png
deleted file mode 100644
index eb683c1a..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_gradient.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_grid_on.png b/app/src/main/res/drawable-xxxhdpi/ic_grid_on.png
deleted file mode 100644
index a8c41f3e..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_grid_on.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_inventory.png b/app/src/main/res/drawable-xxxhdpi/ic_inventory.png
deleted file mode 100644
index 43be3f25..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_inventory.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_layers.png b/app/src/main/res/drawable-xxxhdpi/ic_layers.png
deleted file mode 100644
index 2fde17c5..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_layers.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_location.png b/app/src/main/res/drawable-xxxhdpi/ic_location.png
deleted file mode 100644
index c6bdce60..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_location.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_nature_people.png b/app/src/main/res/drawable-xxxhdpi/ic_nature_people.png
deleted file mode 100644
index 7470ff1a..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_nature_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_people.png b/app/src/main/res/drawable-xxxhdpi/ic_people.png
deleted file mode 100644
index 911c4b52..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_people.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_people_outline.png b/app/src/main/res/drawable-xxxhdpi/ic_people_outline.png
deleted file mode 100644
index e57ae0fc..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_people_outline.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_person.png b/app/src/main/res/drawable-xxxhdpi/ic_person.png
deleted file mode 100644
index c1e75b4d..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_person.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_person_pin_circle.png b/app/src/main/res/drawable-xxxhdpi/ic_person_pin_circle.png
deleted file mode 100644
index 5c83a95e..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_person_pin_circle.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_place.png b/app/src/main/res/drawable-xxxhdpi/ic_place.png
deleted file mode 100644
index ba0538e1..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_place.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_player.png b/app/src/main/res/drawable-xxxhdpi/ic_player.png
deleted file mode 100644
index e7398b08..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_player.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_priority_high.png b/app/src/main/res/drawable-xxxhdpi/ic_priority_high.png
deleted file mode 100644
index fc335f4c..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_priority_high.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_refresh.png b/app/src/main/res/drawable-xxxhdpi/ic_refresh.png
deleted file mode 100644
index 455000ed..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_refresh.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_satellite.png b/app/src/main/res/drawable-xxxhdpi/ic_satellite.png
deleted file mode 100644
index fdcdfb31..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_satellite.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_settings_brightness.png b/app/src/main/res/drawable-xxxhdpi/ic_settings_brightness.png
deleted file mode 100644
index c7f9f208..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_settings_brightness.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_terrain.png b/app/src/main/res/drawable-xxxhdpi/ic_terrain.png
deleted file mode 100644
index 347669d1..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_terrain.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_visibility.png b/app/src/main/res/drawable-xxxhdpi/ic_visibility.png
deleted file mode 100644
index 5aa86dec..00000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_visibility.png and /dev/null differ
diff --git a/app/src/main/res/drawable/bg_dialog_transparent.xml b/app/src/main/res/drawable/bg_dialog_transparent.xml
new file mode 100644
index 00000000..ef02075d
--- /dev/null
+++ b/app/src/main/res/drawable/bg_dialog_transparent.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_fab_transparent.xml b/app/src/main/res/drawable/bg_fab_transparent.xml
new file mode 100644
index 00000000..3b878a13
--- /dev/null
+++ b/app/src/main/res/drawable/bg_fab_transparent.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_float_transparent.xml b/app/src/main/res/drawable/bg_float_transparent.xml
new file mode 100644
index 00000000..bf4e94f3
--- /dev/null
+++ b/app/src/main/res/drawable/bg_float_transparent.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/external.png b/app/src/main/res/drawable/external.png
new file mode 100644
index 00000000..45fba9e8
Binary files /dev/null and b/app/src/main/res/drawable/external.png differ
diff --git a/app/src/main/res/drawable/ic_action_arrow_right.xml b/app/src/main/res/drawable/ic_action_arrow_right.xml
new file mode 100644
index 00000000..f8f4650c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_arrow_right.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_close.xml b/app/src/main/res/drawable/ic_action_close.xml
new file mode 100644
index 00000000..914246e2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_close.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_exit.xml b/app/src/main/res/drawable/ic_action_exit.xml
new file mode 100644
index 00000000..2c3b9778
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_exit.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_filter.xml b/app/src/main/res/drawable/ic_action_filter.xml
new file mode 100644
index 00000000..41a72184
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_filter.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_home.xml b/app/src/main/res/drawable/ic_action_home.xml
new file mode 100644
index 00000000..98ee1341
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_home.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_home_b.xml b/app/src/main/res/drawable/ic_action_home_b.xml
new file mode 100644
index 00000000..8e5a6fb8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_home_b.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_list.xml b/app/src/main/res/drawable/ic_action_list.xml
new file mode 100644
index 00000000..e29491cc
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_list.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_map.xml b/app/src/main/res/drawable/ic_action_map.xml
new file mode 100644
index 00000000..fbe75e9e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_map.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_map_b.xml b/app/src/main/res/drawable/ic_action_map_b.xml
new file mode 100644
index 00000000..ec0acbb1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_map_b.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_puzzle.xml b/app/src/main/res/drawable/ic_action_puzzle.xml
new file mode 100644
index 00000000..85ea9e69
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_puzzle.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_save.xml b/app/src/main/res/drawable/ic_action_save.xml
new file mode 100644
index 00000000..5ed3c6e3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_save.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_save_b.xml b/app/src/main/res/drawable/ic_action_save_b.xml
new file mode 100644
index 00000000..19d1ecb8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_save_b.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_search.xml b/app/src/main/res/drawable/ic_action_search.xml
new file mode 100644
index 00000000..fd21d7c0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_search.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_search_black.xml b/app/src/main/res/drawable/ic_action_search_black.xml
new file mode 100644
index 00000000..4b467960
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_search_black.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_settings.xml b/app/src/main/res/drawable/ic_action_settings.xml
new file mode 100644
index 00000000..601bcb51
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_settings.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml
new file mode 100644
index 00000000..834ff462
--- /dev/null
+++ b/app/src/main/res/drawable/ic_add.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml
new file mode 100644
index 00000000..dd959826
--- /dev/null
+++ b/app/src/main/res/drawable/ic_add_black.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_broken_image.xml b/app/src/main/res/drawable/ic_broken_image.xml
new file mode 100644
index 00000000..42a12c08
--- /dev/null
+++ b/app/src/main/res/drawable/ic_broken_image.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_bubble_chart.xml b/app/src/main/res/drawable/ic_bubble_chart.xml
new file mode 100644
index 00000000..13c627cc
--- /dev/null
+++ b/app/src/main/res/drawable/ic_bubble_chart.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_emoticon.xml b/app/src/main/res/drawable/ic_emoticon.xml
new file mode 100644
index 00000000..2a1d9034
--- /dev/null
+++ b/app/src/main/res/drawable/ic_emoticon.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_folder_open.xml b/app/src/main/res/drawable/ic_folder_open.xml
new file mode 100644
index 00000000..559c7e36
--- /dev/null
+++ b/app/src/main/res/drawable/ic_folder_open.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_gps_fixed.xml b/app/src/main/res/drawable/ic_gps_fixed.xml
new file mode 100644
index 00000000..ca15beab
--- /dev/null
+++ b/app/src/main/res/drawable/ic_gps_fixed.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_gradient.xml b/app/src/main/res/drawable/ic_gradient.xml
new file mode 100644
index 00000000..1f77438a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_gradient.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_grid_on.xml b/app/src/main/res/drawable/ic_grid_on.xml
new file mode 100644
index 00000000..12dbc651
--- /dev/null
+++ b/app/src/main/res/drawable/ic_grid_on.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_help_black.xml b/app/src/main/res/drawable/ic_help_black.xml
new file mode 100644
index 00000000..b0af2467
--- /dev/null
+++ b/app/src/main/res/drawable/ic_help_black.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_inventory.xml b/app/src/main/res/drawable/ic_inventory.xml
new file mode 100644
index 00000000..7d164a0e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_inventory.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..0d60f2b8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 00000000..90570271
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_layers.xml b/app/src/main/res/drawable/ic_layers.xml
new file mode 100644
index 00000000..a99b97cd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_layers.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_location.xml b/app/src/main/res/drawable/ic_location.xml
new file mode 100644
index 00000000..c2521a2e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_location.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable-v21/ic_menu_camera.xml b/app/src/main/res/drawable/ic_menu_camera.xml
similarity index 75%
rename from app/src/main/res/drawable-v21/ic_menu_camera.xml
rename to app/src/main/res/drawable/ic_menu_camera.xml
index 0d9ea104..6b1b8e21 100644
--- a/app/src/main/res/drawable-v21/ic_menu_camera.xml
+++ b/app/src/main/res/drawable/ic_menu_camera.xml
@@ -1,12 +1,12 @@
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
diff --git a/app/src/main/res/drawable/ic_menu_camera_black.xml b/app/src/main/res/drawable/ic_menu_camera_black.xml
new file mode 100644
index 00000000..634fe922
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu_camera_black.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable-v21/ic_menu_gallery.xml b/app/src/main/res/drawable/ic_menu_gallery.xml
similarity index 100%
rename from app/src/main/res/drawable-v21/ic_menu_gallery.xml
rename to app/src/main/res/drawable/ic_menu_gallery.xml
diff --git a/app/src/main/res/drawable-v21/ic_menu_manage.xml b/app/src/main/res/drawable/ic_menu_manage.xml
similarity index 100%
rename from app/src/main/res/drawable-v21/ic_menu_manage.xml
rename to app/src/main/res/drawable/ic_menu_manage.xml
diff --git a/app/src/main/res/drawable-v21/ic_menu_send.xml b/app/src/main/res/drawable/ic_menu_send.xml
similarity index 100%
rename from app/src/main/res/drawable-v21/ic_menu_send.xml
rename to app/src/main/res/drawable/ic_menu_send.xml
diff --git a/app/src/main/res/drawable-v21/ic_menu_share.xml b/app/src/main/res/drawable/ic_menu_share.xml
similarity index 100%
rename from app/src/main/res/drawable-v21/ic_menu_share.xml
rename to app/src/main/res/drawable/ic_menu_share.xml
diff --git a/app/src/main/res/drawable-v21/ic_menu_slideshow.xml b/app/src/main/res/drawable/ic_menu_slideshow.xml
similarity index 100%
rename from app/src/main/res/drawable-v21/ic_menu_slideshow.xml
rename to app/src/main/res/drawable/ic_menu_slideshow.xml
diff --git a/app/src/main/res/drawable/ic_people.xml b/app/src/main/res/drawable/ic_people.xml
new file mode 100644
index 00000000..8982c5c1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_people.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_people_outline.xml b/app/src/main/res/drawable/ic_people_outline.xml
new file mode 100644
index 00000000..f6930229
--- /dev/null
+++ b/app/src/main/res/drawable/ic_people_outline.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_person.xml b/app/src/main/res/drawable/ic_person.xml
new file mode 100644
index 00000000..38765cc9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_person.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_person_black.xml b/app/src/main/res/drawable/ic_person_black.xml
new file mode 100644
index 00000000..eb96cc22
--- /dev/null
+++ b/app/src/main/res/drawable/ic_person_black.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_place.xml b/app/src/main/res/drawable/ic_place.xml
new file mode 100644
index 00000000..8d8f3cb4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_place.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_satellite.xml b/app/src/main/res/drawable/ic_satellite.xml
new file mode 100644
index 00000000..0478dedf
--- /dev/null
+++ b/app/src/main/res/drawable/ic_satellite.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_selection_extend.xml b/app/src/main/res/drawable/ic_selection_extend.xml
new file mode 100644
index 00000000..bfe99df1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_selection_extend.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_settings_brightness.xml b/app/src/main/res/drawable/ic_settings_brightness.xml
new file mode 100644
index 00000000..0cba5200
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings_brightness.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_byte.xml b/app/src/main/res/drawable/ic_tag_byte.xml
new file mode 100644
index 00000000..c657028c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_byte.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_byte_array.xml b/app/src/main/res/drawable/ic_tag_byte_array.xml
new file mode 100644
index 00000000..ff3d4535
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_byte_array.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_compound.xml b/app/src/main/res/drawable/ic_tag_compound.xml
new file mode 100644
index 00000000..3a312a97
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_compound.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_default.xml b/app/src/main/res/drawable/ic_tag_default.xml
new file mode 100644
index 00000000..09219470
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_default.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_double.xml b/app/src/main/res/drawable/ic_tag_double.xml
new file mode 100644
index 00000000..3b77336e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_double.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_float.xml b/app/src/main/res/drawable/ic_tag_float.xml
new file mode 100644
index 00000000..848f1845
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_float.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_int.xml b/app/src/main/res/drawable/ic_tag_int.xml
new file mode 100644
index 00000000..cc0a8d88
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_int.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_int_array.xml b/app/src/main/res/drawable/ic_tag_int_array.xml
new file mode 100644
index 00000000..bcc6932f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_int_array.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_list.xml b/app/src/main/res/drawable/ic_tag_list.xml
new file mode 100644
index 00000000..37c764a4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_list.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_long.xml b/app/src/main/res/drawable/ic_tag_long.xml
new file mode 100644
index 00000000..fb309af9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_long.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_root.xml b/app/src/main/res/drawable/ic_tag_root.xml
new file mode 100644
index 00000000..b2047d75
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_root.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_short.xml b/app/src/main/res/drawable/ic_tag_short.xml
new file mode 100644
index 00000000..3b8b699f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_short.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_string.xml b/app/src/main/res/drawable/ic_tag_string.xml
new file mode 100644
index 00000000..528f1857
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_string.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_terrain.xml b/app/src/main/res/drawable/ic_terrain.xml
new file mode 100644
index 00000000..50b23a99
--- /dev/null
+++ b/app/src/main/res/drawable/ic_terrain.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_visibility.xml b/app/src/main/res/drawable/ic_visibility.xml
new file mode 100644
index 00000000..ff446d49
--- /dev/null
+++ b/app/src/main/res/drawable/ic_visibility.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_world_icon.xml b/app/src/main/res/drawable/ic_world_icon.xml
new file mode 100644
index 00000000..4f949a27
--- /dev/null
+++ b/app/src/main/res/drawable/ic_world_icon.xml
@@ -0,0 +1,274 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/lampshade.png b/app/src/main/res/drawable/lampshade.png
new file mode 100644
index 00000000..840616ed
Binary files /dev/null and b/app/src/main/res/drawable/lampshade.png differ
diff --git a/app/src/main/res/drawable/rect_border_round_corner.xml b/app/src/main/res/drawable/rect_border_round_corner.xml
new file mode 100644
index 00000000..421c7ce3
--- /dev/null
+++ b/app/src/main/res/drawable/rect_border_round_corner.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/sel_item_flat_layer.xml b/app/src/main/res/drawable/sel_item_flat_layer.xml
new file mode 100644
index 00000000..9c1df3da
--- /dev/null
+++ b/app/src/main/res/drawable/sel_item_flat_layer.xml
@@ -0,0 +1,21 @@
+
+
+ -
+
+