def dimension_type(self, name_parts: ResourceIdentifier, fixed_time: int, has_skylight: bool, has_ceiling: bool, ultrawarm: bool, natural: bool, coordinate_scale: float, piglin_safe: bool, bed_works: bool, respawn_anchor_works: bool, has_raids: bool, min_y: int, height: int, logical_height: int, infiniburn: ResourceIdentifier, effects: ResourceIdentifier, ambient_light: float): res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'dimension_type', res.path), { 'fixed_time': fixed_time, 'has_skylight': has_skylight, 'has_ceiling': has_ceiling, 'ultrawarm': ultrawarm, 'natural': natural, 'coordinate_scale': coordinate_scale, 'piglin_safe': piglin_safe, 'bed_works': bed_works, 'respawn_anchor_works': respawn_anchor_works, 'has_raids': has_raids, 'min_y': min_y, 'height': height, 'logical_height': logical_height, 'infiniburn': utils.resource_location(infiniburn).join(), 'effects': utils.resource_location(effects).join(), 'ambient_light': ambient_light })
def item_model(self, name_parts: ResourceIdentifier, *textures: Union[Json, str], parent: ResourceIdentifier = 'item/generated', no_textures: bool = False) -> ItemContext: """ Creates an item model file :param name_parts: the resource location, including path elements. :param textures: the textures for the model. Defaults to 'domain:item/name/parts' :param parent: the parent model. :param no_textures: if the textures element should be ignored """ res = utils.resource_location(self.domain, name_parts) if no_textures: textures = None else: if textures is None or len(textures) == 0: textures = res.join('item/'), textures = utils.item_model_textures(textures) self.write( (*self.resource_dir, 'assets', res.domain, 'models', 'item', res.path), { 'parent': utils.resource_location(parent).join(simple=True), 'textures': textures }) return ItemContext(self, res)
def dimension(self, name_parts: ResourceIdentifier, dimension_type: ResourceIdentifier, generator: Json): res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'dimension', res.path), { 'type': utils.resource_location(dimension_type).join(), 'generator': generator })
def custom_item_model(self, name_parts: ResourceIdentifier, loader: ResourceIdentifier, data: Dict[str, Any]) -> ItemContext: res = utils.resource_location(self.domain, name_parts) self.write((*self.resource_dir, 'assets', res.domain, 'models', 'item', res.path), { 'loader': utils.resource_location(loader).join(), **data }) return ItemContext(self, res)
def placed_feature(self, name_parts: ResourceIdentifier, feature: ResourceIdentifier, *placements: TypeWithOptionalConfig): res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'worldgen', 'placed_feature', res.path), { 'feature': utils.resource_location(feature).join(), 'placement': [utils.configured_placement(p) for p in placements] })
def configured_placement(data): if utils.is_sequence(data): res, cfg = utils.unordered_pair(data, str, dict) assert 'type' not in cfg, 'Type specified twice for placement' return {'type': utils.resource_location(res).join(), **cfg} elif isinstance(data, dict): assert 'type' in data, 'Missing \'type\' in placement' return data elif isinstance(data, str): return {'type': utils.resource_location(data).join()} else: raise ValueError('Unknown object %s at configured_placement' % str(data))
def advancement(self, name_parts: ResourceIdentifier, display: Json = None, parent: str = None, criteria: Dict[str, Dict[str, Json]] = None, requirements: Sequence[Sequence[str]] = None, rewards: Dict[str, Json] = None): """ Creates a generic advancement. Performs basic filling in of data types :param name_parts: The resource location, including path elements. :param display: The display data. Inserted as is. :param parent: The parent advancement registry name :param criteria: The criteria for an advancement. Inserted as is. :param requirements: The requirements. If None, will default to a list of all the requirements (OR'd together). :param rewards: The rewards. Inserted as is. """ res = utils.resource_location(self.domain, name_parts) if requirements is None: requirements = [[k for k in criteria.keys()]] self.write( (*self.resource_dir, 'data', res.domain, 'advancements', res.path), { 'parent': parent, 'criteria': criteria, 'display': display, 'requirements': requirements, 'rewards': rewards })
def crafting_shaped(self, name_parts: ResourceIdentifier, pattern: Sequence[str], ingredients: Json, result: Json, group: str = None, conditions: Optional[Json] = None) -> RecipeContext: """ Creates a shaped crafting recipe. :param name_parts: The resource location, including path elements. :param pattern: The pattern for the recipe. :param ingredients: The ingredients, indexed by key in pattern. :param result: The result of crafting the recipe. :param group: The group. :param conditions: Any conditions for the recipe to be enabled. """ res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'recipes', res.path), { 'type': 'minecraft:crafting_shaped', 'group': group, 'pattern': pattern, 'key': utils.item_stack_dict(ingredients, ''.join(pattern)[0]), 'result': utils.item_stack(result), 'conditions': utils.recipe_condition(conditions) }) return RecipeContext(self, res)
def block_model(self, name_parts: ResourceIdentifier, textures: Union[Dict[str, str], Sequence[str]] = None, parent: Union[str, None] = 'block/cube_all', elements: Json = None, no_textures: bool = False) -> BlockContext: """ Creates a block model file :param name_parts: the resource location, including path elements. :param textures: the textures for the model. Defaults to 'domain:block/name/parts' :param parent: the parent model. If none, it is omitted :param elements: elements of the model. Can be a single element, which will get expanded to a list of one element :param no_textures: If true, textures will be ignored. """ res = utils.resource_location(self.domain, name_parts) if textures is None: if not no_textures: textures = {'all': res.join('block/')} elif isinstance(textures, str): textures = {'all': textures} elif isinstance(textures, Sequence): textures = dict((k, res.join('block')) for k in textures) if isinstance(elements, Dict): elements = [elements] self.write((*self.resource_dir, 'assets', res.domain, 'models', 'block', res.path), { 'parent': parent, 'textures': textures, 'elements': elements }) return BlockContext(self, res)
def advancement(self, name: str, icon: Json, title: str, description: str, parent: Optional[str], criteria: Json, requirements: Json = None, frame: str = 'task', toast: bool = True, chat: bool = True, hidden: bool = False): key = '%s.advancements.%s.%s' % (self.rm.domain, self.category, name) if parent is not None: parent = utils.resource_location(self.rm.domain, self.category + '/' + parent).join() self.rm.advancement( (self.category, name), { 'icon': utils.item_stack(icon), 'title': { 'translate': key + '.title' }, 'description': { 'translate': key + '.description' }, 'frame': frame, 'show_toast': toast, 'announce_to_chat': chat, 'hidden': hidden, 'background': self.background }, parent, criteria, requirements) self.rm.lang(key + '.title', title) self.rm.lang(key + '.description', description)
def recipe_unlocked(recipe: ResourceIdentifier) -> Json: return { 'trigger': 'minecraft:recipe_unlocked', 'conditions': { 'recipe': utils.resource_location(recipe).join() } }
def configured(self, name_parts: ResourceIdentifier, feature: ResourceIdentifier, config: Json = None, root: str = ''): res = utils.resource_location(self.domain, name_parts) self.write((*self.resource_dir, 'data', res.domain, 'worldgen', root, res.path), utils.configure(feature, config))
def noise(self, name_parts: ResourceIdentifier, first_octave: float, *amplitudes: float): res = utils.resource_location(self.domain, name_parts) self.write((*self.resource_dir, 'data', res.domain, 'worldgen', 'noise', res.path), { 'firstOctave': first_octave, 'amplitudes': amplitudes })
def with_item_model(self) -> 'BlockContext': """ Shortcut for a block item model, which generates a model with a single parent reference to the block model of the same name """ self.rm.item_model(self.res, parent=utils.resource_location( self.rm.domain, 'block/' + self.res.path), no_textures=True) return self
def loot(self, name_parts: ResourceIdentifier, *loot_pools: Json, path: str, loot_type: str) -> ResourceLocation: res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'loot_tables', path, res.path), { 'type': loot_type, 'pools': [utils.loot_pool(pool, path) for pool in loot_pools] }) return res
def noise_threshold_condition(noise: ResourceIdentifier, min_value: float, max_value: float, then: JsonObject) -> JsonObject: return condition( { 'type': 'minecraft:noise_threshold', 'noise': utils.resource_location(noise).join(), 'min_threshold': min_value, 'max_threshold': max_value }, then)
def write(self, path_parts: Sequence[str], data_in: Json): m = self.modified_files super(ModificationLoggingResourceManager, self).write(path_parts, data_in) if m != self.modified_files: print('Modified: ' + utils.resource_location(self.domain, path_parts).join(), file=sys.stderr) traceback.print_stack() print('', file=sys.stderr)
def bucket_item_model(name_parts, fluid): res = utils.resource_location(rm.domain, name_parts) rm.write( (*rm.resource_dir, 'assets', res.domain, 'models', 'item', res.path), { 'parent': 'forge:item/bucket', 'loader': 'forge:bucket', 'fluid': fluid }) return rm.item(name_parts)
def biome(self, name_parts: ResourceIdentifier, precipitation: str = 'none', category: str = 'none', temperature: float = 0, temperature_modifier: str = 'none', downfall: float = 0.5, effects: Optional[Json] = None, air_carvers: Optional[Sequence[str]] = None, water_carvers: Optional[Sequence[str]] = None, features: Sequence[Sequence[str]] = None, structures: Sequence[str] = None, spawners: Optional[Json] = None, player_spawn_friendly: bool = True, creature_spawn_probability: float = 0.5, parent: Optional[str] = None, spawn_costs: Optional[Json] = None): """ Creates a biome, with all possible optional parameters filled in to the minimum required state. Parameters are exactly as they appear in the final biome. """ if effects is None: effects = {} for required_effect in ('fog_color', 'sky_color', 'water_color', 'water_fog_color'): if required_effect not in effects: effects[required_effect] = 0 if features is None: features = [] if structures is None: structures = [] if spawners is None: spawners = {} if spawn_costs is None: spawn_costs = {} res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'worldgen', 'biome', res.path), { 'precipitation': precipitation, 'category': category, 'temperature': temperature, 'temperature_modifier': temperature_modifier, 'downfall': downfall, 'effects': effects, 'carvers': { 'air': air_carvers, 'liquid': water_carvers }, 'features': features, 'starts': structures, 'spawners': spawners, 'player_spawn_friendly': player_spawn_friendly, 'creature_spawn_probability': creature_spawn_probability, 'parent': parent, 'spawn_costs': spawn_costs })
def biome_condition(biomes: Sequence[ResourceIdentifier], then: JsonObject) -> JsonObject: return condition( { 'type': 'minecraft:biome', 'biome_is': [ utils.resource_location(r).join() for r in utils.str_list(biomes) ] }, then)
def with_tag(self, tag_name_parts: Sequence[str] = None, replace: bool = None) -> 'BlockContext': """ Shortcut for ResourceManager#block_tag """ if tag_name_parts is None: tag_name_parts = self.res tag_res = utils.resource_location(self.rm.domain, tag_name_parts) self.rm.block_tag(tag_res, self.res, replace=replace) return self
def blockstate_multipart(self, name_parts: ResourceIdentifier, *parts: Json) -> BlockContext: """ Creates a blockstate file, using the multipart model syntax :param name_parts: the resource location, including path elements. :param parts: The parts. Each element can be a 2-element sequence of a 'when' and 'apply' json, or a single 'apply' json. """ res = utils.resource_location(self.domain, name_parts) self.write((*self.resource_dir, 'assets', res.domain, 'blockstates', res.path), {'multipart': utils.blockstate_multipart_parts(parts)}) return BlockContext(self, res)
def damage_shapeless(name_parts: utils.ResourceIdentifier, ingredients: utils.Json, result: utils.Json, group: str = None, conditions: utils.Json = None) -> RecipeContext: res = utils.resource_location(rm.domain, name_parts) rm.write((*rm.resource_dir, 'data', res.domain, 'recipes', res.path), { 'type': 'tfc:damage_inputs_crafting', 'recipe': { 'type': 'minecraft:crafting_shapeless', 'group': group, 'ingredients': utils.item_stack_list(ingredients), 'result': utils.item_stack(result), 'conditions': utils.recipe_condition(conditions) } }) return RecipeContext(rm, res)
def data(self, name_parts: ResourceIdentifier, data_in: Dict[str, Any], root_domain: str = 'data'): """ Creates a generic data file. Used for anything and everything under the sun. :param name_parts: The resource location, including path elements. :param data_in: Data to be inserted into the json :param root_domain: The root location (either data or assets) to insert into """ res = utils.resource_location(self.domain, name_parts) self.write((*self.resource_dir, root_domain, res.domain, res.path), data_in)
def tag(self, name_parts: ResourceIdentifier, root_domain: str, *values: ResourceIdentifier, replace: bool = None): """ Creates or appends to a tag entry :param name_parts: The resource location, including path elements. :param root_domain: The root domain of the tag. Should be 'blocks', 'items', 'fluids', or 'entity_types' :param values: The resource location values for the tag :param replace: If the tag should replace previous values """ res = utils.resource_location(self.domain, name_parts) values = [utils.resource_location(self.domain, v) for v in values] if res not in self.tags_buffer[root_domain]: if replace is None: replace = False tag = Tag(replace) tag.add_all(values) self.tags_buffer[root_domain][res] = tag else: self.tags_buffer[root_domain][res].add_all(values) if replace is not None: self.tags_buffer[root_domain][res].replace = replace
def recipe(self, name_parts: ResourceIdentifier, type_in: str, data_in: Dict[str, Any], group: str = None, conditions: Json = None) -> RecipeContext: """ Creates a non-crafting recipe file, used for custom mod recipes using vanilla's data pack system :param name_parts: The resource location, including path elements. :param type_in: The type of the recipe. :param data_in: Data required by the recipe, as present in json :param group: The group. :param conditions: Any conditions for the recipe to be enabled. """ res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'recipes', res.path), { 'type': type_in, 'group': group, **data_in, 'conditions': utils.recipe_condition(conditions) }) return RecipeContext(self, res)
def crafting_shapeless(self, name_parts: ResourceIdentifier, ingredients: Json, result: Json, group: str = None, conditions: Optional[Json] = None) -> RecipeContext: """ Creates a shapeless crafting recipe. :param name_parts: The resource location, including path elements. :param ingredients: The ingredients. :param result: The result of crafting the recipe. :param group: The group. :param conditions: Any conditions for the recipe to be enabled. """ res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'recipes', res.path), { 'type': 'minecraft:crafting_shapeless', 'group': group, 'ingredients': utils.item_stack_list(ingredients), 'result': utils.item_stack(result), 'conditions': utils.recipe_condition(conditions) }) return RecipeContext(self, res)
def blockstate(self, name_parts: ResourceIdentifier, model: str = None, variants: Dict[str, Json] = None, use_default_model: bool = True) -> BlockContext: """ Creates a blockstate file :param name_parts: the resource location, including path elements. :param model: the model, used if there are no variants. Defaults to 'domain:block/name/parts' :param variants: the variants, as they would be present in json :param use_default_model: if a model is missing for a variant, should this populate the variant using the assumed model """ res = utils.resource_location(self.domain, name_parts) if model is None: model = res.join('block/') if variants is None: variants = {'': {'model': model}} if use_default_model: for key, prop in variants.items(): if 'model' not in prop: prop['model'] = model self.write((*self.resource_dir, 'assets', res.domain, 'blockstates', res.path), {'variants': variants}) return BlockContext(self, res)
def noise_settings(self, name_parts: ResourceIdentifier, ore_veins_enabled: bool, noodle_caves_enabled: bool, legacy_random_source: bool, disable_mob_generation: bool, aquifers_enabled: bool, noise_caves_enabled: bool, default_block: Json, default_fluid: Json, sea_level: int, noise: Json, surface_rule: Json, structures: Json): res = utils.resource_location(self.domain, name_parts) self.write( (*self.resource_dir, 'data', res.domain, 'worldgen', 'noise_settings', res.path), { 'ore_veins_enabled': ore_veins_enabled, 'noodle_caves_enabled': noodle_caves_enabled, 'legacy_random_source': legacy_random_source, 'disable_mob_generation': disable_mob_generation, 'aquifers_enabled': aquifers_enabled, 'noise_caves_enabled': noise_caves_enabled, 'default_block': utils.block_state(default_block), 'default_fluid': utils.block_state(default_fluid), 'sea_level': sea_level, 'noise': noise, 'surface_rule': surface_rule, 'structures': structures })
def item(self, name_parts: ResourceIdentifier) -> ItemContext: return ItemContext(self, utils.resource_location(self.domain, name_parts))