Repository navigation
Expand file tree
/
Copy pathcraftengine-schemas.js
More file actions
2539 lines (2484 loc) · 216 KB
/
Copy pathcraftengine-schemas.js
File metadata and controls
2539 lines (2484 loc) · 216 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* ChoTenEditor CraftEngine (CE) 配置 Schema 定义
* 依赖: 无 (纯数据 + 小型构建助手)。在 craftengine-interpreter.js 之前加载。
* 数据源: CraftEngine 官方 Wiki (docs/configuration + docs/reference)
* 结构: window.CESchemas = { constants, conditions, functions, loot, sections, ... }
* 字段类型 (由 interpreter 表单引擎消费):
* text / number / bool / select / textarea / miniText / lines / linesScalar / kv /
* listOf / mapOf / union / idRef / sound / vec3 / color / events / obj / wholeText / kvWhole
* union 扩展项: noTypeKey(值不带 type 字段) / allowScalar(值可为标量) / negatable(生成 !type 选项)
* / types.{k}.widget(以其它 widget 渲染该类型体) / sharedKeys(切换类型时保留的公共键)
*/
(function () {
'use strict';
var ROOT = typeof window !== 'undefined' ? window : globalThis;
var S = {};
function l(zh, en) { return { zh: zh, en: en }; }
function f(key, zh, en, type, extra) {
var o = extra || {};
o.key = key;
o.label = l(zh, en);
if (type) o.type = type;
return o;
}
// ============ 常量 ============
S.constants = {
// 常用原版物品 (datalist 数据源, 不完全)
vanillaItems: [
'minecraft:air', 'minecraft:stone', 'minecraft:granite', 'minecraft:diorite', 'minecraft:andesite',
'minecraft:deepslate', 'minecraft:cobblestone', 'minecraft:dirt', 'minecraft:grass_block',
'minecraft:sand', 'minecraft:gravel', 'minecraft:oak_log', 'minecraft:spruce_log',
'minecraft:birch_log', 'minecraft:jungle_log', 'minecraft:acacia_log', 'minecraft:dark_oak_log',
'minecraft:mangrove_log', 'minecraft:cherry_log', 'minecraft:oak_planks', 'minecraft:spruce_planks',
'minecraft:birch_planks', 'minecraft:jungle_planks', 'minecraft:acacia_planks',
'minecraft:dark_oak_planks', 'minecraft:mangrove_planks', 'minecraft:cherry_planks',
'minecraft:oak_leaves', 'minecraft:spruce_leaves', 'minecraft:birch_leaves', 'minecraft:jungle_leaves',
'minecraft:acacia_leaves', 'minecraft:dark_oak_leaves', 'minecraft:mangrove_leaves',
'minecraft:cherry_leaves', 'minecraft:glass', 'minecraft:obsidian', 'minecraft:bedrock',
'minecraft:brick', 'minecraft:stone_bricks', 'minecraft:nether_brick', 'minecraft:netherrack',
'minecraft:soul_sand', 'minecraft:end_stone', 'minecraft:purpur_block', 'minecraft:prismarine',
'minecraft:sea_lantern', 'minecraft:glowstone', 'minecraft:redstone_lamp', 'minecraft:iron_block',
'minecraft:gold_block', 'minecraft:diamond_block', 'minecraft:emerald_block', 'minecraft:netherite_block',
'minecraft:redstone_block', 'minecraft:lapis_block', 'minecraft:copper_block', 'minecraft:amethyst_block',
'minecraft:note_block', 'minecraft:mushroom_stem', 'minecraft:red_mushroom_block',
'minecraft:brown_mushroom_block', 'minecraft:oak_sapling', 'minecraft:spruce_sapling',
'minecraft:birch_sapling', 'minecraft:jungle_sapling', 'minecraft:acacia_sapling',
'minecraft:dark_oak_sapling', 'minecraft:cherry_sapling', 'minecraft:cactus', 'minecraft:sugar_cane',
'minecraft:bamboo', 'minecraft:vine', 'minecraft:lily_pad', 'minecraft:kelp', 'minecraft:seagrass',
'minecraft:chorus_flower', 'minecraft:paper', 'minecraft:stick', 'minecraft:bone', 'minecraft:bone_meal',
'minecraft:feather', 'minecraft:flint', 'minecraft:string', 'minecraft:leather', 'minecraft:rabbit_hide',
'minecraft:slime_ball', 'minecraft:clay_ball', 'minecraft:gunpowder', 'minecraft:blaze_rod',
'minecraft:blaze_powder', 'minecraft:ender_pearl', 'minecraft:ender_eye', 'minecraft:ghast_tear',
'minecraft:magma_cream', 'minecraft:nether_star', 'minecraft:experience_bottle', 'minecraft:book',
'minecraft:enchanted_book', 'minecraft:book_written', 'minecraft:name_tag', 'minecraft:map',
'minecraft:compass', 'minecraft:clock', 'minecraft:recovery_compass', 'minecraft:torch',
'minecraft:soul_torch', 'minecraft:lantern', 'minecraft:soul_lantern', 'minecraft:sea_pickle',
'minecraft:glass_bottle', 'minecraft:water_bucket', 'minecraft:lava_bucket', 'minecraft:milk_bucket',
'minecraft:bowl', 'minecraft:bow', 'minecraft:arrow', 'minecraft:spectral_arrow', 'minecraft:crossbow',
'minecraft:shield', 'minecraft:fishing_rod', 'minecraft:carrot_on_a_stick', 'minecraft:elytra',
'minecraft:trident', 'minecraft:wooden_sword', 'minecraft:stone_sword', 'minecraft:iron_sword',
'minecraft:golden_sword', 'minecraft:diamond_sword', 'minecraft:netherite_sword',
'minecraft:wooden_pickaxe', 'minecraft:stone_pickaxe', 'minecraft:iron_pickaxe',
'minecraft:golden_pickaxe', 'minecraft:diamond_pickaxe', 'minecraft:netherite_pickaxe',
'minecraft:wooden_axe', 'minecraft:stone_axe', 'minecraft:iron_axe', 'minecraft:golden_axe',
'minecraft:diamond_axe', 'minecraft:netherite_axe', 'minecraft:wooden_shovel', 'minecraft:stone_shovel',
'minecraft:iron_shovel', 'minecraft:golden_shovel', 'minecraft:diamond_shovel', 'minecraft:netherite_shovel',
'minecraft:wooden_hoe', 'minecraft:stone_hoe', 'minecraft:iron_hoe', 'minecraft:golden_hoe',
'minecraft:diamond_hoe', 'minecraft:netherite_hoe', 'minecraft:shears', 'minecraft:flint_and_steel',
'minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:bread',
'minecraft:cooked_beef', 'minecraft:cooked_porkchop', 'minecraft:cooked_chicken',
'minecraft:cooked_cod', 'minecraft:cooked_salmon', 'minecraft:cookie', 'minecraft:cake',
'minecraft:pumpkin_pie', 'minecraft:sweet_berries', 'minecraft:glow_berries', 'minecraft:honey_bottle',
'minecraft:golden_carrot', 'minecraft:carrot', 'minecraft:potato', 'minecraft:baked_potato',
'minecraft:beetroot', 'minecraft:melon_slice', 'minecraft:chorus_fruit', 'minecraft:dried_kelp',
'minecraft:coal', 'minecraft:charcoal', 'minecraft:iron_ingot', 'minecraft:gold_ingot',
'minecraft:copper_ingot', 'minecraft:netherite_ingot', 'minecraft:diamond', 'minecraft:emerald',
'minecraft:lapis_lazuli', 'minecraft:quartz', 'minecraft:amethyst_shard', 'minecraft:redstone',
'minecraft:iron_nugget', 'minecraft:gold_nugget', 'minecraft:netherite_scrap', 'minecraft:echo_shard',
'minecraft:leather_helmet', 'minecraft:leather_chestplate', 'minecraft:leather_leggings',
'minecraft:leather_boots', 'minecraft:iron_helmet', 'minecraft:iron_chestplate',
'minecraft:iron_leggings', 'minecraft:iron_boots', 'minecraft:golden_helmet', 'minecraft:golden_chestplate',
'minecraft:golden_leggings', 'minecraft:golden_boots', 'minecraft:diamond_helmet',
'minecraft:diamond_chestplate', 'minecraft:diamond_leggings', 'minecraft:diamond_boots',
'minecraft:netherite_helmet', 'minecraft:netherite_chestplate', 'minecraft:netherite_leggings',
'minecraft:netherite_boots', 'minecraft:turtle_helmet', 'minecraft:chainmail_helmet',
'minecraft:chainmail_chestplate', 'minecraft:chainmail_leggings', 'minecraft:chainmail_boots',
'minecraft:potion', 'minecraft:splash_potion', 'minecraft:lingering_potion', 'minecraft:spawn_egg',
'minecraft:chest', 'minecraft:barrel', 'minecraft:furnace', 'minecraft:crafting_table', 'minecraft:anvil',
'minecraft:enchanting_table', 'minecraft:brewing_stand', 'minecraft:beacon', 'minecraft:ender_chest',
'minecraft:hopper', 'minecraft:dispenser', 'minecraft:dropper', 'minecraft:piston', 'minecraft:sticky_piston',
'minecraft:lever', 'minecraft:redstone_torch', 'minecraft:redstone_lamp', 'minecraft:daylight_detector',
'minecraft:repeater', 'minecraft:comparator', 'minecraft:target', 'minecraft:bell', 'minecraft:campfire',
'minecraft:soul_campfire', 'minecraft:ladder', 'minecraft:oak_door', 'minecraft:iron_door',
'minecraft:oak_trapdoor', 'minecraft:iron_trapdoor', 'minecraft:oak_fence', 'minecraft:oak_fence_gate',
'minecraft:oak_slab', 'minecraft:oak_stairs', 'minecraft:oak_button', 'minecraft:stone_button',
'minecraft:oak_pressure_plate', 'minecraft:stone_pressure_plate', 'minecraft:oak_sign',
'minecraft:oak_hanging_sign', 'minecraft:item_frame', 'minecraft:painting', 'minecraft:armor_stand',
'minecraft:minecart', 'minecraft:chest_minecart', 'minecraft:boat', 'minecraft:written_book',
'minecraft:firework_rocket', 'minecraft:firework_star', 'minecraft:lead', 'minecraft:saddle',
'minecraft:egg', 'minecraft:snowball', 'minecraft:ender_pearl', 'minecraft:heart_of_the_sea',
'minecraft:nautilus_shell', 'minecraft:scute', 'minecraft:nether_wart', 'minecraft:poisonous_potato',
'minecraft:spider_eye', 'minecraft:fermented_spider_eye', 'minecraft:blaze_cream', 'minecraft:rabbit_foot',
'minecraft:phantom_membrane', 'minecraft:shulker_shell', 'minecraft:totem_of_undying',
'minecraft:dragon_breath', 'minecraft:music_disc_13', 'minecraft:music_disc_cat',
'minecraft:music_disc_pigstep', 'minecraft:goat_horn', 'minecraft:honeycomb', 'minecraft:beehive',
'minecraft:honey_block', 'minecraft:slime_block', 'minecraft:ice', 'minecraft:packed_ice',
'minecraft:blue_ice', 'minecraft:snow_block', 'minecraft:magma_block', 'minecraft:tnt',
'minecraft:sponge', 'minecraft:wet_sponge', 'minecraft:bookshelf', 'minecraft:jukebox',
'minecraft:note_block', 'minecraft:mushroom_stem', 'minecraft:shroomlight', 'minecraft:sculk',
'minecraft:sculk_sensor', 'minecraft:sculk_shrieker', 'minecraft:sculk_catalyst', 'minecraft:sculk_vein',
'minecraft:reinforced_deepslate', 'minecraft:echo_shard', 'minecraft:disc_fragment_5',
],
equipmentSlots: ['head', 'chest', 'legs', 'feet', 'body', 'mainhand', 'offhand', 'saddle'],
equipmentLayers: ['humanoid', 'humanoid_leggings', 'wings', 'wolf_body', 'horse_body', 'llama_body', 'pig_saddle', 'strider_saddle', 'camel_saddle', 'horse_saddle', 'donkey_saddle', 'mule_saddle', 'skeleton_horse_saddle', 'zombie_horse_saddle', 'happy_ghast_body', 'camel_husk_saddle', 'nautilus_body'],
soundSources: ['music', 'master', 'record', 'weather', 'block', 'hostile', 'neutral', 'player', 'ambient', 'voice', 'ui'],
pushReactions: ['PUSH_PULL', 'PUSH', 'POPPED', 'IMMOVEABLE', 'IGNORE_ENTITY', 'NORMAL', 'DESTROY', 'BLOCK', 'IGNORE', 'PUSH_ONLY'],
billboards: ['fixed', 'vertical', 'horizontal', 'center'],
displayTransforms: ['none', 'third_person_left_hand', 'third_person_right_hand', 'first_person_left_hand', 'first_person_right_hand', 'head', 'gui', 'ground', 'fixed'],
alignments: ['any', 'center', 'half', 'quarter', 'corner', 'center_quarter'],
rotations: ['any', 'four', 'eight', 'sixteen', 'north', 'east', 'west', 'south'],
hitboxDirections: ['UP', 'DOWN', 'NORTH', 'WEST', 'EAST', 'SOUTH'],
glowColors: ['black', 'dark_blue', 'dark_green', 'dark_aqua', 'dark_red', 'dark_purple', 'gold', 'gray', 'dark_gray', 'blue', 'green', 'aqua', 'red', 'light_purple', 'yellow', 'white'],
openWindowTypes: ['anvil', 'enchantment', 'grindstone', 'loom', 'smithing', 'crafting', 'cartography'],
eventTriggers: ['break', 'place', 'right_click', 'left_click', 'consume', 'pick_up', 'attack', 'step'],
equipmentTypes: ['component', 'trim'],
lootSourceTypes: ['block_break', 'block_shear', 'entity_death', 'entity_drop', 'entity_shear', 'fishing', 'piglin_barter', 'container', 'archaeology', 'harvest', 'shear_block', 'vault', 'advancement'],
lootOverwrites: ['none', 'items', 'experience', 'all'],
recipeTypes: ['shaped', 'shapeless', 'shaped_transform', 'shapeless_transform', 'smelting', 'blasting', 'smoking', 'campfire_cooking', 'stonecutting', 'smithing_transform', 'smithing_trim', 'brewing'],
autoStateGroups: ['solid', 'note_block', 'mushroom_stem', 'red_mushroom_block', 'brown_mushroom_block', 'mushroom', 'tintable_leaves', 'waterlogged_tintable_leaves', 'non_tintable_leaves', 'waterlogged_non_tintable_leaves', 'leaves', 'waterlogged_leaves', 'lower_tripwire', 'higher_tripwire', 'tripwire', 'sapling', 'pressure_plate', 'cactus', 'sugar_cane', 'weeping_vine', 'twisting_vine', 'cave_vine', 'kelp', 'chorus'],
blockPropertyTypes: ['boolean', 'int', 'string', 'direction', 'horizontal_direction', 'axis', 'single_block_half', 'double_block_half', 'hinge', 'slab_type', 'stairs_shape', 'sofa_shape', 'anchor_type'],
// 特殊属性名 → 自动旋转等硬编码行为
specialPropertyNames: ['axis', 'facing', 'facing_clockwise', 'rotation', 'waterlogged'],
instruments: ['BASEDRUM', 'SNARE', 'HAT', 'BASS', 'FLUTE', 'BELL', 'GUITAR', 'CHIME', 'XYLOPHONE', 'IRON_XYLOPHONE', 'COW_BELL', 'DIDGERIDOO', 'BIT', 'BANJO', 'PLING', 'HARP'],
fluidStates: ['empty', 'water', 'lava'],
attributeOperations: ['add_value', 'add_multiplied_base', 'add_multiplied_total'],
attributeSlots: ['any', 'mainhand', 'offhand', 'hand', 'feet', 'legs', 'chest', 'head', 'body', 'saddle', 'equipment'],
};
// ============ 条件类型 (wiki reference/conditions.mdx) ============
var COND_TYPES = {
any_of: { label: l('任一满足 (any_of)', 'Any Of'), fields: [f('terms', '子条件', 'Terms', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES_REF }, label: l('子条件', 'Terms') })] },
all_of: { label: l('全部满足 (all_of)', 'All Of'), fields: [f('terms', '子条件', 'Terms', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES_REF }, label: l('子条件', 'Terms') })] },
inverted: { label: l('取反 (inverted)', 'Inverted'), fields: [f('term', '条件', 'Term', 'union', { types: COND_TYPES_REF, negatable: true, label: l('条件', 'Term') })] },
falling_block: { label: l('方块坠落掉落', 'Falling Block') },
survives_explosion: { label: l('爆炸存活', 'Survives Explosion') },
has_item: { label: l('手中有物品', 'Has Item') },
match_item: { label: l('匹配手中物品', 'Match Item'), fields: [f('id', '物品 ID', 'Item ID', 'linesScalar', { hint: l('单个 ID 或每行一个 ID', 'Single ID or one ID per line'), datalist: 'items' }), f('regex', '正则匹配', 'Regex', 'bool')] },
match_block_property: { label: l('匹配方块属性', 'Match Block Property'), fields: [f('properties', '属性', 'Properties', 'mapOf', { valueType: { type: 'scalar' }, label: l('属性', 'Properties') })] },
match_block: { label: l('匹配方块', 'Match Block'), fields: [f('id', '方块 ID', 'Block ID', 'text', { datalist: 'blocks' }), f('x', 'X', 'X', 'number'), f('y', 'Y', 'Y', 'number'), f('z', 'Z', 'Z', 'number'), f('regex', '正则匹配', 'Regex', 'bool')] },
match_entity: { label: l('匹配实体', 'Match Entity'), fields: [f('id', '实体 ID', 'Entity ID', 'text'), f('regex', '正则匹配', 'Regex', 'bool')] },
match_furniture_variant: { label: l('匹配家具变体', 'Match Furniture Variant'), fields: [f('variants', '变体', 'Variants', 'lines', { hint: l('每行一个变体名', 'One variant per line') })] },
enchantment: { label: l('附魔检测', 'Enchantment'), fields: [f('predicate', '谓词', 'Predicate', 'text', { hint: l('如 minecraft:silk_touch>=1 (> >= = < <=)', 'e.g. minecraft:silk_touch>=1') })] },
table_bonus: { label: l('附魔概率表 (table_bonus)', 'Table Bonus'), fields: [f('enchantment', '附魔', 'Enchantment', 'text'), f('chances', '概率', 'Chances', 'lines', { hint: l('每行一个概率, 对应附魔等级', 'One chance per line, per enchantment level') })] },
random: { label: l('随机概率', 'Random'), fields: [f('value', '概率', 'Value', 'number', { hint: l('0.1 = 10%', '0.1 = 10%') })] },
permission: { label: l('权限', 'Permission'), fields: [f('permission', '权限', 'Permission', 'text')] },
expression: { label: l('表达式', 'Expression'), fields: [f('expression', '表达式', 'Expression', 'text', { hint: l('返回 true 时满足 (EvalEx)', 'Passes when it returns true (EvalEx)') })] },
string_equals: { label: l('字符串相等', 'String Equals'), fields: [f('value1', '值 1', 'Value 1', 'text'), f('value2', '值 2', 'Value 2', 'text')] },
string_contains: { label: l('字符串包含', 'String Contains'), fields: [f('value1', '值 1', 'Value 1', 'text'), f('value2', '值 2', 'Value 2', 'text')] },
regex: { label: l('正则匹配', 'Regex'), fields: [f('value', '值', 'Value', 'text'), f('regex', '正则', 'Regex', 'text')] },
is_null: { label: l('参数为空', 'Is Null'), fields: [f('argument', '参数', 'Argument', 'text', { hint: l('如 player.main_hand_item', 'e.g. player.main_hand_item') })] },
hand: { label: l('交互手', 'Hand'), fields: [f('hand', '手', 'Hand', 'select', { options: ['main_hand', 'off_hand'] })] },
on_cooldown: { label: l('冷却中', 'On Cooldown'), fields: [f('id', '冷却 ID', 'Cooldown ID', 'text', { hint: l('由 set_cooldown 函数设置', 'Set by the set_cooldown function') })] },
'worldguard:region': { label: l('WorldGuard 区域', 'WorldGuard Region'), fields: [f('mode', '模式', 'Mode', 'select', { options: [{ v: '1', l: '1 (并集)' }, { v: '2', l: '2 (交集)' }] }), f('regions', '区域', 'Regions', 'lines')] },
distance: { label: l('距离范围', 'Distance'), fields: [f('min', '最小', 'Min', 'number'), f('max', '最大', 'Max', 'number')] },
has_player: { label: l('有玩家', 'Has Player') },
inventory_has_item: { label: l('背包有物品', 'Inventory Has Item'), fields: [f('id', '物品 ID', 'Item ID', 'text', { datalist: 'items' }), f('count', '数量', 'Count', 'number')] },
is_bedrock_player: { label: l('基岩版玩家', 'Is Bedrock Player') },
test_flag: { label: l('测试交互旗标', 'Test Flag'), fields: [f('flag', '旗标', 'Flag', 'select', { options: ['break', 'place', 'interact', 'open_container'] })] },
world: { label: l('世界', 'World'), fields: [f('world', '世界', 'World', 'text')] },
js: { label: l('JavaScript', 'JS'), fields: [
f('script', '脚本 ID', 'Script ID', 'text', { hint: l('namespace:path', 'namespace:path') }),
f('function', '函数', 'Function', 'text', { hint: l('默认 main', 'Default: main') }),
f('args', '参数', 'Args', 'union', { noTypeKey: true, label: l('参数', 'Args'), types: {
list: { label: l('列表', 'List'), widget: { type: 'listOf', label: l('参数', 'Args'), itemType: { type: 'text' } } },
map: { label: l('映射', 'Map'), widget: { type: 'mapOf', label: l('参数', 'Args'), valueType: { type: 'scalar' } } },
} }),
]},
};
function COND_TYPES_REF() { return COND_TYPES; }
// ============ 函数类型 (wiki reference/events.mdx) ============
// 通用: 每个函数都附带 conditions 条件列表 (自动追加)
function FN(fields) {
var flds = fields.slice ? fields.slice() : [];
flds.push(f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions'), hint: l('全部满足才执行该函数', 'All must pass for the function to run') }));
return { fields: flds };
}
var FN_TYPES = {
cancel_event: { label: l('取消事件', 'Cancel Event') },
run: { label: l('依次执行 (run)', 'Run'), fields: [
f('delay', '延迟 (tick)', 'Delay (ticks)', 'number', { hint: l('默认 0', 'Default 0') }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: FN_TYPES_REF }, label: l('函数', 'Functions') }),
] },
command: { label: l('执行命令', 'Command'), fields: [
f('command', '命令', 'Command', 'linesScalar', { hint: l('支持 <arg:...> 占位符; 多行 = 多条命令', 'Supports <arg:...>; multiple lines = multiple commands') }),
f('target', '目标', 'Target', 'text', { hint: l('all / self / 玩家选择器', 'all / self / player selector') }),
f('as_player', '以玩家身份', 'As Player', 'bool'),
f('as_op', '以 OP 身份', 'As OP', 'bool', { hint: l('不推荐, 有安全风险', 'Not recommended, security risk') }),
f('as_event', '以事件执行', 'As Event', 'bool', { hint: l('部分事件式命令插件需要', 'Some event-based command plugins require this') }),
] },
message: { label: l('发送消息', 'Message'), fields: [
f('message', '消息', 'Message', 'linesScalar', { hint: l('多行 = 多条消息', 'Multiple lines = multiple messages') }),
f('target', '目标', 'Target', 'text', { hint: l('all / self / 玩家选择器', 'all / self / player selector') }),
f('overlay', 'Actionbar', 'Overlay', 'bool', { hint: l('true = actionbar, false = 聊天框', 'true = actionbar, false = chat') }),
] },
actionbar: { label: l('Actionbar', 'Actionbar'), fields: [
f('actionbar', '内容', 'Content', 'text'),
f('target', '目标', 'Target', 'text'),
] },
title: { label: l('Title', 'Title'), fields: [
f('title', '标题', 'Title', 'miniText'),
f('subtitle', '副标题', 'Subtitle', 'miniText'),
f('fade_in', '淡入 (tick)', 'Fade In', 'number'),
f('stay', '停留 (tick)', 'Stay', 'number'),
f('fade_out', '淡出 (tick)', 'Fade Out', 'number'),
] },
open_window: { label: l('打开界面', 'Open Window'), fields: [
f('gui_type', '界面类型', 'GUI Type', 'select', { options: S.constants.openWindowTypes }),
f('title', '标题', 'Title', 'text'),
f('target', '目标', 'Target', 'text'),
] },
break_block: { label: l('破坏方块', 'Break Block'), fields: [
f('x', 'X', 'X', 'text', { hint: l('默认 <arg:position.x>', 'Default <arg:position.x>') }),
f('y', 'Y', 'Y', 'text', { hint: l('默认 <arg:position.y>', 'Default <arg:position.y>') }),
f('z', 'Z', 'Z', 'text', { hint: l('默认 <arg:position.z>', 'Default <arg:position.z>') }),
] },
place_block: { label: l('放置方块', 'Place Block'), fields: [
f('block_state', '方块状态', 'Block State', 'text', { hint: l('如 default:chinese_lantern', 'e.g. default:chinese_lantern'), datalist: 'blocks' }),
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
] },
update_block_property: { label: l('更新方块属性', 'Update Block Property'), fields: [
f('properties', '属性', 'Properties', 'mapOf', { valueType: { type: 'scalar' }, label: l('属性', 'Properties') }),
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
] },
transform_block: { label: l('转换方块', 'Transform Block'), fields: [
f('block', '方块', 'Block', 'text', { datalist: 'blocks' }),
f('properties', '属性', 'Properties', 'mapOf', { valueType: { type: 'scalar' }, label: l('属性', 'Properties') }),
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
] },
drop_loot: { label: l('掉落战利品', 'Drop Loot'), fields: [
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
f('to_inventory', '直接进背包', 'To Inventory', 'bool'),
f('loot', '战利品表', 'Loot Table', 'union', { noTypeKey: true, allowScalar: { type: 'text', placeholder: 'minecraft:chests/simple_dungeon' }, label: l('战利品表', 'Loot Table'), types: LOOT_TYPES_REF() }),
] },
update_interaction_tick: { label: l('更新交互计时', 'Update Interaction Tick') },
set_count: { label: l('设置物品数量', 'Set Count'), fields: [
f('add', '追加', 'Add', 'bool'), f('count', '数量', 'Count', 'number'),
f('target', '目标', 'Target', 'text'),
] },
set_food: { label: l('设置饱食度', 'Set Food'), fields: [
f('add', '追加', 'Add', 'bool'), f('food', '饱食度 (0~20)', 'Food (0-20)', 'number'),
f('target', '目标', 'Target', 'text'),
] },
set_saturation: { label: l('设置饱和度', 'Set Saturation'), fields: [
f('add', '追加', 'Add', 'bool'), f('saturation', '饱和度 (0~10)', 'Saturation (0-10)', 'number'),
f('target', '目标', 'Target', 'text'),
] },
swing_hand: { label: l('挥手', 'Swing Hand'), fields: [
f('hand', '手', 'Hand', 'select', { options: ['main_hand', 'off_hand'], hint: l('留空 = 事件中的手', 'Empty = the hand in this context') }),
] },
particle: { label: l('生成粒子', 'Particle'), fields: [
f('particle', '粒子', 'Particle', 'text', { hint: l('如 minecraft:end_rod', 'e.g. minecraft:end_rod') }),
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
f('count', '数量', 'Count', 'number'), f('offset_x', '偏移 X', 'Offset X', 'number'),
f('offset_y', '偏移 Y', 'Offset Y', 'number'), f('offset_z', '偏移 Z', 'Offset Z', 'number'),
f('speed', '速度', 'Speed', 'number'),
] },
potion_effect: { label: l('药水效果', 'Potion Effect'), fields: [
f('potion_effect', '效果', 'Effect', 'text', { hint: l('如 minecraft:blindness', 'e.g. minecraft:blindness') }),
f('duration', '时长 (tick)', 'Duration', 'number'), f('amplifier', '等级', 'Amplifier', 'number'),
f('ambient', '环境 (信标)', 'Ambient', 'bool'), f('particles', '粒子', 'Particles', 'bool'),
f('show_icon', '显示图标', 'Show Icon', 'bool'),
] },
remove_potion_effect: { label: l('移除药水效果', 'Remove Potion Effect'), fields: [
f('potion_effect', '效果', 'Effect', 'text'), f('all', '全部', 'All', 'bool'),
] },
leveler_exp: { label: l('技能经验 (leveler)', 'Leveler Exp'), fields: [
f('plugin', '插件', 'Plugin', 'text', { hint: l('如 AuraSkills', 'e.g. AuraSkills') }),
f('leveler', '技能/职业 ID', 'Leveler ID', 'text'), f('count', '经验', 'Exp', 'number'),
] },
set_cooldown: { label: l('设置冷却', 'Set Cooldown'), fields: [
f('time', '时长', 'Time', 'text', { hint: l('如 1m30s (t/s/m/h/d/w)', 'e.g. 1m30s (t/s/m/h/d/w)') }),
f('id', '冷却 ID', 'Cooldown ID', 'text'), f('add', '累加', 'Add', 'bool'),
] },
remove_cooldown: { label: l('移除冷却', 'Remove Cooldown'), fields: [
f('id', '冷却 ID', 'Cooldown ID', 'text'), f('all', '全部', 'All', 'bool'),
] },
play_sound: { label: l('播放音效', 'Play Sound'), fields: [
f('sound', '音效', 'Sound', 'text', { hint: l('如 minecraft:block.xxx.xxx', 'e.g. minecraft:block.xxx.xxx') }),
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
f('target', '目标', 'Target', 'text'), f('pitch', '音调', 'Pitch', 'number'),
f('volume', '音量', 'Volume', 'number'), f('source', '来源', 'Source', 'select', { options: S.constants.soundSources }),
] },
cast_mythic_skill: { label: l('释放 MythicMobs 技能', 'Cast Mythic Skill'), fields: [
f('skill', '技能 ID', 'Skill ID', 'text'), f('power', '强度', 'Power', 'number'),
] },
spawn_furniture: { label: l('生成家具', 'Spawn Furniture'), fields: [
f('furniture_id', '家具 ID', 'Furniture ID', 'text', { datalist: 'furniture' }),
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
f('pitch', 'Pitch', 'Pitch', 'text'), f('yaw', 'Yaw', 'Yaw', 'text'),
f('variant', '变体', 'Variant', 'text'), f('play_sound', '播放音效', 'Play Sound', 'bool'),
] },
remove_furniture: { label: l('移除家具', 'Remove Furniture'), fields: [
f('drop_loot', '掉落战利品', 'Drop Loot', 'bool'), f('play_sound', '播放音效', 'Play Sound', 'bool'),
] },
replace_furniture: { label: l('替换家具', 'Replace Furniture'), fields: [
f('furniture_id', '家具 ID', 'Furniture ID', 'text', { datalist: 'furniture' }),
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
f('pitch', 'Pitch', 'Pitch', 'text'), f('yaw', 'Yaw', 'Yaw', 'text'),
f('variant', '变体', 'Variant', 'text'), f('drop_loot', '掉落战利品', 'Drop Loot', 'bool'),
f('play_sound', '播放音效', 'Play Sound', 'bool'),
] },
rotate_furniture: { label: l('旋转家具', 'Rotate Furniture'), fields: [
f('degree', '角度', 'Degree', 'number'),
f('on_success', '成功时', 'On Success', 'listOf', { itemType: { type: 'union', types: FN_TYPES_REF }, label: l('成功时', 'On Success') }),
f('on_failure', '失败时', 'On Failure', 'listOf', { itemType: { type: 'union', types: FN_TYPES_REF }, label: l('失败时', 'On Failure') }),
] },
teleport: { label: l('传送', 'Teleport'), fields: [
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
f('pitch', 'Pitch', 'Pitch', 'text'), f('yaw', 'Yaw', 'Yaw', 'text'), f('world', '世界', 'World', 'text'),
] },
toast: { label: l('发送 Toast', 'Toast'), fields: [
f('toast', '内容', 'Content', 'text'),
f('advancement_type', '类型', 'Type', 'select', { options: ['goal', 'task', 'challenge'] }),
f('icon', '图标', 'Icon', 'text', { datalist: 'items' }),
] },
damage: { label: l('造成伤害', 'Damage'), fields: [
f('target', '目标', 'Target', 'text'), f('amount', '伤害', 'Amount', 'number'),
f('damage_type', '伤害类型', 'Damage Type', 'text', { hint: l('默认 generic', 'Default: generic') }),
] },
set_variable: { label: l('设置变量', 'Set Variable'), fields: [
f('name', '变量名', 'Name', 'text', { hint: l('用 <arg:var_[name]> 访问', 'Access via <arg:var_[name]>') }),
f('number', '数字', 'Number', 'number'), f('as_int', '取整', 'As Int', 'bool'),
f('text', '文本', 'Text', 'text'),
] },
merchant_trade: { label: l('村民交易', 'Merchant Trade'), fields: [
f('title', '标题', 'Title', 'text'),
f('offers', '交易项', 'Offers', 'listOf', {
label: l('交易项', 'Offers'),
itemType: { type: 'object', fields: [
f('cost_1', '花费 1', 'Cost 1', 'union', { noTypeKey: true, label: l('花费 1', 'Cost 1'), types: {
string: { label: l('物品 ID', 'Item ID'), widget: { type: 'text' } },
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('item', '物品', 'Item', 'text', { datalist: 'items' }),
f('count', '数量', 'Count', 'number'),
f('components', '组件', 'Components', 'kv'),
] } },
} }),
f('cost_2', '花费 2 (可选)', 'Cost 2', 'union', { noTypeKey: true, label: l('花费 2', 'Cost 2'), types: {
string: { label: l('物品 ID', 'Item ID'), widget: { type: 'text' } },
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('item', '物品', 'Item', 'text', { datalist: 'items' }), f('count', '数量', 'Count', 'number'),
] } },
} }),
f('result', '结果', 'Result', 'union', { noTypeKey: true, label: l('结果', 'Result'), types: {
string: { label: l('物品 ID', 'Item ID'), widget: { type: 'text' } },
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('item', '物品', 'Item', 'text', { datalist: 'items' }), f('count', '数量', 'Count', 'number'),
] } },
} }),
f('experience', '经验', 'Experience', 'number'),
] },
}),
] },
remove_entity: { label: l('移除实体', 'Remove Entity') },
if_else: { label: l('条件分支 (if_else)', 'If Else'), fields: [
f('rules', '规则', 'Rules', 'listOf', {
label: l('规则', 'Rules'),
itemType: { type: 'object', fields: [
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: FN_TYPES_REF }, label: l('函数', 'Functions') }),
] },
hint: l('依次匹配, 最后一条无条件的规则作为 else', 'First match wins; a rule without conditions acts as else'),
}),
] },
when: { label: l('多路分支 (when)', 'When'), fields: [
f('source', '源值', 'Source', 'text', { hint: l('如 <papi:player_world>', 'e.g. <papi:player_world>') }),
f('cases', '分支', 'Cases', 'listOf', {
label: l('分支', 'Cases'),
itemType: { type: 'object', fields: [
f('when', '匹配值', 'When', 'linesScalar', { hint: l('单行 = 单个值, 多行 = 多个值', 'One line = one value, multiple lines = several') }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: FN_TYPES_REF }, label: l('函数', 'Functions') }),
] },
}),
f('fallback', '兜底', 'Fallback', 'listOf', { itemType: { type: 'union', types: FN_TYPES_REF }, label: l('兜底', 'Fallback') }),
] },
damage_item: { label: l('消耗耐久', 'Damage Item'), fields: [
f('amount', '数量', 'Amount', 'number'),
f('slot', '槽位', 'Slot', 'select', { options: ['mainhand', 'offhand', 'feet', 'legs', 'chest', 'head'] }),
] },
cycle_block_property: { label: l('循环方块属性', 'Cycle Block Property'), fields: [
f('property', '属性', 'Property', 'text', { hint: l('如 axis / facing', 'e.g. axis / facing') }),
f('inverse', '反向', 'Inverse', 'text', { hint: l('默认 <arg:player.is_sneaking>', 'Default <arg:player.is_sneaking>') }),
f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'), f('z', 'Z', 'Z', 'text'),
f('rules', '自定义顺序', 'Rules', 'mapOf', { valueType: { type: 'text' }, label: l('自定义顺序', 'Rules'), hint: l('值 → 下一个值', 'value → next value') }),
] },
set_exp: { label: l('设置经验值', 'Set Exp'), fields: [
f('count', '经验', 'Exp', 'number'), f('add', '追加', 'Add', 'bool'), f('target', '目标', 'Target', 'text'),
] },
set_level: { label: l('设置等级', 'Set Level'), fields: [
f('count', '等级', 'Level', 'number'), f('add', '追加', 'Add', 'bool'), f('target', '目标', 'Target', 'text'),
] },
play_totem_animation: { label: l('图腾动画', 'Play Totem Animation'), fields: [
f('item', '物品', 'Item', 'text', { datalist: 'items' }), f('sound', '音效', 'Sound', 'text'),
f('pitch', '音调', 'Pitch', 'number'), f('volume', '音量', 'Volume', 'number'),
f('silent', '静默', 'Silent', 'bool'), f('target', '目标', 'Target', 'text'),
] },
close_inventory: { label: l('关闭背包', 'Close Inventory'), fields: [
f('target', '目标', 'Target', 'text'),
] },
clear_item: { label: l('清除物品', 'Clear Item'), fields: [
f('id', '物品 ID', 'Item ID', 'text', { datalist: 'items' }), f('count', '数量', 'Count', 'number'),
] },
heal: { label: l('治疗', 'Heal'), fields: [
f('amount', '生命值', 'Amount', 'number'), f('target', '目标', 'Target', 'text'),
] },
spawn_mythic_mob: { label: l('生成 MythicMobs 生物', 'Spawn Mythic Mob'), fields: [
f('mob', '生物 ID', 'Mob ID', 'text'), f('level', '等级', 'Level', 'number'),
f('world', '世界', 'World', 'text'), f('x', 'X', 'X', 'text'), f('y', 'Y', 'Y', 'text'),
f('z', 'Z', 'Z', 'text'), f('pitch', 'Pitch', 'Pitch', 'text'), f('yaw', 'Yaw', 'Yaw', 'text'),
] },
set_furniture_variant: { label: l('切换家具变体', 'Set Furniture Variant'), fields: [
f('variant', '变体', 'Variant', 'text'),
] },
set_item_cooldown: { label: l('物品冷却 (1.21.2+)', 'Set Item Cooldown'), fields: [
f('id', '物品 ID', 'Item ID', 'text', { hint: l('冷却组, 如 minecraft:ender_pearl', 'Cooldown group, e.g. minecraft:ender_pearl') }),
f('time', '时长', 'Time', 'text', { hint: l('如 5s (t/s/m/h/d/w)', 'e.g. 5s (t/s/m/h/d/w)') }),
f('add', '追加', 'Add', 'bool'),
] },
js: { label: l('JavaScript', 'JS'), fields: [
f('script', '脚本 ID', 'Script ID', 'text', { hint: l('namespace:path', 'namespace:path') }),
f('function', '函数', 'Function', 'text'),
f('args', '参数', 'Args', 'union', { noTypeKey: true, label: l('参数', 'Args'), types: {
list: { label: l('列表', 'List'), widget: { type: 'listOf', label: l('参数', 'Args'), itemType: { type: 'text' } } },
map: { label: l('映射', 'Map'), widget: { type: 'mapOf', label: l('参数', 'Args'), valueType: { type: 'scalar' } } },
} }),
] },
};
function FN_TYPES_REF() { return FN_TYPES; }
// ============ 战利品表 (wiki reference/loot_table.mdx) ============
var LOOT_FN_TYPES = {
apply_bonus: { label: l('附魔加成', 'Apply Bonus'), fields: [
f('enchantment', '附魔', 'Enchantment', 'text'),
f('formula', '公式', 'Formula', 'union', { noTypeKey: true, label: l('公式', 'Formula'), types: {
ore_drops: { label: l('矿石掉落 (ore_drops)', 'Ore Drops') },
binomial_with_bonus_count: { label: l('二项分布 (binomial)', 'Binomial With Bonus Count'), widget: { type: 'object', fields: [
f('extra', '额外', 'Extra', 'number'), f('probability', '概率', 'Probability', 'number'),
] } },
} }),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
apply_data: { label: l('应用数据', 'Apply Data'), fields: [
f('data', '数据', 'Data', 'kv'),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
set_count: { label: l('设置数量', 'Set Count'), fields: [
f('count', '数量', 'Count', 'text'), f('add', '追加', 'Add', 'bool'),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
explosion_decay: { label: l('爆炸衰减', 'Explosion Decay'), fields: [
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
drop_exp: { label: l('掉落经验', 'Drop Exp'), fields: [
f('count', '经验', 'Count', 'text'),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
limit_count: { label: l('限制数量', 'Limit Count'), fields: [
f('min', '最小', 'Min', 'number'), f('max', '最大', 'Max', 'number'),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
};
var LOOT_ENTRY_TYPES = {
item: { label: l('物品', 'Item'), fields: [
f('item', '物品 ID', 'Item ID', 'text', { datalist: 'items' }),
f('weight', '权重', 'Weight', 'number'),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: LOOT_FN_TYPES_REF }, label: l('函数', 'Functions') }),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
furniture_item: { label: l('家具物品', 'Furniture Item'), fields: [
f('item', '物品 ID', 'Item ID', 'text', { hint: l('掉落放置时使用的物品', 'Drops the item used to place'), datalist: 'items' }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: LOOT_FN_TYPES_REF }, label: l('函数', 'Functions') }),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
exp: { label: l('经验', 'Exp'), fields: [
f('count', '经验', 'Count', 'text'),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: LOOT_FN_TYPES_REF }, label: l('函数', 'Functions') }),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
alternatives: { label: l('备选 (alternatives)', 'Alternatives'), fields: [
f('children', '子条目', 'Children', 'listOf', { itemType: { type: 'union', types: LOOT_ENTRY_TYPES_REF }, label: l('子条目', 'Children') }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: LOOT_FN_TYPES_REF }, label: l('函数', 'Functions') }),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
loot_table: { label: l('引用战利品表', 'Loot Table'), fields: [
f('id', 'ID', 'ID', 'text', { hint: l('如 minecraft:chests/simple_dungeon', 'e.g. minecraft:chests/simple_dungeon') }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: LOOT_FN_TYPES_REF }, label: l('函数', 'Functions') }),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
};
function LOOT_FN_TYPES_REF() { return LOOT_FN_TYPES; }
function LOOT_ENTRY_TYPES_REF() { return LOOT_ENTRY_TYPES; }
var LOOT_POOL = {
type: 'object',
fields: [
f('rolls', '抽取次数', 'Rolls', 'text', { hint: l('数字或表达式, 如 1~3', 'Number or expression, e.g. 1~3') }),
f('bonus_rolls', '额外次数', 'Bonus Rolls', 'text'),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
f('entries', '条目', 'Entries', 'listOf', { itemType: { type: 'union', types: LOOT_ENTRY_TYPES }, label: l('条目', 'Entries') }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: LOOT_FN_TYPES }, label: l('函数', 'Functions') }),
],
};
var LOOT_TYPES = {
template: { label: l('模板', 'Template'), fields: [
f('template', '模板 ID', 'Template ID', 'text', { hint: l('如 default:loot_table/furniture', 'e.g. default:loot_table/furniture') }),
f('arguments', '参数', 'Arguments', 'mapOf', { valueType: { type: 'scalar' }, label: l('参数', 'Arguments') }),
] },
pools: { label: l('内联战利品', 'Inline Loot'), fields: [
f('pools', '战利品池', 'Pools', 'listOf', { itemType: LOOT_POOL, label: l('战利品池', 'Pools') }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: LOOT_FN_TYPES }, label: l('函数', 'Functions') }),
] },
};
function LOOT_TYPES_REF() { return LOOT_TYPES; }
// loot 对象形式: template+arguments 或 pools+functions 共存于同一对象
// (loot 数据无 type 键, 不用 union 避免形状误判丢数据)
var LOOT_OBJECT_FIELDS = [
f('template', '模板', 'Template', 'text', { hint: l('如 default:loot_table/furniture', 'e.g. default:loot_table/furniture') }),
f('arguments', '参数', 'Arguments', 'mapOf', { valueType: { type: 'scalar' }, label: l('参数', 'Arguments') }),
f('pools', '战利品池', 'Pools', 'listOf', { itemType: LOOT_POOL, label: l('战利品池', 'Pools') }),
f('functions', '函数', 'Functions', 'listOf', { itemType: { type: 'union', types: LOOT_FN_TYPES }, label: l('函数', 'Functions') }),
];
S.loot = { types: LOOT_TYPES, pool: LOOT_POOL, entries: LOOT_ENTRY_TYPES, functions: LOOT_FN_TYPES, objectFields: LOOT_OBJECT_FIELDS };
// ============ 共享字段构建 ============
function conditionsList() {
return { type: 'listOf', label: l('条件', 'Conditions'), itemType: { type: 'union', negatable: true, types: COND_TYPES }, hint: l('全部满足才生效 (可加 ! 取反)', 'All must pass (! prefix inverts)') };
}
function functionsList(labelZh) {
return { type: 'listOf', label: l(labelZh || '函数', 'Functions'), itemType: { type: 'union', types: FN_TYPES } };
}
S.conditions = COND_TYPES;
S.functions = FN_TYPES;
S.conditionsList = conditionsList;
S.functionsList = functionsList;
// ============ Section 表单 (简单类型) ============
// 复杂类型 (item/block/furniture/recipe) 在后续模块补充
var SECTIONS = {};
SECTIONS.equipment = {
fields: [
f('type', '类型', 'Type', 'select', { options: S.constants.equipmentTypes, hint: l('装备类型: component / trim', 'Equipment type: component / trim') }),
f('__root__', '层', 'Layers', 'mapOf', {
custom: 'root-map',
label: l('层', 'Layers'),
hint: l('键为层类型 (直接写在条目下): ' + S.constants.equipmentLayers.join(' / '), 'Key is layer type (written directly under the entry): ' + S.constants.equipmentLayers.join(' / ')),
valueType: { type: 'union', noTypeKey: true, label: l('层', 'Layer'), types: {
string: { label: l('纹理路径', 'Texture Path'), widget: { type: 'text' } },
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('texture', '纹理', 'Texture', 'text', { hint: l('如 minecraft:leather', 'e.g. minecraft:leather') }),
f('dyeable', '可染色', 'Dyeable', 'union', { noTypeKey: true, label: l('可染色', 'Dyeable'), types: {
bool: { label: l('布尔', 'Boolean'), widget: { type: 'bool' } },
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('color_when_undyed', '未染色颜色', 'Color When Undyed', 'number', { hint: l('十进制颜色值, 如 -6265536', 'Decimal color, e.g. -6265536') }),
] } },
} }),
f('use_player_texture', '玩家纹理 (鞘翅)', 'Use Player Texture', 'bool'),
] } },
list: { label: l('多纹理组合', 'Texture List'), widget: { type: 'listOf', label: l('层', 'Layers'), itemType: { type: 'union', noTypeKey: true, types: {
string: { label: l('纹理路径', 'Texture Path'), widget: { type: 'text' } },
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('texture', '纹理', 'Texture', 'text'),
f('dyeable', '可染色', 'Dyeable', 'union', { noTypeKey: true, label: l('可染色', 'Dyeable'), types: {
bool: { label: l('布尔', 'Boolean'), widget: { type: 'bool' } },
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('color_when_undyed', '未染色颜色', 'Color When Undyed', 'number'),
] } },
} }),
] } },
} } },
} } },
}),
],
};
SECTIONS.image = {
fields: [
f('file', '文件', 'File', 'text', { hint: l('如 assets/images/xxx.png', 'e.g. assets/images/xxx.png') }),
f('height', '高度', 'Height', 'number'),
f('ascent', '基线偏移', 'Ascent', 'number'),
f('font', '字体', 'Font', 'text', { hint: l('默认 namespace:default', 'Default: namespace:default') }),
f('char', '字符', 'Char', 'text'),
f('chars', '字符集', 'Chars', 'lines', { hint: l('每行一个字符', 'One char per line') }),
f('grid_size', '网格大小', 'Grid Size', 'text', { hint: l('如 2,3 = 2 行 × 3 列', 'e.g. 2,3 = 2 rows × 3 columns') }),
f('ref', '引用', 'Ref', 'text'),
f('row', '行', 'Row', 'number'),
f('column', '列', 'Column', 'number'),
],
};
SECTIONS.category = {
fields: [
f('name', '显示名', 'Name', 'miniText', { hint: l('支持 MiniMessage', 'Supports MiniMessage') }),
f('lore', '描述', 'Lore', 'lines', { hint: l('每行一条', 'One line each') }),
f('icon', '图标', 'Icon', 'text', { hint: l('注册的物品 ID', 'A registered item ID'), datalist: 'items' }),
f('priority', '优先级', 'Priority', 'number', { hint: l('越小越靠前', 'Lower shows first') }),
f('hidden', '隐藏', 'Hidden', 'bool', { hint: l('不出现在主菜单 (子分类)', 'Hidden from main menu (sub-category)') }),
f('conditions', '显示条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('显示条件', 'Conditions'), hint: l('满足条件才在主菜单显示此分类', 'Category shows only when these are met') }),
f('list', '成员列表', 'List', 'lines', { hint: l('物品 ID 或 #分类ID (每行一个)', 'Item IDs or #category refs (one per line)') }),
f('all_items', '包含全部物品', 'All Items', 'bool', { hint: l('自动包含所有注册的自定义物品', 'Auto-include all registered custom items') }),
],
};
SECTIONS.sound = {
fields: [
f('replace', '替换原音效', 'Replace', 'bool'),
f('subtitle', '字幕', 'Subtitle', 'text'),
f('sounds', '音效列表', 'Sounds', 'listOf', {
label: l('音效列表', 'Sounds'),
itemType: { type: 'union', noTypeKey: true, types: {
string: { label: l('路径', 'Path'), widget: { type: 'text', hint: l('如 block/custom_block_1', 'e.g. block/custom_block_1') } },
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('name', '路径', 'Path', 'text'),
f('volume', '音量', 'Volume', 'number'),
f('weight', '权重', 'Weight', 'number'),
f('stream', '流式播放', 'Stream', 'bool'),
f('attenuation_distance', '衰减距离', 'Attenuation Distance', 'number'),
f('preload', '预加载', 'Preload', 'bool'),
f('type', '类型', 'Type', 'select', { options: ['file', 'event'], hint: l('file: 独立音效文件; event: 原版音效事件', 'file: standalone sound file; event: vanilla sound event') }),
] } },
} },
}),
],
};
SECTIONS.emoji = {
fields: [
f('keywords', '关键词', 'Keywords', 'lines', { hint: l('每行一个', 'One per line') }),
f('content', '内容', 'Content', 'textarea'),
f('image', '图片', 'Image', 'text', { hint: l('图片单元引用: namespace:id:row:column (单格图片可省略 :row:column), 如 default:emojis:0:0', 'Image cell reference: namespace:id:row:column (single-cell may omit :row:column), e.g. default:emojis:0:0') }),
f('permission', '权限', 'Permission', 'text'),
f('chat_completion', '聊天补全', 'Chat Completion', 'bool'),
f('template', '模板', 'Template', 'text'),
f('overrides', '覆盖', 'Overrides', 'mapOf', { valueType: { type: 'scalar' }, label: l('覆盖', 'Overrides') }),
f('content_overrides', '按场景切换内容', 'Content Overrides', 'mapOf', { valueType: { type: 'scalar' }, label: l('按场景切换内容', 'Content Overrides'), hint: l('不同场景 (聊天/书本/铁砧/告示牌/指令) 使用不同格式, 键 = chat/book/anvil/sign/command', 'Different chat contexts (chat, book, anvil, sign, command) may need different formatting; key = chat/book/anvil/sign/command') }),
],
};
SECTIONS.jukeboxSong = {
fields: [
f('sound', '音效', 'Sound', 'text', { hint: l('如 minecraft:music_disc.pigstep', 'e.g. minecraft:music_disc.pigstep') }),
f('length', '时长 (秒)', 'Length (seconds)', 'number'),
f('description', '描述', 'Description', 'text'),
f('comparator_output', '红石输出', 'Comparator Output', 'number'),
f('range', '范围', 'Range', 'number'),
],
};
SECTIONS.painting = {
fields: [
f('width', '宽 (1~16)', 'Width', 'number'),
f('height', '高 (1~16)', 'Height', 'number', { hint: l('画的高度, 1~16 方块', 'Painting height in blocks, 1~16') }),
f('asset_id', '纹理', 'Asset ID', 'text', { hint: l('默认等于条目 ID', 'Defaults to the entry id') }),
f('title', '标题', 'Title', 'miniText', { hint: l('支持 <lang:...>', 'Supports <lang:...>') }),
f('author', '作者', 'Author', 'miniText'),
f('show_in_op_tab', 'OP 工具选项卡显示', 'Show in OP Tab', 'bool'),
],
};
// 全局变量/翻译: 值可能为字符串或对象, 由表单引擎按值形态处理
SECTIONS.globalVariable = { wholeValue: true };
SECTIONS.translation = { wholeValue: true };
SECTIONS.lang = { wholeValue: true };
SECTIONS.lootSource = {
fields: [
f('type', '类型', 'Type', 'select', { options: S.constants.lootSourceTypes }),
f('target', '目标', 'Target', 'text', { hint: l('按类型可为方块/实体/战利品表/进度 ID; fishing 与 piglin_barter 无目标', 'Block/entity/loot-table/advancement id; fishing & piglin_barter take none') }),
f('targets', '多个目标', 'Targets', 'lines', { hint: l('每行一个', 'One per line') }),
f('overwrite', '覆盖', 'Overwrite', 'select', { options: S.constants.lootOverwrites, hint: l('从原版掉落中移除的内容', 'What to remove from the vanilla result') }),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
f('loot', '战利品', 'Loot', 'union', { noTypeKey: true, allowScalar: { type: 'text', placeholder: 'minecraft:chests/simple_dungeon' }, label: l('战利品', 'Loot'), types: LOOT_TYPES }),
],
};
// 放置修饰器 (wiki 无结构文档, 按原版 placemod 建模; 未知类型 kv 兜底)
var PLACEMENT_MODIFIER_TYPES = {
'minecraft:rarity_filter': { label: l('稀有度过滤 (rarity_filter)', 'Rarity Filter'), fields: [f('chance', '概率', 'Chance', 'number')] },
'minecraft:in_square': { label: l('方形内 (in_square)', 'In Square') },
'minecraft:heightmap': { label: l('高度图 (heightmap)', 'Heightmap'), fields: [f('heightmap', '高度图', 'Heightmap', 'text')] },
'minecraft:biome': { label: l('群系过滤 (biome)', 'Biome') },
'minecraft:random_offset': { label: l('随机偏移 (random_offset)', 'Random Offset'), fields: [
f('xz_spread', 'XZ 偏移', 'XZ Spread', 'number'),
f('y_spread', 'Y 偏移', 'Y Spread', 'number'),
] },
'minecraft:block_predicate_filter': { label: l('方块谓词过滤 (block_predicate_filter)', 'Block Predicate Filter'), fields: [f('predicate', '谓词', 'Predicate', 'kv')] },
'minecraft:count': { label: l('数量 (count)', 'Count'), fields: [f('count', '数量', 'Count', 'text')] },
'minecraft:noise_threshold_count': { label: l('噪声阈值数量 (noise_threshold_count)', 'Noise Threshold Count'), fields: [
f('noise_level', '噪声级别', 'Noise Level', 'number'),
f('below_noise', '低于噪声', 'Below Noise', 'number'),
f('above_noise', '高于噪声', 'Above Noise', 'number'),
] },
'minecraft:count_on_every_layer': { label: l('每层数量 (count_on_every_layer)', 'Count On Every Layer'), fields: [f('count', '数量', 'Count', 'text')] },
'minecraft:environment_scan': { label: l('环境扫描 (environment_scan)', 'Environment Scan'), fields: [
f('direction_of_search', '搜索方向', 'Direction', 'text'),
f('max_steps', '最大步数', 'Max Steps', 'number'),
f('target_condition', '目标条件', 'Target Condition', 'kv'),
f('allowed_condition', '允许条件', 'Allowed Condition', 'kv'),
] },
'minecraft:spread_32_above_top': { label: l('顶部上 32 格散布 (spread_32_above_top)', 'Spread 32 Above Top') },
'minecraft:top_slice_height': { label: l('顶部切片高度 (top_slice_height)', 'Top Slice Height'), fields: [f('height', '高度', 'Height', 'text', { hint: l('上方截取的方块数', 'Blocks cut from the top') })] },
'minecraft:carving_mask': { label: l('洞穴雕刻掩码 (carving_mask)', 'Carving Mask'), fields: [f('step', '步骤', 'Step', 'text')] },
'minecraft:random_spread': { label: l('随机散布 (random_spread)', 'Random Spread'), fields: [
f('spread_type', '散布类型', 'Spread Type', 'text'),
f('spread', '散布', 'Spread', 'number'),
f('horizontal_spread', '水平散布', 'Horizontal Spread', 'number'),
f('vertical_spread', '垂直散布', 'Vertical Spread', 'number'),
] },
'minecraft:block_predictions': { label: l('方块预测 (block_predictions)', 'Block Predictions'), fields: [f('predicate', '谓词', 'Predicate', 'kv')] },
'minecraft:height_range': { label: l('高度范围 (height_range)', 'Height Range'), fields: [
f('height', '高度', 'Height', 'object', { hint: l('生成高度范围', 'Spawn height range'), fields: [
f('type', '类型', 'Type', 'text', { hint: l('如 minecraft:uniform', 'e.g. minecraft:uniform') }),
f('min_inclusive', '最小高度', 'Min Inclusive', 'number'),
f('max_inclusive', '最大高度', 'Max Inclusive', 'number'),
] }),
] },
};
var PLACED_FEATURE_UNION = {
type: 'union', noTypeKey: true, allowScalar: { type: 'text', placeholder: l('minecraft:patch', 'minecraft:patch') },
label: l('地物', 'Feature'),
types: {
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('type', '类型', 'Type', 'text', { hint: l('已配置地物类型, 如 minecraft:tree', 'Configured feature type, e.g. minecraft:tree') }),
f('config', '配置', 'Config', 'kv'),
], label: l('地物', 'Feature') } },
},
};
var PLACED_PLACEMENT_UNION = {
type: 'union', noTypeKey: true, label: l('放置规则', 'Placement'),
types: {
single: { label: l('单个修饰器', 'Single Modifier'), widget: { type: 'union', types: PLACEMENT_MODIFIER_TYPES, label: l('修饰器', 'Modifier') } },
list: { label: l('修饰器列表', 'Modifier List'), widget: { type: 'listOf', label: l('放置修饰器', 'Placement Modifiers'), itemType: { type: 'union', types: PLACEMENT_MODIFIER_TYPES, label: l('修饰器', 'Modifier') } } },
},
};
SECTIONS.placedFeature = {
fields: [
f('feature', '地物', 'Feature', 'popup', { content: PLACED_FEATURE_UNION, label: l('地物', 'Feature'), hint: l('生成结构定义', 'Structure definition') }),
f('placement', '放置规则', 'Placement', 'popup', { content: PLACED_PLACEMENT_UNION, label: l('放置规则', 'Placement'), hint: l('放置修饰器', 'Placement modifiers') }),
f('world', '世界', 'World', 'lines'),
f('dimension', '维度', 'Dimension', 'lines'),
f('dimension_type', '维度类型', 'Dimension Type', 'lines'),
f('biome', '生物群系', 'Biome', 'lines'),
],
};
// ============ Item 可视化编辑 ============
// 数据源: wiki item/data.mdx, item/models.mdx + models/ 子文档, item/settings.mdx,
// item/behaviors.mdx + behaviors/ 子文档, item/updater.mdx
// ---- 常量补充 (datalist) ----
S.constants.glowColors = ['#000000', '#FF0000', '#FF8000', '#FFFF00', '#80FF00', '#00FF00', '#00FF80',
'#00FFFF', '#0080FF', '#0000FF', '#8000FF', '#FF00FF', '#FF0080', '#FFFFFF'];
S.constants.equipmentSlots = ['main_hand', 'off_hand', 'head', 'chest', 'legs', 'feet', 'body', 'saddle', 'any'];
S.constants.enchantOperations = ['ADD', 'MULTIPLY_BASE', 'MULTIPLY_TOTAL'];
S.constants.bannerColors = ['white', 'orange', 'magenta', 'light_blue', 'yellow', 'lime', 'pink', 'gray',
'light_gray', 'cyan', 'purple', 'blue', 'brown', 'green', 'red', 'black'];
S.constants.headKinds = ['SKULL', 'PLAYER', 'BLOCK', 'CREEPER', 'DRAGON', 'PIGLIN', 'SKELETON', 'WITHER_SKELETON', 'ZOMBIE'];
S.constants.rotations = ['NONE', 'CLOCKWISE_45', 'CLOCKWISE_90', 'CLOCKWISE_135', 'FLIPPED',
'COUNTERCLOCKWISE_45', 'COUNTERCLOCKWISE_90', 'COUNTERCLOCKWISE_135'];
S.constants.alignments = ['none', 'center', 'bottom'];
S.constants.modelCondProps = ['component', 'custom_model_data', 'item_model'];
S.constants.modelSelProps = ['component', 'custom_model_data', 'item_model'];
S.constants.modelRangeProps = ['component', 'custom_model_data', 'item_model'];
S.constants.bookGenerations = ['ORIGINAL', 'COPY_OF_ORIGINAL', 'COPY_OF_COPY', 'TATTERED'];
// 音效值: 字符串 或 详细 {id, pitch, volume}
var SOUND_REF_TYPES = {
map: { label: l('详细', 'Detailed'), widget: { type: 'object', fields: [
f('id', '音效 ID', 'Sound ID', 'text'),
f('pitch', '音调', 'Pitch', 'number'),
f('volume', '音量', 'Volume', 'text', { hint: l('支持 0.25~0.3 区间', 'Ranged values supported, e.g. 0.25~0.3') }),
], label: l('音效', 'Sound') } },
};
function soundRefField(key, zh, en) {
return f(key, zh, en, 'union', { noTypeKey: true, allowScalar: { type: 'text', placeholder: l('minecraft:block.deepslate.break', 'minecraft:block.deepslate.break') }, label: l('音效', 'Sound'), types: SOUND_REF_TYPES });
}
// 音效对象 (弹窗 content): 方块五键 / 家具三键 / 其他键位 (须在 _bh 之前, 行为字段会引用)
function soundObject(keys) {
return {
type: 'object',
fields: keys.map(function (k) {
var zh = { break: '破坏', step: '踩踏', place: '放置', hit: '挖掘', fall: '坠落', open: '打开', close: '关闭', put: '放入', take: '取出', on: '按下', off: '松开', chime: '风铃', land: '落地', destroy: '破坏', rotate: '旋转' }[k] || k;
var en = k.charAt(0).toUpperCase() + k.slice(1);
return soundRefField(k, zh, en);
}),
label: l('音效', 'Sounds'),
};
}
var BLOCK_SOUND_OBJECT = soundObject(['break', 'step', 'place', 'hit', 'fall']);
var FURNITURE_SOUND_OBJECT = soundObject(['break', 'place', 'hit']);
// legacy 行为字段 → 新 schema 字段 (数据源: 旧版 interpreter BEHAVIOR_FIELDS, 与 wiki behaviors 文档一致)
// spec: [path, 'text'|'number'|'bool'|'lines'|'select'|'json']
function _bh(list) {
return (list || []).map(function (spec) {
var p = spec[0], t = spec[1];
if (p === 'conditions') return f(p, p, p, 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') });
if (p === 'sounds' && t === 'json') {
var skeys = spec[2] ? String(spec[2]).split(',') : null;
return f(p, p, p, 'popup', { content: skeys ? soundObject(skeys) : BLOCK_SOUND_OBJECT, label: l('音效', 'Sounds') });
}
if (t === 'number') return f(p, p, p, 'number');
if (t === 'bool') return f(p, p, p, 'bool');
if (t === 'lines') return f(p, p, p, 'lines');
if (t === 'select') return f(p, p, p, 'select', { options: spec[2] || [] });
if (t === 'json') return f(p, p, p, 'kv');
return f(p, p, p, 'text');
});
}
// ---- 通用小块 ----
var CRAFT_REMAINDER_TYPES = {
fixed: { label: l('固定物品 (fixed)', 'Fixed Item'), fields: [f('item', '物品', 'Item', 'text', { datalist: 'items' }), f('count', '数量', 'Count', 'number')] },
hurt_and_break: { label: l('损坏并破碎 (hurt_and_break)', 'Hurt And Break'), fields: [f('damage', '耐久消耗', 'Damage', 'number', { hint: l('消耗的耐久度', 'Durability consumed') })] },
recipe_based: { label: l('基于配方 (recipe_based)', 'Recipe Based'), fields: [f('terms', '条款', 'Terms', 'listOf', { itemType: { type: 'object', fields: [
f('recipes', '配方', 'Recipes', 'lines', { hint: l('每行一个配方 ID', 'One recipe ID per line') }),
f('craft_remainder', '合成残留', 'Craft Remainder', 'union', { allowScalar: { type: 'text', datalist: 'items' }, types: CRAFT_REMAINDER_TYPES_REF, label: l('合成残留', 'Craft Remainder') }),
], label: l('条款', 'Term') }, label: l('条款', 'Terms') })] },
same: { label: l('相同物品 (same)', 'Same Item') },
};
function CRAFT_REMAINDER_TYPES_REF() { return CRAFT_REMAINDER_TYPES; }
var ROTATION_TYPES = {
quaternion: { label: l('四元数 (quaternion)', 'Quaternion'), fields: [f('quaternion', '四元数', 'Quaternion', 'lines', { hint: l('4 个数, 每行一个', '4 numbers, one per line') })] },
axis_angle: { label: l('轴角 (axis_angle)', 'Axis Angle'), fields: [f('axis', '轴', 'Axis', 'text'), f('angle', '角度', 'Angle', 'number')] },
};
var TRANSFORM_TYPES = {
decomposed: { label: l('分解 (decomposed)', 'Decomposed'), fields: [
f('rotation', '旋转', 'Rotation', 'lines', { hint: l('3 个数, 每行一个', '3 numbers, one per line') }),
f('translation', '平移', 'Translation', 'lines', { hint: l('3 个数, 每行一个', '3 numbers, one per line') }),
f('scale', '缩放', 'Scale', 'lines', { hint: l('3 个数, 每行一个', '3 numbers, one per line') }),
f('left_rotation', '左旋转', 'Left Rotation', 'union', { types: ROTATION_TYPES, label: l('左旋转', 'Left Rotation') }),
f('right_rotation', '右旋转', 'Right Rotation', 'union', { types: ROTATION_TYPES, label: l('右旋转', 'Right Rotation') }),
] },
matrix: { label: l('矩阵 (matrix)', 'Matrix'), widget: { type: 'lines', label: l('矩阵', 'Matrix'), hint: l('16 个数, 每行一个', '16 numbers, one per line') } },
};
// 方块状态: 字符串 或 键值映射 (item data.block_state / block 相关)
var BLOCK_STATE_WIDGET = {
type: 'union', noTypeKey: true, allowScalar: { type: 'text', placeholder: l('default:palm_sapling[stage=0]', 'default:palm_sapling[stage=0]') },
label: l('方块状态', 'Block State'),
types: {
map: { label: l('属性映射', 'Property Map'), widget: { type: 'mapOf', valueType: { type: 'string-scalar' }, label: l('属性映射', 'Property Map') } },
},
};
// ---- data 组件 (wiki item/data.mdx) ----
var LORE_LINE_TYPES = {
advanced: { label: l('高级 (advanced)', 'Advanced'), fields: [
f('content', '内容', 'Content', 'text', { mini: true }),
f('priority', '优先级', 'Priority', 'number'),
f('operation', '操作', 'Operation', 'select', { options: ['APPEND', 'PREPEND'] }),
f('split_lines', '按行拆分', 'Split Lines', 'bool'),
f('conditions', '条件', 'Conditions', 'listOf', { itemType: { type: 'union', negatable: true, types: COND_TYPES }, label: l('条件', 'Conditions') }),
] },
simple: { label: l('简单文本', 'Simple Text'), widget: { type: 'text', mini: true } },
};
var LORE_LINE_UNION = { type: 'union', noTypeKey: true, allowScalar: { type: 'text', mini: true }, label: l('Lore 行', 'Lore Line'), types: LORE_LINE_TYPES };
// insert_lore (wiki): {position, pattern, lore, fallback{position, lore}}
var INSERT_LORE_FIELDS = [
f('position', '位置', 'Position', 'select', { options: ['HEAD', 'TAIL', 'BEFORE', 'AFTER'] }),
f('pattern', '匹配行', 'Pattern', 'text', { hint: l('BEFORE/AFTER 时匹配的行 (正则)', 'Line matched for BEFORE/AFTER (regex)') }),
f('lore', '插入内容', 'Insert', 'listOf', { itemType: LORE_LINE_UNION, label: l('插入内容', 'Insert') }),
f('fallback', '未匹配回退', 'Fallback', 'object', { fields: [
f('position', '位置', 'Position', 'select', { options: ['HEAD', 'TAIL', 'BEFORE', 'AFTER'] }),
f('lore', '插入内容', 'Insert', 'listOf', { itemType: LORE_LINE_UNION, label: l('插入内容', 'Insert') }),
], label: l('未匹配回退', 'Fallback') }),
];
var CUSTOM_MODEL_DATA_TYPES = {
map: { label: l('详细 (floats/flags/strings)', 'Detailed'), widget: { type: 'object', fields: [
f('floats', '浮点数', 'Floats', 'lines'),
f('flags', '旗标', 'Flags', 'lines'),
f('strings', '字符串', 'Strings', 'lines'),
] } },
};
var CUSTOM_MODEL_DATA_UNION = { type: 'union', noTypeKey: true, allowScalar: { type: 'scalar' }, label: l('Custom Model Data', 'Custom Model Data'), types: CUSTOM_MODEL_DATA_TYPES };
var PROFILE_TYPES = {
map: { label: l('字段', 'Fields'), widget: { type: 'object', fields: [
f('name', '玩家名', 'Player Name', 'text'),
f('texture', '纹理 URL', 'Texture URL', 'text'),
f('url', '皮肤 URL', 'Skin URL', 'text'),
f('base64', 'Base64', 'Base64', 'text'),
] } },
};
var PROFILE_UNION = { type: 'union', noTypeKey: true, allowScalar: { type: 'text' }, label: l('皮肤', 'Profile'), types: PROFILE_TYPES };
var WRITTEN_PAGE_TYPES = {
lines: { label: l('多行文本', 'Lines'), widget: { type: 'lines', label: l('文本', 'Text') } },
raw_filtered: { label: l('原始过滤 (raw_filtered)', 'Raw Filtered'), widget: { type: 'object', fields: [
f('raw', '原始文本', 'Raw', 'text'),
f('filtered', '过滤后文本', 'Filtered', 'text'),
], label: l('原始过滤', 'Raw Filtered') } },
};
var WRITTEN_PAGE_UNION = { type: 'union', noTypeKey: true, allowScalar: { type: 'text' }, label: l('页', 'Page'), types: WRITTEN_PAGE_TYPES };
var ATTR_MOD_FIELDS = [
f('type', '属性', 'Attribute', 'text', { hint: l('如 minecraft:max_health', 'e.g. minecraft:max_health') }),
f('amount', '数值', 'Amount', 'number'),
f('operation', '操作', 'Operation', 'select', { options: S.constants.enchantOperations }),
f('id', 'ID', 'ID', 'text'),
f('slot', '槽位', 'Slot', 'select', { options: S.constants.equipmentSlots }),
];
var FOOD_EFFECT_FIELDS = [
f('effect', '效果', 'Effect', 'text', { hint: l('如 minecraft:speed', 'e.g. minecraft:speed') }),
f('probability', '概率', 'Probability', 'number'),
f('duration', '时长 (tick)', 'Duration', 'number'),
f('amplifier', '等级', 'Amplifier', 'number'),
f('ambient', '环境', 'Ambient', 'bool'),
f('show_particles', '显示粒子', 'Show Particles', 'bool'),
f('show_icon', '显示图标', 'Show Icon', 'bool'),
];
var FOOD_FIELDS = [
f('nutrition', '营养', 'Nutrition', 'number'),
f('saturation', '饱和度', 'Saturation', 'number'),
f('can_always_eat', '随时可吃', 'Can Always Eat', 'bool'),
f('eat_seconds', '进食时间 (秒)', 'Eat Seconds', 'number'),
f('using_converts_to', '食用后得到', 'Using Converts To', 'text', { datalist: 'items' }),
f('effects', '效果', 'Effects', 'listOf', { itemType: { type: 'object', fields: FOOD_EFFECT_FIELDS, label: l('效果', 'Effect') }, label: l('效果', 'Effects') }),
];
var EQUIPPABLE_FIELDS = [
f('slot', '槽位', 'Slot', 'select', { options: S.constants.equipmentSlots }),
f('model', '模型', 'Model', 'text', { hint: l('如 minecraft:item/elytra', 'e.g. minecraft:item/elytra') }),
f('camera_overlay', '相机覆盖', 'Camera Overlay', 'text'),
f('allowed_entities', '允许实体', 'Allowed Entities', 'lines'),
f('dispensable', '可发射', 'Dispensable', 'bool'),
f('swappable', '可替换', 'Swappable', 'bool'),
f('equip_sound', '装备音效', 'Equip Sound', 'text', { hint: l('如 minecraft:item.armor.equip_elytra', 'e.g. minecraft:item.armor.equip_elytra') }),
f('asset_id', '资源 ID', 'Asset ID', 'text'),
f('damage_on_hurt', '受击损耗', 'Damage On Hurt', 'bool'),
f('equip_on_interact', '交互穿戴', 'Equip On Interact', 'bool'),
];
var WRITTEN_BOOK_FIELDS = [
f('pages', '页', 'Pages', 'listOf', { itemType: WRITTEN_PAGE_UNION, label: l('页', 'Pages') }),
f('author', '作者', 'Author', 'text'),
f('title', '标题', 'Title', 'text'),
f('resolved', '已解析', 'Resolved', 'bool'),
f('generation', '版本', 'Generation', 'select', { options: S.constants.bookGenerations }),
];
var JUKEPLAYABLE_FIELDS = [
f('song', '歌曲', 'Song', 'text', { hint: l('如 minecraft:cat', 'e.g. minecraft:cat') }),
f('show_in_tooltip', '显示在提示中', 'Show In Tooltip', 'bool'),
];
// ---- item data 六类分组 (wiki item/data.mdx): 外观/行为/存储/外部/数据组件/客户端数据 ----
var EXTERNAL_FIELDS = [
f('plugin', '插件', 'Plugin', 'text', { hint: l('数据来源插件 (或 source), 如 neigeitems', 'Source plugin (or "source"), e.g. neigeitems') }),
f('id', '物品 ID', 'Item ID', 'text'),
];
var REMOVE_LORE_TYPES = {
text: { label: l('正则', 'Regex'), widget: { type: 'text', hint: l('移除匹配的行 (正则)', 'Lines to remove (regex)') } },
object: { label: l('详细 (pattern/count/regex)', 'Detailed'), widget: { type: 'object', fields: [
f('pattern', '匹配行', 'Pattern', 'text'),
f('count', '数量', 'Count', 'number', { hint: l('移除的行数, 默认 1', 'Lines to remove, default 1') }),
f('regex', '正则匹配', 'Regex', 'bool'),
], label: l('移除 Lore', 'Remove Lore') } },
};
var REMOVE_LORE_UNION = { type: 'union', noTypeKey: true, label: l('移除 Lore', 'Remove Lore'), types: REMOVE_LORE_TYPES };
var DYED_COLOR_TYPES = {
text: { label: l('颜色 (r,g,b)', 'Color'), widget: { type: 'text', placeholder: l('255,128,64', '255,128,64') } },
object: { label: l('详细 (rgb/show_in_tooltip)', 'Detailed'), widget: { type: 'object', fields: [
f('rgb', '颜色', 'RGB', 'text', { placeholder: l('#FF0000', '#FF0000') }),
f('show_in_tooltip', '显示在提示中', 'Show In Tooltip', 'bool'),
], label: l('染色', 'Dyed Color') } },
};
var DYED_COLOR_UNION = { type: 'union', noTypeKey: true, label: l('染色', 'Dyed Color'), types: DYED_COLOR_TYPES };
var UNBREAKABLE_TYPES = {
bool: { label: l('布尔', 'Boolean'), widget: { type: 'bool' } },
object: { label: l('详细 (show_in_tooltip)', 'Detailed'), widget: { type: 'object', fields: [
f('show_in_tooltip', '显示在提示中', 'Show In Tooltip', 'bool'),
], label: l('不可破坏', 'Unbreakable') } },
};
var UNBREAKABLE_UNION = { type: 'union', noTypeKey: true, label: l('不可破坏', 'Unbreakable'), types: UNBREAKABLE_TYPES };
var USE_REMAINDER_TYPES = {
text: { label: l('物品 ID', 'Item ID'), widget: { type: 'text', datalist: 'items' } },
object: { label: l('详细 (id/count)', 'Detailed'), widget: { type: 'object', fields: [
f('id', '物品 ID', 'Item ID', 'text', { datalist: 'items' }),
f('count', '数量', 'Count', 'number', { hint: l('默认 1', 'Default 1') }),
], label: l('使用剩余', 'Use Remainder') } },
};
var USE_REMAINDER_UNION = { type: 'union', noTypeKey: true, label: l('使用剩余', 'Use Remainder'), types: USE_REMAINDER_TYPES };
var JUKEBOX_TYPES = {
text: { label: l('歌曲 ID', 'Song ID'), widget: { type: 'text', hint: l('如 default:credits_music', 'e.g. default:credits_music') } },
object: { label: l('详细 (song/show_in_tooltip)', 'Detailed'), widget: { type: 'object', fields: JUKEPLAYABLE_FIELDS, label: l('唱片', 'Jukebox Playable') } },
};
var JUKEBOX_UNION = { type: 'union', noTypeKey: true, label: l('唱片', 'Jukebox Playable'), types: JUKEBOX_TYPES };
// 外观
var ITEM_APPEARANCE_TYPES = {
item_name: { label: l('物品名 (item_name)', 'Item Name'), widget: { type: 'text', label: l('物品名', 'Item Name'), mini: true } },
custom_name: { label: l('自定义名 (custom_name)', 'Custom Name'), widget: { type: 'text', label: l('自定义名', 'Custom Name'), mini: true } },
lore: { label: l('Lore', 'Lore'), widget: { type: 'union', noTypeKey: true, defaultKey: 'simple', keepKey: true, label: l('Lore', 'Lore'), types: {
simple: { label: l('普通定义', 'Simple'), widget: { type: 'lines', label: l('Lore', 'Lore'), mini: true, hint: l('每行一条描述文本', 'One line each') } },
complex: { label: l('复杂定义', 'Complex'), widget: { type: 'listOf', itemType: LORE_LINE_UNION, label: l('Lore', 'Lore') } },
} } },
insert_lore: { label: l('插入 Lore (insert_lore)', 'Insert Lore'), widget: { type: 'object', fields: INSERT_LORE_FIELDS, label: l('插入 Lore', 'Insert Lore') } },
remove_lore: { label: l('移除 Lore (remove_lore)', 'Remove Lore'), widget: REMOVE_LORE_UNION },