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
8586
Server/Protocol/1.13/base.btp.txt
Normal file
8586
Server/Protocol/1.13/base.btp.txt
Normal file
File diff suppressed because it is too large
Load Diff
11275
Server/Protocol/1.14.4/base.btp.txt
Normal file
11275
Server/Protocol/1.14.4/base.btp.txt
Normal file
File diff suppressed because it is too large
Load Diff
554
Server/Protocol/UpgradeBlockTypePalette.txt
Normal file
554
Server/Protocol/UpgradeBlockTypePalette.txt
Normal file
@ -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
|
5
Tools/BlockTypePaletteGenerator/.gitignore
vendored
Normal file
5
Tools/BlockTypePaletteGenerator/.gitignore
vendored
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
223
Tools/BlockTypePaletteGenerator/UpgradeGenerator.lua
Normal file
223
Tools/BlockTypePaletteGenerator/UpgradeGenerator.lua
Normal file
@ -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);
|
||||