BlockTypePalette: Load from TSV or original reports' JSON.
This commit is contained in:
parent
7453a9fbe1
commit
2d6f6a574d
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,554 @@
|
|||
UpgradeBlockTypePalette
|
||||
FileVersion 1
|
||||
CommonPrefix minecraft:
|
||||
|
||||
0 0 air
|
||||
1 0 stone
|
||||
1 1 granite
|
||||
1 2 polished_granite
|
||||
1 3 diorite
|
||||
1 4 polished_diorite
|
||||
1 5 andesite
|
||||
1 6 polished_andesite
|
||||
2 0 grass_block
|
||||
3 0 dirt
|
||||
3 1 coarse_dirt
|
||||
3 2 podzol
|
||||
4 0 cobblestone
|
||||
5 0 oak_planks
|
||||
5 1 spruce_planks
|
||||
5 2 birch_planks
|
||||
5 3 jungle_planks
|
||||
5 4 acacia_planks
|
||||
5 5 dark_oak_planks
|
||||
6 0 oak_sapling
|
||||
6 1 spruce_sapling
|
||||
6 2 birch_sapling
|
||||
6 3 jungle_sapling
|
||||
6 4 acacia_sapling
|
||||
6 5 dark_oak_sapling
|
||||
7 0 bedrock
|
||||
8 0 flowing_water
|
||||
9 0 water
|
||||
10 0 flowing_lava
|
||||
11 0 lava
|
||||
12 0 sand
|
||||
12 1 red_sand
|
||||
13 0 gravel
|
||||
14 0 gold_ore
|
||||
15 0 iron_ore
|
||||
16 0 coal_ore
|
||||
17 0 oak_log
|
||||
17 1 spruce_log
|
||||
17 2 birch_log
|
||||
17 3 jungle_log
|
||||
18 0 oak_leaves
|
||||
18 1 spruce_leaves
|
||||
18 2 birch_leaves
|
||||
18 3 jungle_leaves
|
||||
19 0 sponge
|
||||
19 1 wet_sponge
|
||||
20 0 glass
|
||||
21 0 lapis_ore
|
||||
22 0 lapis_block
|
||||
23 0 dispenser
|
||||
24 0 sandstone
|
||||
24 1 chiseled_sandstone
|
||||
24 2 smooth_sandstone
|
||||
25 0 note_block
|
||||
26 0 bed
|
||||
27 0 powered_rail
|
||||
28 0 detector_rail
|
||||
29 0 sticky_piston
|
||||
30 0 cobweb
|
||||
31 0 dead_bush
|
||||
31 1 grass
|
||||
31 2 fern
|
||||
32 0 dead_bush
|
||||
33 0 piston
|
||||
34 0 piston_head
|
||||
35 0 white_wool
|
||||
35 1 orange_wool
|
||||
35 2 magenta_wool
|
||||
35 3 light_blue_wool
|
||||
35 4 yellow_wool
|
||||
35 5 lime_wool
|
||||
35 6 pink_wool
|
||||
35 7 gray_wool
|
||||
35 8 light_gray_wool
|
||||
35 9 cyan_wool
|
||||
35 10 purple_wool
|
||||
35 11 blue_wool
|
||||
35 12 brown_wool
|
||||
35 13 green_wool
|
||||
35 14 red_wool
|
||||
35 15 black_wool
|
||||
36 0 moving_piston
|
||||
37 0 dandelion
|
||||
38 0 poppy
|
||||
38 1 blue_orchid
|
||||
38 2 allium
|
||||
38 3 azure_bluet
|
||||
38 4 red_tulip
|
||||
38 5 orange_tulip
|
||||
38 6 white_tulip
|
||||
38 7 pink_tulip
|
||||
38 8 oxeye_daisy
|
||||
39 0 brown_mushroom
|
||||
40 0 red_mushroom
|
||||
41 0 gold_block
|
||||
42 0 iron_block
|
||||
43 0 stone_slab
|
||||
43 1 sandstone_slab
|
||||
43 2 oak_slab
|
||||
43 3 cobblestone_slab
|
||||
43 4 brick_slab
|
||||
43 5 stone_brick_slab
|
||||
43 6 nether_brick_slab
|
||||
43 7 smooth_quartz
|
||||
43 8 stone_slab
|
||||
43 9 sandstone_slab
|
||||
44 0 stone_slab
|
||||
44 1 sandstone_slab
|
||||
44 2 oak_slab
|
||||
44 3 cobblestone_slab
|
||||
44 4 brick_slab
|
||||
44 5 stone_brick_slab
|
||||
44 6 nether_brick_slab
|
||||
44 7 quartz_slab
|
||||
44 8 stone_slab type top
|
||||
44 9 sandstone_slab type top
|
||||
44 10 oak_slab
|
||||
44 11 cobblestone_slab type top
|
||||
44 12 brick_slab type top
|
||||
44 13 stone_brick_slab type top
|
||||
44 14 nether_brick_slab type top
|
||||
44 15 quartz_slab type top
|
||||
45 0 bricks
|
||||
46 0 tnt
|
||||
47 0 bookshelf
|
||||
48 0 mossy_cobblestone
|
||||
49 0 obsidian
|
||||
50 0 torch
|
||||
51 0 fire
|
||||
52 0 spawner
|
||||
53 0 oak_stairs
|
||||
53 4 oak_stairs half top
|
||||
54 0 chest
|
||||
55 0 redstone_wire
|
||||
56 0 diamond_ore
|
||||
57 0 diamond_block
|
||||
58 0 crafting_table
|
||||
59 0 wheat
|
||||
59 0 wheat age 0
|
||||
59 1 wheat age 1
|
||||
59 2 wheat age 2
|
||||
59 3 wheat age 3
|
||||
59 4 wheat age 4
|
||||
59 5 wheat age 5
|
||||
59 6 wheat age 6
|
||||
60 0 farmland
|
||||
60 0 farmland moisture 0
|
||||
61 0 furnace
|
||||
62 0 furnace
|
||||
63 0 sign
|
||||
64 0 oak_door
|
||||
65 0 ladder
|
||||
66 0 rail
|
||||
67 0 cobblestone_stairs
|
||||
67 4 cobblestone_stairs half top
|
||||
68 0 wall_sign
|
||||
69 0 lever
|
||||
70 0 stone_pressure_plate
|
||||
71 0 iron_door
|
||||
72 0 oak_pressure_plate
|
||||
73 0 redstone_ore
|
||||
74 0 redstone_ore
|
||||
75 0 redstone_torch
|
||||
76 0 redstone_torch powered true
|
||||
77 0 stone_button
|
||||
78 0 snow
|
||||
79 0 ice
|
||||
80 0 snow_block
|
||||
81 0 cactus
|
||||
82 0 clay
|
||||
83 0 sugar_cane
|
||||
84 0 jukebox
|
||||
85 0 oak_fence
|
||||
86 0 pumpkin
|
||||
87 0 netherrack
|
||||
88 0 soul_sand
|
||||
89 0 glowstone
|
||||
90 0 nether_portal
|
||||
91 0 jack_o_lantern
|
||||
92 0 cake
|
||||
93 0 repeater
|
||||
94 0 repeater powered true
|
||||
95 0 white_stained_glass
|
||||
95 1 orange_stained_glass
|
||||
95 2 magenta_stained_glass
|
||||
95 3 light_blue_stained_glass
|
||||
95 4 yellow_stained_glass
|
||||
95 5 lime_stained_glass
|
||||
95 6 pink_stained_glass
|
||||
95 7 gray_stained_glass
|
||||
95 8 light_gray_stained_glass
|
||||
95 9 cyan_stained_glass
|
||||
95 10 purple_stained_glass
|
||||
95 11 blue_stained_glass
|
||||
95 12 brown_stained_glass
|
||||
95 13 green_stained_glass
|
||||
95 14 red_stained_glass
|
||||
95 15 black_stained_glass
|
||||
96 0 oak_trapdoor
|
||||
97 0 infested_stone
|
||||
97 1 infested_cobblestone
|
||||
97 2 infested_stone_bricks
|
||||
97 3 infested_mossy_stone_bricks
|
||||
97 4 infested_cracked_stone_bricks
|
||||
97 5 infested_chiseled_stone_bricks
|
||||
98 0 stone_bricks
|
||||
98 1 mossy_stone_bricks
|
||||
98 2 cracked_stone_bricks
|
||||
98 3 chiseled_stone_bricks
|
||||
99 0 brown_mushroom_block up false
|
||||
99 0 brown_mushroom_block
|
||||
99 1 brown_mushroom_block
|
||||
99 2 brown_mushroom_block
|
||||
99 3 brown_mushroom_block
|
||||
99 4 brown_mushroom_block
|
||||
99 5 brown_mushroom_block
|
||||
99 6 brown_mushroom_block
|
||||
99 7 brown_mushroom_block
|
||||
99 8 brown_mushroom_block
|
||||
99 9 brown_mushroom_block
|
||||
99 10 mushroom_stem up false
|
||||
99 14 brown_mushroom_block
|
||||
99 15 mushroom_stem
|
||||
100 0 red_mushroom_block
|
||||
100 0 red_mushroom_block up false
|
||||
100 1 red_mushroom_block
|
||||
100 2 red_mushroom_block
|
||||
100 3 red_mushroom_block
|
||||
100 4 red_mushroom_block
|
||||
100 5 red_mushroom_block
|
||||
100 6 red_mushroom_block
|
||||
100 7 red_mushroom_block
|
||||
100 8 red_mushroom_block
|
||||
100 9 red_mushroom_block
|
||||
100 10 mushroom_stem up false
|
||||
100 14 red_mushroom_block
|
||||
100 15 mushroom_stem
|
||||
101 0 iron_bars
|
||||
102 0 glass_pane
|
||||
103 0 melon
|
||||
104 0 pumpkin_stem
|
||||
105 0 melon_stem
|
||||
106 0 vine
|
||||
107 0 oak_fence_gate
|
||||
108 0 brick_stairs
|
||||
108 4 brick_stairs half top
|
||||
109 0 stone_brick_stairs
|
||||
109 4 stone_brick_stairs half top
|
||||
110 0 mycelium
|
||||
111 0 lily_pad
|
||||
112 0 nether_bricks
|
||||
113 0 nether_brick_fence
|
||||
114 0 nether_brick_stairs
|
||||
114 4 netherbrick_stairs half top
|
||||
115 0 nether_wart
|
||||
115 0 nether_wart age 0
|
||||
115 3 nether_wart age 3
|
||||
116 0 enchanting_table
|
||||
117 0 brewing_stand
|
||||
118 0 cauldron
|
||||
119 0 end_portal
|
||||
120 0 end_portal_frame
|
||||
120 4 end_portal_frame eye true
|
||||
121 0 end_stone
|
||||
122 0 dragon_egg
|
||||
123 0 redstone_lamp
|
||||
124 0 redstone_lamp lit on
|
||||
125 0 oak_slab
|
||||
125 1 spruce_slab
|
||||
125 2 birch_slab
|
||||
125 3 jungle_slab
|
||||
125 4 acacia_slab
|
||||
125 5 dark_oak_slab
|
||||
126 0 oak_slab
|
||||
126 1 spruce_slab
|
||||
126 2 birch_slab
|
||||
126 3 jungle_slab
|
||||
126 4 acacia_slab
|
||||
126 5 dark_oak_slab
|
||||
126 8 oak_slab type top
|
||||
126 9 spruce_slab type top
|
||||
126 10 birch_slab type top
|
||||
126 11 jungle_slab type top
|
||||
126 12 acacia_slab type top
|
||||
126 13 dark_oak_slab type top
|
||||
127 0 cocoa
|
||||
127 8 cocoa
|
||||
128 0 sandstone_stairs
|
||||
128 4 sandstone_stairs half top
|
||||
129 0 emerald_ore
|
||||
130 0 ender_chest
|
||||
131 0 tripwire_hook
|
||||
132 0 tripwire
|
||||
133 0 emerald_block
|
||||
134 0 spruce_stairs
|
||||
134 4 spruce_stairs half top
|
||||
135 0 birch_stairs
|
||||
135 4 birch_stairs half top
|
||||
136 0 jungle_stairs
|
||||
136 4 jungle_stairs half top
|
||||
137 0 command_block
|
||||
138 0 beacon
|
||||
139 0 cobblestone_wall
|
||||
139 1 mossy_cobblestone_wall
|
||||
140 0 flower_pot
|
||||
140 1 potted_poppy
|
||||
140 2 potted_dandelion
|
||||
140 3 potted_oak_sapling
|
||||
140 4 potted_spruce_sapling
|
||||
140 5 potted_birch_sapling
|
||||
140 6 potted_jungle_sapling
|
||||
140 7 potted_red_mushroom
|
||||
140 8 potted_brown_mushroom
|
||||
140 9 potted_cactus
|
||||
140 10 potted_dead_bush
|
||||
140 11 potted_fern
|
||||
140 12 potted_acacia_sapling
|
||||
140 13 potted_dark_oak_sapling
|
||||
141 0 carrots
|
||||
141 0 carrots age 0
|
||||
141 1 carrots age 1
|
||||
141 2 carrots age 2
|
||||
142 0 potatoes age 0
|
||||
142 0 potatoes
|
||||
142 1 potatoes age 1
|
||||
142 2 potatoes age 2
|
||||
142 3 potatoes age 3
|
||||
142 4 potatoes age 4
|
||||
142 5 potatoes age 5
|
||||
142 6 potatoes age 6
|
||||
143 0 oak_button
|
||||
144 0 mob_head
|
||||
145 0 anvil
|
||||
145 4 chipped_anvil
|
||||
145 8 damaged_anvil
|
||||
146 0 trapped_chest
|
||||
147 0 light_weighted_pressure_plate
|
||||
148 0 heavy_weighted_pressure_plate
|
||||
149 0 comparator
|
||||
150 0 comparator powered true
|
||||
151 0 daylight_detector
|
||||
152 0 redstone_block
|
||||
153 0 nether_quartz_ore
|
||||
154 0 hopper
|
||||
155 0 quartz_block
|
||||
155 1 chiseled_quartz_block
|
||||
155 2 quartz_pillar
|
||||
155 3 quartz_pillar
|
||||
155 4 quartz_pillar
|
||||
156 0 quartz_stairs
|
||||
156 4 quartz_stairs half top
|
||||
157 0 activator_rail
|
||||
158 0 dropper
|
||||
159 0 white_terracotta
|
||||
159 1 orange_terracotta
|
||||
159 2 magenta_terracotta
|
||||
159 3 light_blue_terracotta
|
||||
159 4 yellow_terracotta
|
||||
159 5 lime_terracotta
|
||||
159 6 pink_terracotta
|
||||
159 7 gray_terracotta
|
||||
159 8 light_gray_terracotta
|
||||
159 9 cyan_terracotta
|
||||
159 10 purple_terracotta
|
||||
159 11 blue_terracotta
|
||||
159 12 brown_terracotta
|
||||
159 13 green_terracotta
|
||||
159 14 red_terracotta
|
||||
159 15 black_terracotta
|
||||
160 0 white_stained_glass_pane
|
||||
160 1 orange_stained_glass_pane
|
||||
160 2 magenta_stained_glass_pane
|
||||
160 3 light_blue_stained_glass_pane
|
||||
160 4 yellow_stained_glass_pane
|
||||
160 5 lime_stained_glass_pane
|
||||
160 6 pink_stained_glass_pane
|
||||
160 7 gray_stained_glass_pane
|
||||
160 8 light_gray_stained_glass_pane
|
||||
160 9 cyan_stained_glass_pane
|
||||
160 10 purple_stained_glass_pane
|
||||
160 11 blue_stained_glass_pane
|
||||
160 12 brown_stained_glass_pane
|
||||
160 13 green_stained_glass_pane
|
||||
160 14 red_stained_glass_pane
|
||||
160 15 black_stained_glass_pane
|
||||
161 0 acacia_leaves
|
||||
161 1 dark_oak_leaves
|
||||
162 0 acacia_log
|
||||
162 1 dark_oak_log
|
||||
163 0 acacia_stairs
|
||||
163 4 acacia_stairs half top
|
||||
164 0 dark_oak_stairs
|
||||
164 4 dark_oak_stairs half top
|
||||
165 0 slime_block
|
||||
166 0 barrier
|
||||
167 0 iron_trapdoor
|
||||
168 0 prismarine
|
||||
168 1 prismarine_bricks
|
||||
168 2 dark_prismarine
|
||||
169 0 sea_lantern
|
||||
170 0 hay_block
|
||||
171 0 white_carpet
|
||||
171 1 orange_carpet
|
||||
171 2 magenta_carpet
|
||||
171 3 light_blue_carpet
|
||||
171 4 yellow_carpet
|
||||
171 5 lime_carpet
|
||||
171 6 pink_carpet
|
||||
171 7 gray_carpet
|
||||
171 8 light_gray_carpet
|
||||
171 9 cyan_carpet
|
||||
171 10 purple_carpet
|
||||
171 11 blue_carpet
|
||||
171 12 brown_carpet
|
||||
171 13 green_carpet
|
||||
171 14 red_carpet
|
||||
171 15 black_carpet
|
||||
172 0 terracotta
|
||||
173 0 coal_block
|
||||
174 0 packed_ice
|
||||
175 0 sunflower
|
||||
175 1 lilac
|
||||
175 2 tall_grass
|
||||
175 3 large_fern
|
||||
175 4 rose_bush
|
||||
175 5 peony
|
||||
175 8 large_flower_(top_part)
|
||||
175 10 large_flower_(top_part)
|
||||
176 0 white_banner
|
||||
177 0 white_wall_banner
|
||||
178 0 daylight_detector
|
||||
179 0 red_sandstone
|
||||
179 1 chiseled_red_sandstone
|
||||
179 2 smooth_red_sandstone
|
||||
180 0 red_sandstone_stairs
|
||||
180 4 red_sandstone_stairs half top
|
||||
181 0 red_sandstone_slab
|
||||
181 8 red_sandstone_slab
|
||||
182 0 red_sandstone_slab
|
||||
182 8 red_sandstone_slab type top
|
||||
183 0 spruce_fence_gate
|
||||
184 0 birch_fence_gate
|
||||
185 0 jungle_fence_gate
|
||||
186 0 dark_oak_fence_gate
|
||||
187 0 acacia_fence_gate
|
||||
188 0 spruce_fence
|
||||
189 0 birch_fence
|
||||
190 0 jungle_fence
|
||||
191 0 dark_oak_fence
|
||||
192 0 acacia_fence
|
||||
193 0 spruce_door
|
||||
194 0 birch_door
|
||||
195 0 jungle_door
|
||||
196 0 acacia_door
|
||||
197 0 dark_oak_door
|
||||
198 0 end_rod
|
||||
199 0 chorus_plant
|
||||
200 0 chorus_flower
|
||||
200 5 chorus_flower age 5
|
||||
201 0 purpur_block
|
||||
202 0 purpur_pillar
|
||||
203 0 purpur_stairs
|
||||
203 4 purpur_stairs half top
|
||||
204 0 purpur_slab
|
||||
205 0 purpur_slab
|
||||
205 8 purpur_slab type top
|
||||
206 0 end_stone_bricks
|
||||
207 0 beetroots age 0
|
||||
207 0 beetroots
|
||||
207 1 beetroots age 1
|
||||
207 2 beetroots age 2
|
||||
208 0 grass_path
|
||||
209 0 end_gateway
|
||||
210 0 repeating_command_block
|
||||
211 0 chain_command_block
|
||||
212 0 frosted_ice
|
||||
213 0 magma_block
|
||||
214 0 nether_wart_block
|
||||
215 0 red_nether_bricks
|
||||
216 0 bone_block
|
||||
217 0 structure_void
|
||||
218 0 observer
|
||||
219 0 white_shulker_box
|
||||
220 0 orange_shulker_box
|
||||
221 0 magenta_shulker_box
|
||||
222 0 light_blue_shulker_box
|
||||
223 0 yellow_shulker_box
|
||||
224 0 lime_shulker_box
|
||||
225 0 pink_shulker_box
|
||||
226 0 gray_shulker_box
|
||||
227 0 light_gray_shulker_box
|
||||
228 0 cyan_shulker_box
|
||||
229 0 purple_shulker_box
|
||||
230 0 blue_shulker_box
|
||||
231 0 brown_shulker_box
|
||||
232 0 green_shulker_box
|
||||
233 0 red_shulker_box
|
||||
234 0 black_shulker_box
|
||||
235 0 white_glazed_terracotta
|
||||
236 0 orange_glazed_terracotta
|
||||
237 0 magenta_glazed_terracotta
|
||||
238 0 light_blue_glazed_terracotta
|
||||
239 0 yellow_glazed_terracotta
|
||||
240 0 lime_glazed_terracotta
|
||||
241 0 pink_glazed_terracotta
|
||||
242 0 gray_glazed_terracotta
|
||||
243 0 light_gray_glazed_terracotta
|
||||
244 0 cyan_glazed_terracotta
|
||||
245 0 purple_glazed_terracotta
|
||||
246 0 blue_glazed_terracotta
|
||||
247 0 brown_glazed_terracotta
|
||||
248 0 green_glazed_terracotta
|
||||
249 0 red_glazed_terracotta
|
||||
250 0 black_glazed_terracotta
|
||||
251 0 white_concrete
|
||||
251 1 orange_concrete
|
||||
251 2 magenta_concrete
|
||||
251 3 light_blue_concrete
|
||||
251 4 yellow_concrete
|
||||
251 5 lime_concrete
|
||||
251 6 pink_concrete
|
||||
251 7 gray_concrete
|
||||
251 8 light_gray_concrete
|
||||
251 9 cyan_concrete
|
||||
251 10 purple_concrete
|
||||
251 11 blue_concrete
|
||||
251 12 brown_concrete
|
||||
251 13 green_concrete
|
||||
251 14 red_concrete
|
||||
251 15 black_concrete
|
||||
252 0 white_concrete_powder
|
||||
252 1 orange_concrete_powder
|
||||
252 2 magenta_concrete_powder
|
||||
252 3 light_blue_concrete_powder
|
||||
252 4 yellow_concrete_powder
|
||||
252 5 lime_concrete_powder
|
||||
252 6 pink_concrete_powder
|
||||
252 7 gray_concrete_powder
|
||||
252 8 light_gray_concrete_powder
|
||||
252 9 cyan_concrete_powder
|
||||
252 10 purple_concrete_powder
|
||||
252 11 blue_concrete_powder
|
||||
252 12 brown_concrete_powder
|
||||
252 13 green_concrete_powder
|
||||
252 14 red_concrete_powder
|
||||
252 15 black_concrete_powder
|
||||
255 0 structure_block
|
||||
255 1 structure_block
|
||||
255 2 structure_block
|
||||
255 3 structure_block
|
|
@ -0,0 +1,5 @@
|
|||
# Ignore the scripts' outputs:
|
||||
*.json
|
||||
*.btp.txt
|
||||
UpgradeBlockTypePalette.txt
|
||||
|
|
@ -1,14 +1,33 @@
|
|||
-- lib/lunajson/src/ is not in default Lua package paths
|
||||
-- Generator.lua
|
||||
|
||||
--[[
|
||||
Crafts an intermediate block palette format to be read by Cuberite.
|
||||
It processes the blocks.json report file (https://wiki.vg/Data_Generators)
|
||||
into a file that can be loaded into a BlockTypePalette (and is to be stored
|
||||
as Server/Protocol/<version>/base.btp.txt).
|
||||
|
||||
The output format is the regular TSV BlockTypePalette, described in the
|
||||
$/src/BlockTypePalette.h file.
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
|
||||
-- Allow Lua to load libraries in our subfolder:
|
||||
package.path = 'lib/lunajson/src/?.lua;' .. package.path;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Prints usage instructions to stdout.
|
||||
-- If the optional `message` is passed, output is prepended by message _and_
|
||||
-- If the optional `aMessage` is passed, output is prepended by message _and_
|
||||
-- redirected to stderr.
|
||||
function usage(message)
|
||||
if message then
|
||||
local function usage(aMessage)
|
||||
if aMessage then
|
||||
io.output(io.stderr);
|
||||
io.write(message, "\n\n");
|
||||
io.write(aMessage, "\n\n");
|
||||
end
|
||||
io.write(
|
||||
"Usage: lua Generator.lua INPUTFILE OUTPUTFILE\n"..
|
||||
|
@ -22,70 +41,125 @@ function usage(message)
|
|||
end
|
||||
|
||||
|
||||
-- Test whether the script is run in a path where it can load it's libraries
|
||||
if not pcall(function() require("lunajson.decoder") end) then
|
||||
usage("Could not load required libraries, please run `Generator.lua` "..
|
||||
"within its directory and make sure to run `git submodule update`.");
|
||||
|
||||
|
||||
|
||||
--- Parses the JSON registry into a Lua table
|
||||
--[[ The returned array-table has the following format:
|
||||
{
|
||||
{ id = 1, blockTypeName = "minecraft:stone", properties = {key = value, ...} },
|
||||
...
|
||||
}
|
||||
--]]
|
||||
local function parseRegistry(aBlockRegistryJsonStr)
|
||||
assert(type(aBlockRegistryJsonStr) == "string")
|
||||
|
||||
local lj = require("lunajson")
|
||||
local input = lj.decode(aBlockRegistryJsonStr)
|
||||
local registry = {}
|
||||
local idx = 1
|
||||
for blockTypeName, blockData in pairs(input) do
|
||||
for _, state in pairs(blockData.states) do
|
||||
registry[idx] = {
|
||||
id = state.id,
|
||||
blockTypeName = blockTypeName,
|
||||
properties = state.properties,
|
||||
}
|
||||
idx = idx + 1
|
||||
end
|
||||
end
|
||||
return registry
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Serializes the properties from the JSON / array table format into a single output string
|
||||
-- Concatenates all properties with \t as the delimiting character
|
||||
local function serializeProperties(aProperties)
|
||||
local res = {}
|
||||
local idx = 1
|
||||
for k, v in pairs(aProperties or {}) do
|
||||
res[idx] = k
|
||||
res[idx + 1] = v
|
||||
idx = idx + 2
|
||||
end
|
||||
return table.concat(res, "\t")
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Returns the prefix that is common for all block type names in the registry
|
||||
-- aRegistry is the parsed registry, as returned from parseRegistry()
|
||||
local function findCommonPrefix(aRegistryTable)
|
||||
local prefix = aRegistryTable[1].blockTypeName
|
||||
local len = string.len(prefix)
|
||||
local sub = string.sub
|
||||
for _, block in ipairs(aRegistryTable) do
|
||||
while (sub(block.blockTypeName, 1, len) ~= prefix) do
|
||||
len = len - 1
|
||||
if (len == 0) then
|
||||
return ""
|
||||
end
|
||||
prefix = sub(prefix, 1, len)
|
||||
end
|
||||
end
|
||||
return prefix
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- Test whether the script is run in a path where it can load it's libraries
|
||||
if not(pcall(function() require("lunajson") end)) then
|
||||
usage(
|
||||
"Could not load required libraries, please run `Generator.lua` " ..
|
||||
"within its directory and make sure to run `git submodule update`."
|
||||
)
|
||||
end
|
||||
|
||||
-- Check/Prepare CLI arguments
|
||||
local inpath, outpath = ...;
|
||||
io.input(io.stdin);
|
||||
io.output(io.stdout);
|
||||
|
||||
if select("#", ...) ~= 2 then
|
||||
usage("Incorrect number of arguments.");
|
||||
inpath = inpath or "blocks.json"
|
||||
outpath = outpath or "base.btp.txt"
|
||||
if (inpath ~= "-") then
|
||||
local handle, err = io.open(inpath, "r")
|
||||
io.input(handle or usage(err))
|
||||
end
|
||||
if (outpath ~= "-") then
|
||||
local handle, err = io.open(outpath, "w")
|
||||
io.output(handle or usage(err))
|
||||
end
|
||||
|
||||
if inpath ~= "-" then
|
||||
local handle, err = io.open(inpath, "r");
|
||||
io.input(handle or usage(err));
|
||||
end
|
||||
-- Parse the registry:
|
||||
local registry = parseRegistry(io.input():read("*a"))
|
||||
local commonPrefix = findCommonPrefix(registry)
|
||||
|
||||
if outpath ~= "-" then
|
||||
local handle, err = io.open(outpath, "w");
|
||||
io.output(handle or usage(err));
|
||||
end
|
||||
|
||||
|
||||
-- Main program starts here
|
||||
local decode = (require("lunajson.decoder"))();
|
||||
local encode = (require("lunajson.encoder"))();
|
||||
|
||||
local input = decode(io.input():read("*a"));
|
||||
local registry = {};
|
||||
local max_id = -1;
|
||||
|
||||
|
||||
for blockname, blockdata in pairs(input) do
|
||||
for i = 1, #(blockdata.states or {}) do
|
||||
local state = blockdata.states[i];
|
||||
assert(registry[state.id + 1] == nil, "Ensure no duplicate IDs");
|
||||
|
||||
-- needed in the end to verify we got no holes in the array:
|
||||
max_id = math.max(max_id, state.id);
|
||||
|
||||
registry[state.id + 1] = {
|
||||
id = assert(state.id, "id is required."),
|
||||
name = assert(blockname, "Block type name is required."),
|
||||
-- default = state.default or nil, -- may need this later
|
||||
props = state.properties,
|
||||
};
|
||||
-- Sort the entries:
|
||||
table.sort(registry,
|
||||
function (entry1, entry2)
|
||||
return (entry1.id < entry2.id)
|
||||
end
|
||||
)
|
||||
|
||||
-- Write out the output format:
|
||||
io.write("BlockTypePalette\n")
|
||||
io.write("FileVersion\t1\n")
|
||||
io.write("CommonPrefix\t", commonPrefix, "\n")
|
||||
io.write("\n")
|
||||
local prefixLen = string.len(commonPrefix) + 1
|
||||
for _, entry in ipairs(registry) do
|
||||
local props = serializeProperties(entry.properties)
|
||||
if (props ~= "") then
|
||||
props = "\t" .. props
|
||||
end
|
||||
io.write(
|
||||
entry.id, "\t",
|
||||
string.sub(entry.blockTypeName, prefixLen),
|
||||
props, "\n"
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
-- The following assertion is not necessary by the current spec, but is required
|
||||
-- by how lunajson distinguishes objects from arrays. Also if this fails, it is
|
||||
-- _very_ likely that the input file is faulty.
|
||||
assert(#registry == max_id + 1, "Ensure that registry has contiguous keys");
|
||||
|
||||
local out = {
|
||||
Metadata = {
|
||||
ProtocolBlockTypePaletteVersion = 1
|
||||
},
|
||||
Palette = registry
|
||||
};
|
||||
|
||||
io.write(encode(out), "\n");
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
This generator crafts an intermediate index format to be read by cuberite
|
||||
|
||||
# Running
|
||||
|
||||
Run `lua ./Generator.lua`, pass `blocks.json` as first argument to the script
|
||||
and the desired output location as 2nd argument.
|
||||
|
||||
Make sure to run the Generator from within its directory (`cd` into the path
|
||||
where `Generator.lua` is.)
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
SERVER=/path/to/server.jar
|
||||
java -cp "$SERVER" net.minecraft.data.Main --reports &&
|
||||
lua Generator.lua \
|
||||
generated/reports/blocks.json \
|
||||
../../Server/Protocol/1.13/ProtocolBlockTypePalette.json
|
||||
```
|
||||
|
||||
```bash
|
||||
SERVER=/path/to/server.jar
|
||||
java -cp "$SERVER" net.minecraft.data.Main --reports &&
|
||||
lua Generator.lua - -\
|
||||
< generated/reports/blocks.json \
|
||||
> ../Server/Protocol/1.13/ProtocolBlockTypePalette.json
|
||||
```
|
||||
|
||||
## Output format
|
||||
|
||||
The Format is a `JSON` document containing an object with at least two keys at
|
||||
the top level: `Metadata` and `Palette`.
|
||||
|
||||
`Metadata` contains document metadata, namely a key `"ProtocolBlockType": 1`.
|
||||
|
||||
`Palette` contains an array of objects. Each of these objects has at least the
|
||||
keys `id`, `name` and an optional `props` key that contains the individual
|
||||
properties of the current state. These properties are a KV dict of pure strings.
|
||||
|
||||
The order of the array or object elements is not significant. `id` is unique.
|
||||
|
||||
```json
|
||||
{
|
||||
"Metadata": {
|
||||
"ProtocolBlockType": 1
|
||||
},
|
||||
"Palette": [{
|
||||
"id": 0,
|
||||
"name": "minecraft:air"
|
||||
}, {
|
||||
"id": 1,
|
||||
"name": "minecraft:stone"
|
||||
}, {
|
||||
"id": 221,
|
||||
"name": "minecraft:dark_oak_leaves",
|
||||
"props": {
|
||||
"persistent": "false",
|
||||
"distance": "4"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
|
@ -0,0 +1,223 @@
|
|||
-- UpgradeGenerator.lua
|
||||
|
||||
--[[ Creates the UpgradeBlockTypePalette out of JSON data of the Minutor project
|
||||
(https://github.com/mrkite/minutor/blob/master/definitions/vanilla_ids.json
|
||||
|
||||
Parses the JSON into memory, then walks each block's "id" member and possibly
|
||||
the "variants" sub-member to read the block types. The name is either present as "flatname",
|
||||
or is synthesized from the internal Minutor "name" by lowercasing and replacing spaces
|
||||
with underscores.
|
||||
|
||||
Expects two parameters, the input file and output file; either can be replaced by
|
||||
a "-" to use stdin / stdout instead. If not given, the input file defaults to
|
||||
"vanilla_ids.json" and the output file defaults to "UpgradeBlockTypePalette.txt"
|
||||
|
||||
The output format is the upgrade TSV BlockTypePalette, described in the
|
||||
$/src/BlockTypePalette.h file.
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- Allow Lua to load libraries in our subfolder:
|
||||
package.path = 'lib/lunajson/src/?.lua;' .. package.path;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Splits the full flat name into flat name and properties
|
||||
-- "minecraft:carrots:age:0" -> "minecraft:carrots", {age = 0}
|
||||
local function splitFlatName(aFullFlatName)
|
||||
local props = {}
|
||||
local numParts = 0
|
||||
local flatName = ""
|
||||
local propKey = ""
|
||||
aFullFlatName:gsub("([^:]+)",
|
||||
function (aPart)
|
||||
if (numParts == 0) then
|
||||
flatName = aPart
|
||||
elseif (numParts == 1) then
|
||||
flatName = flatName .. ":" .. aPart
|
||||
elseif (numParts % 2 == 0) then
|
||||
propKey = aPart
|
||||
else
|
||||
props[propKey] = aPart
|
||||
end
|
||||
numParts = numParts + 1
|
||||
end
|
||||
)
|
||||
return flatName, props
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Returns the minecraft block name, created from the flat name if present, or synthesized
|
||||
-- from the Minutor name
|
||||
-- If the flat name contains encoded block properties, it returns those properties as a dict-table
|
||||
-- in the second return value
|
||||
local function processBlockName(aFlatName, aMinutorName)
|
||||
if (aFlatName) then
|
||||
assert(type(aFlatName) == "string")
|
||||
return splitFlatName(aFlatName)
|
||||
end
|
||||
if not(type(aMinutorName) == "string") then
|
||||
return nil
|
||||
end
|
||||
return "minecraft:" .. (aMinutorName:lower():gsub(" ", "_")), {}
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Serializes the properties from the JSON / array table format into a single output string
|
||||
-- Concatenates all properties with \t as the delimiting character
|
||||
local function serializeProperties(aProperties)
|
||||
local res = {}
|
||||
local idx = 1
|
||||
for k, v in pairs(aProperties or {}) do
|
||||
res[idx] = k
|
||||
res[idx + 1] = v
|
||||
idx = idx + 2
|
||||
end
|
||||
return table.concat(res, "\t")
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Parses the vanilla_ids.json into a common registry format
|
||||
-- The returned registry is an array-table of
|
||||
-- {blockType = 1, blockMeta = 2, blockTypeName = "name", properties = {key = value, ...}}
|
||||
local function parseRegistry(aJsonString)
|
||||
assert(type(aJsonString) == "string")
|
||||
|
||||
-- Parse the JSON:
|
||||
local lj = require("lunajson")
|
||||
local input = lj.decode(aJsonString)
|
||||
if (not(input) or (input["type"] ~= "block") or not(input["data"])) then
|
||||
error("The input file doesn't contain vanilla IDs.")
|
||||
end
|
||||
|
||||
-- Create the registry:
|
||||
local registry = {}
|
||||
local idx = 1
|
||||
for _, entry in pairs(input["data"]) do
|
||||
local id = entry["id"]
|
||||
local parentBlockTypeName, props = processBlockName(entry["flatname"], entry["name"])
|
||||
registry[idx] =
|
||||
{
|
||||
blockType = id,
|
||||
blockMeta = 0,
|
||||
blockTypeName = parentBlockTypeName,
|
||||
properties = props,
|
||||
}
|
||||
idx = idx + 1
|
||||
for _, variant in pairs(entry["variants"] or {}) do
|
||||
local blockTypeName, props = processBlockName(variant["flatname"], variant["name"])
|
||||
if not(blockTypeName) then
|
||||
-- Some blocks don't have all their variants named ("brown mushroom block"), use the parent name in such a case
|
||||
blockTypeName = parentBlockTypeName
|
||||
end
|
||||
registry[idx] =
|
||||
{
|
||||
blockType = id,
|
||||
blockMeta = variant["data"],
|
||||
blockTypeName = blockTypeName,
|
||||
properties = props,
|
||||
}
|
||||
idx = idx + 1
|
||||
end
|
||||
end
|
||||
return registry
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Returns the prefix that is common for all block type names in the registry
|
||||
-- aRegistry is the parsed registry, as returned from parseRegistry()
|
||||
local function findCommonPrefix(aRegistryTable)
|
||||
local prefix = aRegistryTable[1].blockTypeName
|
||||
local len = string.len(prefix)
|
||||
local sub = string.sub
|
||||
for _, block in ipairs(aRegistryTable) do
|
||||
while (sub(block.blockTypeName, 1, len) ~= prefix) do
|
||||
len = len - 1
|
||||
if (len == 0) then
|
||||
return ""
|
||||
end
|
||||
prefix = sub(prefix, 1, len)
|
||||
end
|
||||
end
|
||||
return prefix
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- Test whether the script is run in a path where it can load it's libraries
|
||||
if not(pcall(function() require("lunajson") end)) then
|
||||
error(
|
||||
"Could not load required libraries, please run `UpgradeGenerator.lua` " ..
|
||||
"within its directory and make sure to run `git submodule update`."
|
||||
)
|
||||
end
|
||||
|
||||
-- Check/Prepare CLI arguments
|
||||
local inpath, outpath = ...;
|
||||
inpath = inpath or "vanilla_ids.json"
|
||||
outpath = outpath or "UpgradeBlockTypePalette.txt"
|
||||
if (inpath ~= "-") then
|
||||
local handle, err = io.open(inpath, "r")
|
||||
io.input(handle or usage(err))
|
||||
end
|
||||
if (outpath ~= "-") then
|
||||
local handle, err = io.open(outpath, "w")
|
||||
io.output(handle or usage(err))
|
||||
end
|
||||
|
||||
-- Parse the registry:
|
||||
local registry = parseRegistry(io.input():read("*a"))
|
||||
local commonPrefix = findCommonPrefix(registry)
|
||||
|
||||
-- Sort the entries:
|
||||
table.sort(registry,
|
||||
function (entry1, entry2)
|
||||
if (entry1.blockType < entry2.blockType) then
|
||||
return true
|
||||
elseif (entry1.blockType > entry2.blockType) then
|
||||
return false
|
||||
else
|
||||
return (entry1.blockMeta < entry2.blockMeta)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
-- Write out the output format:
|
||||
io.write("UpgradeBlockTypePalette\n")
|
||||
io.write("FileVersion\t1\n")
|
||||
io.write("CommonPrefix\t", commonPrefix, "\n")
|
||||
io.write("\n")
|
||||
local prefixLen = string.len(commonPrefix) + 1
|
||||
for _, entry in ipairs(registry) do
|
||||
local props = serializeProperties(entry.properties)
|
||||
if (props ~= "") then
|
||||
props = "\t" .. props
|
||||
end
|
||||
io.write(
|
||||
entry.blockType, "\t", entry.blockMeta, "\t",
|
||||
string.sub(entry.blockTypeName, prefixLen),
|
||||
props, "\n"
|
||||
)
|
||||
end
|
|
@ -123,7 +123,18 @@ std::map<UInt32, UInt32> BlockTypePalette::createTransformMapWithFallback(const
|
|||
|
||||
void BlockTypePalette::loadFromString(const AString & aString)
|
||||
{
|
||||
// TODO: Detect format (Json vs Lua)
|
||||
static const AString hdrTsvRegular = "BlockTypePalette";
|
||||
static const AString hdrTsvUpgrade = "UpgradeBlockTypePalette";
|
||||
|
||||
// Detect format by checking the header line (none -> JSON):
|
||||
if (aString.substr(0, hdrTsvRegular.length()) == hdrTsvRegular)
|
||||
{
|
||||
return loadFromTsv(aString, false);
|
||||
}
|
||||
else if (aString.substr(0, hdrTsvUpgrade.length()) == hdrTsvUpgrade)
|
||||
{
|
||||
return loadFromTsv(aString, true);
|
||||
}
|
||||
return loadFromJsonString(aString);
|
||||
}
|
||||
|
||||
|
@ -143,55 +154,144 @@ void BlockTypePalette::loadFromJsonString(const AString & aJsonPalette)
|
|||
throw LoadFailedException(errs);
|
||||
}
|
||||
|
||||
// Check the JSON's metadata + version:
|
||||
if (!root.isObject() ||
|
||||
!root.isMember("Metadata") ||
|
||||
!root["Metadata"].isMember("ProtocolBlockTypePaletteVersion") ||
|
||||
!root.isMember("Palette") ||
|
||||
!root["Palette"].isArray())
|
||||
// Sanity-check the JSON's structure:
|
||||
if (!root.isObject())
|
||||
{
|
||||
throw LoadFailedException("Incorrect palette format, wrong or missing metadata.");
|
||||
}
|
||||
auto version = root["Metadata"]["ProtocolBlockTypePaletteVersion"].asUInt();
|
||||
if (version != 1)
|
||||
{
|
||||
throw(Printf("Palette format version %d not supported.", version));
|
||||
throw LoadFailedException("Incorrect palette format, expected an object at root.");
|
||||
}
|
||||
|
||||
// Load the palette:
|
||||
auto len = root["Palette"].size();
|
||||
for (decltype(len) i = 0; i < len; ++i)
|
||||
for (auto itr = root.begin(), end = root.end(); itr != end; ++itr)
|
||||
{
|
||||
const auto & record = root["Palette"][i];
|
||||
if (!record.isObject())
|
||||
const auto & blockTypeName = itr.name();
|
||||
const auto & states = (*itr)["states"];
|
||||
if (states == Json::Value())
|
||||
{
|
||||
throw LoadFailedException(Printf("Palette record #%u is not a JSON object.", i));
|
||||
throw LoadFailedException(Printf("Missing \"states\" for block type \"%s\"", blockTypeName));
|
||||
}
|
||||
|
||||
auto blockTypeName = record["name"].asString();
|
||||
auto id = static_cast<UInt32>(std::stoul(record["id"].asString()));
|
||||
std::map<AString, AString> state;
|
||||
|
||||
if (record.isMember("props"))
|
||||
for (const auto & state: states)
|
||||
{
|
||||
const auto & props = record["props"];
|
||||
if (!props.isObject())
|
||||
auto id = static_cast<UInt32>(std::stoul(state["id"].asString()));
|
||||
std::map<AString, AString> props;
|
||||
if (state.isMember("properties"))
|
||||
{
|
||||
throw LoadFailedException(Printf("Palette record #%u: \"props\" value is not a JSON object.", i));
|
||||
}
|
||||
for (const auto & key: props.getMemberNames())
|
||||
{
|
||||
state[key] = props[key].asString();
|
||||
const auto & properties = state["properties"];
|
||||
if (!properties.isObject())
|
||||
{
|
||||
throw LoadFailedException(Printf("Member \"properties\" is not a JSON object (block type \"%s\", id %u).", blockTypeName, id));
|
||||
}
|
||||
for (const auto & key: properties.getMemberNames())
|
||||
{
|
||||
props[key] = properties[key].asString();
|
||||
}
|
||||
}
|
||||
addMapping(id, blockTypeName, props);
|
||||
}
|
||||
BlockState blockState(state);
|
||||
|
||||
// Insert / update in the maps:
|
||||
mNumberToBlock[id] = {blockTypeName, blockState};
|
||||
mBlockToNumber[blockTypeName][blockState] = id;
|
||||
if (id > mMaxIndex)
|
||||
{
|
||||
mMaxIndex = id;
|
||||
}
|
||||
} // for i - Palette[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BlockTypePalette::loadFromTsv(const AString & aTsvPalette, bool aIsUpgrade)
|
||||
{
|
||||
auto lines = StringSplitAndTrim(aTsvPalette, "\n");
|
||||
|
||||
// Parse the header:
|
||||
int fileVersion = 0;
|
||||
AString commonPrefix;
|
||||
auto numLines = lines.size();
|
||||
for (size_t idx = 1; idx < numLines; ++idx)
|
||||
{
|
||||
const auto & line = lines[idx];
|
||||
if (line.empty())
|
||||
{
|
||||
// End of headers, erase them from lines[] and go parse the data
|
||||
lines.erase(lines.begin(), lines.begin() + static_cast<AStringVector::difference_type>(idx) + 1);
|
||||
break;
|
||||
}
|
||||
auto s = StringSplit(line, "\t");
|
||||
if (s.size() != 2)
|
||||
{
|
||||
throw LoadFailedException(Printf("Invalid header format on line %u", idx + 1));
|
||||
}
|
||||
if (s[0] == "FileVersion")
|
||||
{
|
||||
try
|
||||
{
|
||||
fileVersion = std::stoi(s[1]);
|
||||
}
|
||||
catch (const std::exception & exc)
|
||||
{
|
||||
throw LoadFailedException(Printf("Invalid file version: \"%d\" (%s)", s[1], exc.what()));
|
||||
}
|
||||
}
|
||||
else if (s[0] == "CommonPrefix")
|
||||
{
|
||||
commonPrefix = s[1];
|
||||
}
|
||||
}
|
||||
if (fileVersion != 1)
|
||||
{
|
||||
throw LoadFailedException(Printf("Unknown file version (%d), only version 1 is supported", fileVersion));
|
||||
}
|
||||
|
||||
// Parse the data:
|
||||
size_t minSplit = aIsUpgrade ? 3 : 2;
|
||||
for (const auto & line: lines)
|
||||
{
|
||||
auto s = StringSplit(line, "\t");
|
||||
auto numSplit = s.size();
|
||||
if (numSplit < minSplit)
|
||||
{
|
||||
throw LoadFailedException(Printf("Not enough values on data line: \"%s\"", line));
|
||||
}
|
||||
UInt32 id;
|
||||
try
|
||||
{
|
||||
id = static_cast<UInt32>(std::stoi(s[0]));
|
||||
}
|
||||
catch (const std::exception & exc)
|
||||
{
|
||||
throw LoadFailedException(Printf("Invalid block ID: \"%s\" (%s)", s[0], exc.what()));
|
||||
}
|
||||
size_t idx = 1;
|
||||
if (aIsUpgrade)
|
||||
{
|
||||
id = id * 16;
|
||||
try
|
||||
{
|
||||
id = id + static_cast<UInt32>(Clamp(std::stoi(s[1]), 0, 15));
|
||||
}
|
||||
catch (const std::exception & exc)
|
||||
{
|
||||
throw LoadFailedException(Printf("Invalid block meta: \"%s\" (%s)", s[1], exc.what()));
|
||||
}
|
||||
idx = 2;
|
||||
}
|
||||
const auto & blockTypeName = s[idx];
|
||||
idx += 1;
|
||||
std::map<AString, AString> state;
|
||||
while (idx + 1 < numSplit)
|
||||
{
|
||||
state[s[idx]] = s[idx + 1];
|
||||
idx += 2;
|
||||
}
|
||||
addMapping(id, commonPrefix + blockTypeName, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BlockTypePalette::addMapping(UInt32 aID, const AString & aBlockTypeName, const BlockState & aBlockState)
|
||||
{
|
||||
mNumberToBlock[aID] = {aBlockTypeName, aBlockState};
|
||||
mBlockToNumber[aBlockTypeName][aBlockState] = aID;
|
||||
if (aID > mMaxIndex)
|
||||
{
|
||||
mMaxIndex = aID;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,25 @@ The object itself provides no thread safety, users of this class need to handle
|
|||
Note that the palette itself doesn't support erasing;
|
||||
to erase, create a new instance and re-add only the wanted items.
|
||||
|
||||
Internally, the object uses two synced maps, one for each translation direction. */
|
||||
Internally, the object uses two synced maps, one for each translation direction.
|
||||
|
||||
The palette can be loaded from a string (file). The loader supports either the blocks.json file exported by
|
||||
the vanilla server itself (https://wiki.vg/Data_Generators), or a processed text file generated by
|
||||
our tool $/Tools/BlockTypePaletteGenerator/, or a hand-written text file describing the upgrade from
|
||||
1.12 BlockType + BlockMeta to 1.13 string representations.
|
||||
The text file is a TSV (tab-separated values), which basically means the data is generally structured as
|
||||
<value1><tab><value2><tab><value3><tab>...<valueN><eol>, where eol is the platform's CR / CRLF / LF lineend.
|
||||
The file starts with a single value on the first line, "BlockTypePalette" or "UpgradeBlockTypePalette", which
|
||||
is used to detect the file format. The following lines are "headers", simple <key><tab><value><eol> entries
|
||||
that contain the metadata about the file. "FileVersion" is a compulsory key, "CommonPrefix" is supported, others
|
||||
are ignored.
|
||||
The headers are followed by an empty line (that signalizes the end of headers) and then the actual data.
|
||||
For regular BlockTypePalette TSV file of version 1, the data is in the format:
|
||||
<index><tab><blockTypeName><tab><state1Name><tab><state1Value><tab><state2Name> ... <eol>
|
||||
For the UpgradeBlockTypePalette TSV file of version 1, the data is in the format:
|
||||
<blockType><tab><blockMeta><tab><blockTypeName><tab><state1Name><tab><state1Value><tab><state2Name> ... <eol>
|
||||
If a CommonPrefix header is present, its value is pre-pended to each blockTypeName loaded (thus allowing
|
||||
the file to be overall smaller). */
|
||||
class BlockTypePalette
|
||||
{
|
||||
public:
|
||||
|
@ -78,10 +96,11 @@ public:
|
|||
std::map<UInt32, UInt32> createTransformMapWithFallback(const BlockTypePalette & aFrom, UInt32 aFallbackIndex) const;
|
||||
|
||||
/** Loads the palette from the string representation.
|
||||
Throws a LoadFailedException if the loading fails hard (bad string format).
|
||||
Throws a LoadFailedException if the loading fails hard (bad string format);
|
||||
but still a part of the data may already be loaded at that point.
|
||||
If the string specifies duplicate entries (either to already existing entries, or to itself),
|
||||
the duplicates replace the current values silently (this allows us to chain multiple files as "overrides".
|
||||
Currently handles only JSON representation, expected to handle also Lua representation in the future. */
|
||||
Auto-detects the string format (json / tsv, normal / upgrade palette) and calls the appropriate load function. */
|
||||
void loadFromString(const AString & aString);
|
||||
|
||||
|
||||
|
@ -100,9 +119,21 @@ protected:
|
|||
UInt32 mMaxIndex;
|
||||
|
||||
|
||||
/** Loads the palette from the JSON representation.
|
||||
Throws a LoadFailedException if the loading fails hard (bad string format).
|
||||
If the string specifies duplicate entries (either to already existing entries, or to itself),
|
||||
the duplicates replace the current values silently (this allows us to chain multiple files as "overrides". */
|
||||
/** Loads the palette from the JSON representation, https://wiki.vg/Data_Generators
|
||||
Throws a LoadFailedException if the loading fails hard (bad string format);
|
||||
but still a part of the data may already be loaded at that point.
|
||||
See also: loadFromString(). */
|
||||
void loadFromJsonString(const AString & aJsonPalette);
|
||||
|
||||
/** Loads the palette from the regular or upgrade TSV representation.
|
||||
aIsUpgrade specifies whether the format is an upgrade TSV (true) or a regular one (false)
|
||||
Throws a LoadFailedException if the loading fails hard (bad string format);
|
||||
but still a part of the data may already be loaded at that point.
|
||||
See also: loadFromString(). */
|
||||
void loadFromTsv(const AString & aTsvPalette, bool aIsUpgrade);
|
||||
|
||||
/** Adds a mapping between the numeric and stringular representation into both maps,
|
||||
updates the mMaxIndex, if appropriate.
|
||||
Silently overwrites any previous mapping for the ID, if present, but keeps the old string->id mapping. */
|
||||
void addMapping(UInt32 aID, const AString & aBlockTypeName, const BlockState & aBlockState);
|
||||
};
|
||||
|
|
|
@ -24,10 +24,8 @@ public:
|
|||
|
||||
~cStopwatch()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_StartTime).count();
|
||||
LOGD("Stopwatch: %s took %.03f sec", m_Name.c_str(), static_cast<double>(duration) / 1000);
|
||||
#endif // _DEBUG
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_StartTime).count();
|
||||
LOG("Stopwatch: %s took %.03f sec", m_Name, static_cast<double>(duration) / 1000);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "Globals.h"
|
||||
#include "../TestHelpers.h"
|
||||
#include "BlockTypePalette.h"
|
||||
#include "Stopwatch.h"
|
||||
|
||||
|
||||
|
||||
|
@ -123,31 +124,7 @@ static void testTransformWithFallback()
|
|||
|
||||
|
||||
|
||||
/** Tests that loading a simple JSON palette succeeds. */
|
||||
static void testLoadSimpleSuccess(void)
|
||||
{
|
||||
LOG("Testing loading a simple JSON palette");
|
||||
|
||||
BlockTypePalette palette;
|
||||
|
||||
auto example = "{\"Metadata\":{\"ProtocolBlockTypePaletteVersion\":1}, \"Palette\":[{\
|
||||
\"props\": {\
|
||||
\"foo\": \"bar\"\
|
||||
}, \
|
||||
\"name\": \"b\", \
|
||||
\"id\": \"0\"\
|
||||
}]}";
|
||||
|
||||
palette.loadFromString(example);
|
||||
TEST_EQUAL(palette.maybeIndex("b", BlockState({{"foo", "bar"}})), (std::make_pair<UInt32, bool>(0, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("b", BlockState({{"foo", "baz"}})), (std::make_pair<UInt32, bool>(0, false)));
|
||||
TEST_EQUAL(palette.maybeIndex("a", BlockState({{"foo", "bar"}})), (std::make_pair<UInt32, bool>(0, false)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Tests that loading fails for nonsense input */
|
||||
static void testLoadErrors(void)
|
||||
{
|
||||
LOG("Testing palette load error reporting.");
|
||||
|
@ -164,69 +141,154 @@ static void testLoadErrors(void)
|
|||
|
||||
|
||||
|
||||
static void testLoadComplex1(void)
|
||||
/** Tests that loading a simple JSON palette succeeds. */
|
||||
static void testLoadJsonSimple(void)
|
||||
{
|
||||
LOG("Testing loading a complex palette (1)");
|
||||
LOG("Testing loading a simple JSON palette");
|
||||
|
||||
BlockTypePalette palette;
|
||||
auto str = "{\"Metadata\":{\"ProtocolBlockTypePaletteVersion\":1}, \"Palette\":[{\
|
||||
\"props\": {\
|
||||
\"foo\": \"bar\", \
|
||||
\"moo\": \"baz\"\
|
||||
|
||||
auto example = " \
|
||||
{ \
|
||||
\"minecraft:air\": { \
|
||||
\"states\": [ \
|
||||
{ \
|
||||
\"id\": 0, \
|
||||
\"default\": true \
|
||||
} \
|
||||
] \
|
||||
} \
|
||||
}";
|
||||
|
||||
palette.loadFromString(example);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:air", BlockState()), (std::make_pair<UInt32, bool>(0, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:air", BlockState({{"foo", "baz"}})).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:a", BlockState()).second, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Tests loading a complex block with multiple states and duplicates. */
|
||||
static void testLoadJsonComplex(void)
|
||||
{
|
||||
LOG("Testing loading a complex JSON palette");
|
||||
BlockTypePalette palette;
|
||||
auto str = " \
|
||||
{ \
|
||||
\"minecraft:oak_sapling\": { \
|
||||
\"properties\": { \
|
||||
\"stage\": [ \
|
||||
\"0\", \
|
||||
\"1\" \
|
||||
] \
|
||||
}, \
|
||||
\"id\": \"0\", \
|
||||
\"name\": \"b\"\
|
||||
}, {\
|
||||
\"props\": {\
|
||||
\"foo\": \"baz\", \
|
||||
\"moo\": \"bar\"\
|
||||
}, \
|
||||
\"id\": \"1\", \
|
||||
\"name\": \"b\"\
|
||||
}, {\
|
||||
\"props\": {\
|
||||
\"foo\": \"baz\", \
|
||||
\"moo\": \"bar\"\
|
||||
}, \
|
||||
\"id\": \"1001\", \
|
||||
\"name\": \"b\"\
|
||||
}]}";
|
||||
\"states\": [ \
|
||||
{ \
|
||||
\"properties\": { \
|
||||
\"stage\": \"0\" \
|
||||
}, \
|
||||
\"id\" : 21, \
|
||||
\"default\" : true \
|
||||
}, \
|
||||
{ \
|
||||
\"properties\": { \
|
||||
\"stage\": \"1\" \
|
||||
}, \
|
||||
\"id\" : 22 \
|
||||
}, \
|
||||
{ \
|
||||
\"properties\": { \
|
||||
\"stage\": \"1\" \
|
||||
}, \
|
||||
\"id\" : 23 \
|
||||
}\
|
||||
] \
|
||||
} \
|
||||
}";
|
||||
|
||||
// Note: The palette has a duplicate entry with differrent IDs, the latter ID wins
|
||||
palette.loadFromString(str);
|
||||
TEST_EQUAL(palette.maybeIndex("b", {{"foo", "bar"}}).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("b", {{"foo", "bar"}, {"moo", "baz"}}), (std::make_pair<UInt32, bool>(0, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("b", {{"foo", "baz"}, {"moo", "bar"}}), (std::make_pair<UInt32, bool>(1001, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("c", {{"foo", "baz"}, {"moo", "bar"}}).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:oak_sapling", {{"stage", "10"}}).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:oak_sapling", {{"stage", "0"}}), (std::make_pair<UInt32, bool>(21, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:oak_sapling", {{"stage", "1"}}), (std::make_pair<UInt32, bool>(23, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:oak_sapling", {{"foo", "baz"}}).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:oak_sap", {{"stage", "0"}}).second, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void testLoadComplex2(void)
|
||||
/** Tests loading a palette from simple regular TSV text data. */
|
||||
static void testLoadTsvRegular(void)
|
||||
{
|
||||
LOG("Testing loading a complex palette (2)");
|
||||
LOG("Testing loading a simple regular TSV palette");
|
||||
BlockTypePalette palette;
|
||||
auto str = "{\"Metadata\":{\"ProtocolBlockTypePaletteVersion\":1}, \"Palette\":[{\
|
||||
\"id\": \"0\", \
|
||||
\"name\": \"a\"\
|
||||
}, {\
|
||||
\"id\": \"1\", \
|
||||
\"name\": \"b\"\
|
||||
}]}";
|
||||
auto str = "\
|
||||
BlockTypePalette\r\n\
|
||||
FileVersion\t1\n\
|
||||
CommonPrefix\tminecraft:\r\n\
|
||||
\n\
|
||||
0\tair\r\n\
|
||||
1\tstone\n\
|
||||
2\tgrass\tsnow_covered\t0\n\
|
||||
3\tgrass\tsnow_covered\t1\n\
|
||||
";
|
||||
palette.loadFromString(str);
|
||||
TEST_EQUAL(palette.maybeIndex("a", BlockState()), (std::make_pair<UInt32, bool>(0, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("b", BlockState()), (std::make_pair<UInt32, bool>(1, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:air", BlockState()), (std::make_pair<UInt32, bool>(0, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:stone", BlockState()), (std::make_pair<UInt32, bool>(1, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:grass", BlockState({{"snow_covered", "0"}})), (std::make_pair<UInt32, bool>(2, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:grass", BlockState({{"snow_covered", "1"}})), (std::make_pair<UInt32, bool>(3, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:air", BlockState({{"snow_covered", "0"}})).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:grass", BlockState({{"snow_covered", "2"}})).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:grass", BlockState()).second, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void testLoadFromFile1(void)
|
||||
/** Tests loading a palette from simple upgrade TSV text data. */
|
||||
static void testLoadTsvUpgrade(void)
|
||||
{
|
||||
LOG("Testing loading a palette from file \"test.btp.json\"");
|
||||
LOG("Testing loading a simple upgrade TSV palette");
|
||||
BlockTypePalette palette;
|
||||
palette.loadFromString(cFile::ReadWholeFile("test.btp.json"));
|
||||
auto str = "\
|
||||
UpgradeBlockTypePalette\r\n\
|
||||
FileVersion\t1\n\
|
||||
CommonPrefix\tminecraft:\r\n\
|
||||
\n\
|
||||
0\t0\tair\r\n\
|
||||
1\t0\tstone\n\
|
||||
2\t0\tgrass\tsnow_covered\t0\n\
|
||||
2\t1\tgrass\tsnow_covered\t1\n\
|
||||
";
|
||||
palette.loadFromString(str);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:air", BlockState()), (std::make_pair<UInt32, bool>(0, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:stone", BlockState()), (std::make_pair<UInt32, bool>(16, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:grass", BlockState({{"snow_covered", "0"}})), (std::make_pair<UInt32, bool>(32, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:grass", BlockState({{"snow_covered", "1"}})), (std::make_pair<UInt32, bool>(33, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:air", BlockState({{"snow_covered", "0"}})).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:grass", BlockState({{"snow_covered", "2"}})).second, false);
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:grass", BlockState()).second, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Tests loading a palette from a real-life protocol base file (1.13). */
|
||||
static void testLoadFromBaseFile(void)
|
||||
{
|
||||
LOG("Testing loading a palette from file \"base.btp.txt\" (1.13)");
|
||||
BlockTypePalette palette;
|
||||
{
|
||||
auto fileContents = cFile::ReadWholeFile("base.btp.txt");
|
||||
cStopwatch sw("Loading palette");
|
||||
palette.loadFromString(fileContents);
|
||||
}
|
||||
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:air", BlockState()), (std::make_pair<UInt32, bool>(0, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:stone", BlockState()), (std::make_pair<UInt32, bool>(1, true)));
|
||||
|
@ -250,15 +312,19 @@ static void testLoadFromFile1(void)
|
|||
|
||||
|
||||
|
||||
static void testLoadFromFile2(void)
|
||||
/** Tests loading an upgrade-palette from a real-life upgrade file. */
|
||||
static void testLoadFromUpgradeFile(void)
|
||||
{
|
||||
LOG("Testing loading a palette from file \"base.btp.json\" (version 1.13)");
|
||||
LOG("Testing loading an upgrade palette from file \"UpgradeBlockTypePalette.txt\".");
|
||||
BlockTypePalette palette;
|
||||
palette.loadFromString(cFile::ReadWholeFile("base.btp.json"));
|
||||
{
|
||||
auto fileContents = cFile::ReadWholeFile("UpgradeBlockTypePalette.txt");
|
||||
cStopwatch sw("Loading upgrade palette");
|
||||
palette.loadFromString(fileContents);
|
||||
}
|
||||
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:air", BlockState()), (std::make_pair<UInt32, bool>(0, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:stone", BlockState()), (std::make_pair<UInt32, bool>(1, true)));
|
||||
TEST_EQUAL(palette.maybeIndex("minecraft:dirt", BlockState()), (std::make_pair<UInt32, bool>(10, true)));
|
||||
TEST_EQUAL(palette.entry(0), (std::make_pair<AString, BlockState>("minecraft:air", {})));
|
||||
TEST_EQUAL(palette.entry(44 * 16 + 8), (std::make_pair<AString, BlockState>("minecraft:stone_slab", {{"type", "top"}})));
|
||||
}
|
||||
|
||||
|
||||
|
@ -269,12 +335,13 @@ IMPLEMENT_TEST_MAIN("BlockTypePalette",
|
|||
testBasic();
|
||||
testTransformAddMissing();
|
||||
testTransformWithFallback();
|
||||
testLoadSimpleSuccess();
|
||||
testLoadErrors();
|
||||
testLoadComplex1();
|
||||
testLoadComplex2();
|
||||
testLoadFromFile1();
|
||||
testLoadFromFile2();
|
||||
testLoadJsonSimple();
|
||||
testLoadJsonComplex();
|
||||
testLoadTsvRegular();
|
||||
testLoadTsvUpgrade();
|
||||
testLoadFromBaseFile();
|
||||
testLoadFromUpgradeFile();
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ target_link_libraries(PalettedBlockAreaTest fmt::fmt jsoncpp_lib_static)
|
|||
|
||||
# Extra files for BlockTypePalette test:
|
||||
file (COPY
|
||||
test.btp.json
|
||||
../../Server/Protocol/1.13/base.btp.json
|
||||
../../Server/Protocol/1.13/base.btp.txt
|
||||
../../Server/Protocol/UpgradeBlockTypePalette.txt
|
||||
DESTINATION ./
|
||||
)
|
||||
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
{
|
||||
"Metadata": {
|
||||
"ProtocolBlockTypePaletteVersion": 1
|
||||
},
|
||||
"Palette": [{
|
||||
"id": 0,
|
||||
"name": "minecraft:air"
|
||||
}, {
|
||||
"id": 1,
|
||||
"name": "minecraft:stone"
|
||||
}, {
|
||||
"id": 221,
|
||||
"name": "minecraft:dark_oak_leaves",
|
||||
"props": {
|
||||
"persistent": "false",
|
||||
"distance": "4"
|
||||
}
|
||||
}, {
|
||||
"id": 222,
|
||||
"name": "minecraft:dark_oak_leaves",
|
||||
"props": {
|
||||
"persistent": "true",
|
||||
"distance": "5"
|
||||
}
|
||||
}, {
|
||||
"id": 223,
|
||||
"name": "minecraft:dark_oak_leaves",
|
||||
"props": {
|
||||
"persistent": "false",
|
||||
"distance": "5"
|
||||
}
|
||||
}, {
|
||||
"id": 224,
|
||||
"name": "minecraft:dark_oak_leaves",
|
||||
"props": {
|
||||
"persistent": "true",
|
||||
"distance": "6"
|
||||
}
|
||||
}, {
|
||||
"id": 225,
|
||||
"name": "minecraft:dark_oak_leaves",
|
||||
"props": {
|
||||
"persistent": "false",
|
||||
"distance": "6"
|
||||
}
|
||||
}, {
|
||||
"id": 226,
|
||||
"name": "minecraft:dark_oak_leaves",
|
||||
"props": {
|
||||
"persistent": "true",
|
||||
"distance": "7"
|
||||
}
|
||||
}, {
|
||||
"id": 227,
|
||||
"name": "minecraft:dark_oak_leaves",
|
||||
"props": {
|
||||
"persistent": "false",
|
||||
"distance": "7"
|
||||
}
|
||||
}, {
|
||||
"id": 9988,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "true",
|
||||
"shape": "north_south"
|
||||
}
|
||||
}, {
|
||||
"id": 9989,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "true",
|
||||
"shape": "east_west"
|
||||
}
|
||||
}, {
|
||||
"id": 9990,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "true",
|
||||
"shape": "ascending_east"
|
||||
}
|
||||
}, {
|
||||
"id": 9991,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "true",
|
||||
"shape": "ascending_west"
|
||||
}
|
||||
}, {
|
||||
"id": 9992,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "true",
|
||||
"shape": "ascending_north"
|
||||
}
|
||||
}, {
|
||||
"id": 9993,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "true",
|
||||
"shape": "ascending_south"
|
||||
}
|
||||
}, {
|
||||
"id": 9994,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "false",
|
||||
"shape": "north_south"
|
||||
}
|
||||
}, {
|
||||
"id": 9995,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "false",
|
||||
"shape": "east_west"
|
||||
}
|
||||
}, {
|
||||
"id": 9996,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "false",
|
||||
"shape": "ascending_east"
|
||||
}
|
||||
}, {
|
||||
"id": 9997,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "false",
|
||||
"shape": "ascending_west"
|
||||
}
|
||||
}, {
|
||||
"id": 9998,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "false",
|
||||
"shape": "ascending_north"
|
||||
}
|
||||
}, {
|
||||
"id": 9999,
|
||||
"name": "minecraft:powered_rail",
|
||||
"props": {
|
||||
"powered": "false",
|
||||
"shape": "ascending_south"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue