33from collections import defaultdict
44from typing import TYPE_CHECKING
55
6- from beet import Context , Function , LootTable , Predicate
6+ from beet import Context , Function , LootTable , PackFile , Predicate
77
8- from bookshelf .definitions import MC_VERSIONS
98from bookshelf .models import Block , StateNode , StatePredicate , StateProperty , StateValue
109from bookshelf .services import minecraft
1110
1211if TYPE_CHECKING :
13- from collections .abc import Sequence
14-
12+ from collections .abc import Iterable , Sequence
1513
1614ATTR_TAGS = [
1715 ("has_state" , lambda b : b .group > 0 ),
5048 "sounds" ,
5149}
5250
51+ LOOT_TABLE_INCLUDE = {
52+ "type" ,
53+ "item" ,
54+ "group" ,
55+ "sounds" , # @deprecated sounds (removed in in 4.0.0)
56+ }
57+
5358
54- def beet_default (ctx : Context ) -> None :
55- """Generate files used by the bs.block module."""
56- namespace = ctx .directory .name
57- blocks = minecraft .get_blocks (ctx .cache , MC_VERSIONS [- 1 ])
59+ @minecraft .generator
60+ def beet_default (ctx : Context , version : str ) -> Iterable [tuple [str , PackFile ]]:
61+ """Generate files used by the module for a given version."""
62+ ns = ctx .directory .name
63+ blocks = minecraft .get_blocks (ctx .cache , version )
5864
59- loot_table = make_block_loot_table (blocks )
60- ctx .generate (f"{ namespace } :internal/get_type" , render = loot_table )
61- loot_table = make_block_loot_table (blocks , f"{ namespace } :internal" )
62- ctx .generate (f"{ namespace } :internal/get_block" , render = loot_table )
65+ yield f"{ ns } :internal/get_type" , make_block_loot_table (blocks )
66+ yield f"{ ns } :internal/get_block" , make_block_loot_table (blocks , f"{ ns } :internal" )
6367
6468 for state in {s .group : s for b in blocks for s in b .properties }.values ():
65- loot_table = make_block_state_loot_table ( state , f"{ namespace } :internal" )
66- ctx . generate ( f"{ namespace } :internal/group_ { state . group } " , render = loot_table )
69+ location = f"{ ns } :internal/group_ { state . group } "
70+ yield location , make_block_state_loot_table ( state , f"{ ns } :internal" )
6771
6872 for name , formatter in [
6973 ("types" , format_types_table ),
7074 ("items" , format_items_table ),
7175 ("groups" , format_groups_table ),
7276 ]:
73- ctx .generate (
74- f"{ namespace } :import/{ name } _table" ,
75- render = Function (source_path = f"{ name } _table.jinja" ),
76- data = formatter (blocks ),
77- )
77+ location = f"{ ns } :import/{ name } _table"
78+ content = ctx .template .render (f"{ name } _table.jinja" , data = formatter (blocks ))
79+ yield location , Function (content )
7880
7981 for name , predicate in ATTR_TAGS :
80- tag = ctx .data .block_tags [f"{ namespace } :{ name } " ]
81- minecraft .update_block_tag ( tag , blocks , predicate )
82+ base = ctx .data .block_tags [location := f"{ ns } :{ name } " ]
83+ yield location , minecraft .make_block_tag ( base , blocks , predicate )
8284
8385 for name , attribute in ATTR_PREDICATES :
8486 groups = defaultdict (list )
8587 for block in blocks :
8688 groups [attribute (block )].append (block )
87- merge_attr_predicate (ctx .data .predicates [f"{ namespace } :{ name } " ], groups )
89+
90+ base = ctx .data .predicates [location := f"{ ns } :{ name } " ]
91+ yield location , make_attr_predicate (base , groups )
8892
8993 for name , attribute in ATTR_LOOT_TABLES :
9094 seen = set ()
@@ -93,11 +97,11 @@ def beet_default(ctx: Context) -> None:
9397 groups [value := attribute (block )].append (block )
9498 if isinstance (value , StatePredicate ) and value not in seen :
9599 seen .add (value )
96- file = make_attr_state_loot_table ( name , value )
97- ctx . generate ( f" { namespace } :internal/ { name } _ { value . group } " , render = file )
100+ location = f" { ns } :internal/ { name } _ { value . group } "
101+ yield location , make_attr_state_loot_table ( name , value )
98102
99- file = make_attr_loot_table ( name , groups , f"{ namespace } :internal" )
100- ctx . generate ( f"{ namespace } :internal/get_ { name } " , render = file )
103+ location = f"{ ns } :internal/get_ { name } "
104+ yield location , make_attr_loot_table ( name , groups , f"{ ns } :internal" )
101105
102106
103107def format_types_table (blocks : Sequence [Block ]) -> dict :
@@ -126,11 +130,10 @@ def format_groups_table(blocks: Sequence[Block]) -> dict:
126130
127131def format_block_loot_entry (entry : dict , block : Block ) -> dict :
128132 """Attach block data to a loot entry."""
129- # @deprecated sounds (removed in in 4.0.0)
130133 return {** entry , "functions" : [{
131134 "function" : "set_custom_data" ,
132135 "tag" : minecraft .render_snbt (block .model_dump (
133- include = { "type" , "item" , "group" , "sounds" } ,
136+ include = LOOT_TABLE_INCLUDE ,
134137 )),
135138 }]}
136139
@@ -225,10 +228,10 @@ def make_attr_state_loot_table(attr: str, entry: StatePredicate) -> LootTable:
225228 })
226229
227230
228- def merge_attr_predicate (
229- predicate : Predicate ,
231+ def make_attr_predicate (
232+ base : Predicate ,
230233 groups : dict [StateValue [bool ], list [Block ]],
231- ) -> None :
234+ ) -> Predicate :
232235 """Create a predicate for a collection of blocks grouped by attribute."""
233236 def optimize_entry (entry : dict ) -> dict | None :
234237 terms = list (filter (None , entry .get ("terms" , [])))
@@ -257,8 +260,8 @@ def build_node[T: bool](node: StateNode[T] | T) -> dict | None:
257260
258261 return optimize_entry ({"condition" :"any_of" ,"terms" :terms })
259262
260- predicate . set_content ( optimize_entry ({
261- ** predicate .data ,
263+ return Predicate ({
264+ ** base .data ,
262265 "condition" : "any_of" ,
263266 "terms" : [optimize_entry ({
264267 "condition" : "all_of" , "terms" :[{
@@ -269,4 +272,4 @@ def build_node[T: bool](node: StateNode[T] | T) -> dict | None:
269272 "condition" : "location_check" ,
270273 "predicate" : {"block" : {"blocks" : [b .type [10 :] for b in blocks ]}},
271274 } for group , blocks in groups .items () if group ],
272- }))
275+ })
0 commit comments