diff --git a/build.gradle.kts b/build.gradle.kts index 78dc4ac..68443e4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,7 +17,7 @@ val jeiVersion: String = "15.2.0.21" val patchouliVersion: String = "1.20.1-81-FORGE" val jadeVersion: String = "4614153" val topVersion: String = "4629624" -val tfcVersion: String = "5478226" +val tfcVersion: String = "5571484" val modId: String = "beneath" diff --git a/resources/assets.py b/resources/assets.py index a2d0ca3..810d594 100644 --- a/resources/assets.py +++ b/resources/assets.py @@ -101,6 +101,12 @@ def generate(rm: ResourceManager): }).with_lang(lang('burpflower')).with_tag('tfc:plants').with_block_loot('beneath:burpflower') rm.item_model('burpflower', 'beneath:block/plant/burpflower_base') + for i in range(1, 9): + rm.block_model('unposter_%s' % i, parent='beneath:block/compost_%s' % i, textures={'0': 'beneath:block/unposter/normal'}) + rm.block_model('unposter_0', parent='beneath:block/unposter', no_textures=True) + rm.blockstate('unposter', variants=dict(('stage=%s' % i, {'model': 'beneath:block/unposter_%s' % i}) for i in range(0, 9))).with_lang(lang('unposter')).with_block_loot('beneath:unposter') + rm.item_model('unposter', parent='beneath:block/unposter', no_textures=True) + rm.blockstate('cursecoal_pile', variants=dict((('layers=%d' % i), {'model': 'beneath:block/pile/cursecoal_height%d' % (i * 2) if i != 8 else 'beneath:block/pile/cursecoal_block'}) for i in range(1, 1 + 8))).with_lang(lang('Cursecoal Pile')).with_block_loot('beneath:cursecoal') rm.block_model('pile/cursecoal_block', textures={'all': 'beneath:block/cursecoal'}) rm.blockstate('hellforge', variants=dict((('heat_level=%d' % i), {'model': 'beneath:block/hellforge/heat_%d' % i}) for i in range(0, 7 + 1))).with_lang(lang('Hellforge')).with_block_loot('7 beneath:cursecoal') @@ -131,9 +137,9 @@ def generate(rm: ResourceManager): rm.blockstate('crackrack').with_block_loot(loot_tables.alternatives({'name': 'beneath:crackrack', 'conditions': [{'condition': 'tfc:is_isolated'}]}, '2-4 beneath:crackrack_rock')).with_lang(lang('crackrack')).with_block_model().with_tag('minecraft:mineable/pickaxe').with_tag('minecraft:base_stone_nether').with_item_model() for shroom in MUSHROOMS: - mushlang = '%s mushroom' % shroom.replace('fools', 'Fool\'s') + mushlang = lang(shroom) if 'fools' not in shroom else 'Fool\'s Funnel' rm.blockstate('mushroom/%s' % shroom).with_block_model(parent='block/cross', textures={'cross': 'beneath:block/mushroom/%s' % shroom}).with_block_loot('beneath:food/%s' % shroom).with_tag('tfc:plants').with_tag('tfc:mineable_with_sharp_tool').with_lang(lang(mushlang)) - rm.item_model('food/%s' % shroom, 'beneath:block/mushroom/%s' % shroom).with_lang(lang(mushlang)) + rm.item_model('food/%s' % shroom, 'beneath:block/mushroom/%s' % shroom).with_lang(mushlang) simple_block(rm, 'cobblerack', 'minecraft:mineable/pickaxe', 'forge:cobblestone') simple_block(rm, 'fungal_cobblerack', 'minecraft:mineable/pickaxe') diff --git a/resources/constants.py b/resources/constants.py index 7d7643b..d1ccfe3 100644 --- a/resources/constants.py +++ b/resources/constants.py @@ -18,6 +18,7 @@ class Rock(NamedTuple): category: str sand: str +ROCK_CATEGORIES: List[str] = ['sedimentary', 'metamorphic', 'igneous_extrusive', 'igneous_intrusive'] TFC_METALS: Dict[str, Metal] = { 'gold': Metal(1, {'part'}, 0.6, 1060, None), @@ -118,6 +119,7 @@ class Rock(NamedTuple): 'beneath.nutrient.sorrow': 'Sorrow: §9%s%%', 'beneath.block_entity.hellforge': 'Hellforge', 'beneath.screen.juicer': 'Juicer', + 'beneath.screen.juicer.mushrooms': 'Feed me mushrooms!', 'item.beneath.juicer.filled': 'Juicer (%s)', 'death.attack.beneath.sulfur': '%1$s mined sulfur with an iron tool and blew themselves up.', 'death.attack.beneath.sulfur.player': '%1$s mined sulfur with an iron tool and blew themselves up while trying to escape %2$s.', diff --git a/resources/data.py b/resources/data.py index 459ef7b..cc572b1 100644 --- a/resources/data.py +++ b/resources/data.py @@ -241,7 +241,8 @@ def generate(rm: ResourceManager): ### ITEM TAGS ### rm.item_tag('sparks_on_sulfur', *['#tfc:metal_item/%s' % metal for metal in ('black_steel', 'blue_steel', 'red_steel', 'steel', 'wrought_iron', 'cast_iron')]) - rm.item_tag('usable_in_juicer', '#tfc:foods/fruits', '#beneath:mushrooms') + rm.item_tag('usable_in_juicer', '#tfc:foods/fruits', '#beneath:mushrooms', 'minecraft:warped_fungus', 'minecraft:crimson_fungus') + rm.item_tag('unpostable', '#beneath:mushrooms', 'minecraft:warped_fungus', 'minecraft:crimson_fungus', 'beneath:ghost_pepper', 'beneath:gleamflower', 'minecraft:crimson_roots', 'minecraft:warped_roots', 'minecraft:nether_wart', 'minecraft:ghast_tear') block_and_item_tag(rm, 'tfc:rock/aqueduct', 'beneath:blackstone_aqueduct') rm.item_tag('tfc:rock_knapping', 'beneath:nether_pebble', 'beneath:blackstone_pebble') diff --git a/resources/format_lang.py b/resources/format_lang.py new file mode 100644 index 0000000..484d58a --- /dev/null +++ b/resources/format_lang.py @@ -0,0 +1,89 @@ +import difflib +import json + +from typing import Tuple + + +def main(validate: bool, namespace: str, langs: Tuple[str, ...]): + en_us = load(namespace, 'en_us') + for lang in langs: + if lang != 'en_us': + format_lang(namespace, en_us, lang, validate) + + +def update(namespace: str, langs: Tuple[str, ...]): + en_us = load(namespace, 'en_us') + en_us_old = load_old(namespace, 'en_us') + updated_keys = {k for k in en_us.keys() if k in en_us_old and en_us[k] != en_us_old[k]} + + if updated_keys: + print('Found %d modified values:' % len(updated_keys)) + for k in updated_keys: + print('Modified: %s : "%s" -> "%s"' % (k, en_us_old[k], en_us[k])) + + inp = input('Remove these keys from other translations?\n(yes|no) >') + print('Answer: %s' % inp) + if inp == 'yes': + # Strip these keys from en_us, so they don't show up in translations + for k in updated_keys: + del en_us[k] + for lang in langs: + if lang != 'en_us': + format_lang(namespace, en_us, lang, False) + else: + print('No differences found') + + +def format_lang(namespace: str, en_us, lang: str, validate: bool): + lang_data = load(namespace, lang) + lang_comments = {k: v for k, v in lang_data.items() if '__comment' in k and v != 'This file was automatically created by mcresources'} + lang_data = {k: v for k, v in lang_data.items() if '__comment' not in k} + + formatted_lang_data = {} + for k, v in lang_comments.items(): + formatted_lang_data[k] = v + + translated = 0 + for k, v in en_us.items(): + if '__comment' in k: + pass # Exclude comments in en_us + elif k in lang_data and lang_data[k] != v: + translated += 1 + formatted_lang_data[k] = lang_data[k] + else: + formatted_lang_data[k] = v + + # Unique keys to this language, only allowed in the default vanilla overrides. It makes no sense for a language to have uniquely named TFC keys + # But, for vanilla minecraft, we may have to override for vanilla items we rename without renaming. + # e.g. we use 'Egg' but if a translation is 'Chicken Egg', that might be renamed for other languages only. + if namespace == 'minecraft': + for k, v in lang_data.items(): + if k not in en_us: + formatted_lang_data[k] = v + + print('Translation progress for %s (%s): %d / %d (%.1f%%)' % (lang, namespace, translated, len(en_us), 100 * translated / len(en_us))) + save(namespace, lang, formatted_lang_data, validate) + + +def load(namespace: str, lang: str): + with open('./src/main/resources/assets/%s/lang/%s.json' % (namespace, lang), 'r', encoding='utf-8') as f: + return json.load(f) + + +def load_old(namespace: str, lang: str): + """ The old lang file need to be manually placed under the project root and + be named as exactly `..old.json`, where is the + language code, and is usually either 'minecraft' or 'tfc'. + """ + with open('./%s.%s.old.json' % (lang, namespace), 'r', encoding='utf-8') as f: + return json.load(f) + + +def save(namespace: str, lang: str, lang_data, validate: bool): + if validate: + with open('./src/main/resources/assets/%s/lang/%s.json' % (namespace, lang), 'r', encoding='utf-8') as f: + old_lang_data = json.load(f) + assert old_lang_data == lang_data, 'Validation error in mod localization for %s:\n\n=== Diff (expected vs. actual) ===\n\n%s' % (lang, '\n'.join(difflib.unified_diff(json.dumps(lang_data, ensure_ascii=False, indent=2).split('\n'), json.dumps(old_lang_data, ensure_ascii=False, indent=2).split('\n')))) + else: + with open('./src/main/resources/assets/%s/lang/%s.json' % (namespace, lang), 'w', encoding='utf-8') as f: + json.dump(lang_data, f, ensure_ascii=False, indent=2) diff --git a/resources/generate_book.py b/resources/generate_book.py new file mode 100644 index 0000000..619d4d9 --- /dev/null +++ b/resources/generate_book.py @@ -0,0 +1,107 @@ +import format_lang +from patchouli import * +from argparse import ArgumentParser +from typing import Optional + +BOOK_LANGUAGES = ('en_us',) +MOD_LANGUAGES = ('en_us',) + +class LocalInstance: + INSTANCE_DIR = None + + @staticmethod + def wrap(rm: ResourceManager): + def data(name_parts: ResourceIdentifier, data_in: JsonObject, root_domain: str = 'data'): + return rm.write((LocalInstance.INSTANCE_DIR, '/'.join(utils.str_path(name_parts))), data_in) + + if LocalInstance.INSTANCE_DIR is not None: + rm.data = data + return rm + return None + +def main_with_args(): + parser = ArgumentParser('generate_book.py') + parser.add_argument('--translate', type=str, default='en_us', help='The language to translate to') + parser.add_argument('--local', type=str, default=None, help='The directory of a local .minecraft to copy into') + parser.add_argument('--translate-all', type=str, default=None, help='If all languages should be translated') + parser.add_argument('--format', type=str, default=None, help='Format the mod languages') + parser.add_argument('--reverse-translate', type=str, default=None, help='Reverse a translation from the mod files.') + + args = parser.parse_args() + + if args.format: + do_format() + return + + if args.translate_all: + do_format() + for la in BOOK_LANGUAGES: + main(la, args.local, False, reverse_translate=args.reverse_translate is not None) + else: + main(args.translate, args.local, False, reverse_translate=args.reverse_translate is not None) + +def do_format(): + # format_lang.main(False, 'minecraft', BOOK_LANGUAGES) + format_lang.main(False, 'beneath', MOD_LANGUAGES) + +def main(translate_lang: str, local_minecraft_dir: Optional[str], validate: bool, validating_rm: ResourceManager = None, reverse_translate: bool = False): + LocalInstance.INSTANCE_DIR = local_minecraft_dir + + rm = ResourceManager('tfc', './src/main/resources') + if validate: + rm = validating_rm + i18n = I18n(translate_lang, validate) + + print('Writing book at %s' % translate_lang) + make_book(rm, i18n, local_instance=False, reverse_translate=reverse_translate) + + i18n.flush() + + if LocalInstance.wrap(rm): + print('Copying %s book into local instance at: %s' % (translate_lang, LocalInstance.INSTANCE_DIR)) + make_book(rm, I18n(translate_lang, validate), local_instance=True) + + +# def main(): +# for language in BOOK_LANGUAGES: +# rm = ResourceManager('tfc', '../src/main/resources') +# i18n = I18n.create(language) +# +# print('Writing book %s' % language) +# make_book(rm, i18n) +# +# i18n.flush() +# +# if LocalInstance.wrap(rm) and language == 'en_us': +# print('Copying into local instance at: %s' % LocalInstance.INSTANCE_DIR) +# make_book(rm, I18n.create('en_us'), local_instance=True) +# +# print('Done') + +def make_book(rm: ResourceManager, i18n: I18n, local_instance: bool = False, reverse_translate: bool = False): + book = Book(rm, 'field_guide', {}, i18n, local_instance, reverse_translate) + + book.category('beneath', 'Beneath', 'All about what is Beneath', 'beneath:cursecoal', is_sorted=True, entries=( + entry('beneath', 'What Lies Beneath', 'beneath:textures/item/cursecoal.png', pages=( + text('XXX'), + empty_last_page() + )), + )) + + book.build() + +# beneath Pages + +def knapping(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('knapping_recipe', recipe, text_content) + +def alloy_recipe(title: str, ingot: str, *components: Tuple[str, int, int], text_content: str) -> Page: + recipe = ''.join(['$(li)%d - %d %% : $(thing)%s$()' % (lo, hi, alloy) for (alloy, lo, hi) in components]) + return item_spotlight(ingot, title, False, '$(br)$(bold)Requirements:$()$(br)' + recipe + '$(br2)' + text_content) + +def custom_component(x: int, y: int, class_name: str, data: JsonObject) -> Component: + return Component('patchouli:custom', x, y, {'class': 'com.eerussianguy.beneath.compat.patchouli.' + class_name, **data}) + + +if __name__ == '__main__': + main_with_args() + diff --git a/resources/i18n.py b/resources/i18n.py new file mode 100644 index 0000000..9192854 --- /dev/null +++ b/resources/i18n.py @@ -0,0 +1,85 @@ +import json +import os + +import Levenshtein + + +class I18n: + + lang: str + + def __init__(self, lang: str, validate: bool = False): + self.lang = lang + self.before = {} + self.after = {} + self.validate = validate + self.lang_path = './resources/lang/%s.json' % lang + + self.fuzzy_matches = 0 + self.fuzzy_non_matches = 0 + + # Default translation + if not os.path.isfile(self.lang_path): + if validate: + raise ValueError('Cannot validate book for lang %s, as resources/lang/%s.json does not exist' % (lang, lang)) + print('Writing default translation for language %s to %s' % (self.lang, self.lang_path)) + with open(self.lang_path, 'w', encoding='utf-8') as f: + f.write('{}\n') + + # Read the existing translation + with open(self.lang_path, 'r', encoding='utf-8') as f: + print('Reading translation for language %s to %s' % (self.lang, self.lang_path)) + j = json.load(f) + + # Parse json + for key, value in j.items(): + if not isinstance(value, str): + print('Illegal translation entry: "%s": "%s"' % (key, value)) + exit(-1) + self.before[key] = value + + def is_root(self) -> bool: + """ Return true if we are in the root language (en_us) """ + return self.lang == 'en_us' + + def translate(self, text: str) -> str: + """ Translates the string into the current domain """ + if self.is_root(): + # For en_us, always keep the current text (read only) + translated = text + elif text in self.before: + translated = self.before[text] # Translate if available + else: + # Try a fuzzy matcher (if we're not in en_us) + # Use the lowercase of both keys, as difference in capitalization is almost surely not a translation issue + distance, match = min(((Levenshtein.distance(text.lower(), key.lower()), key) for key in self.before.keys())) + if distance / len(text) < 0.1 and distance < 20: # Heuristic: < 5% of text, and < 20 overall distance + if self.before[match] == match: + # This has just matched a default key that was inserted in the translated files + # So if we slightly modify the en_us default, we should change this value as well. + self.fuzzy_non_matches += 1 + translated = text + else: + # Use the fuzzy match + self.fuzzy_matches += 1 + translated = self.before[match] + else: + # Not available, but record and output anyway + self.fuzzy_non_matches += 1 + translated = text + + self.after[text] = translated + return translated + + def flush(self): + """ Updates the local translation file, if needed """ + if not self.is_root() and self.fuzzy_matches + self.fuzzy_non_matches > 0: + print('Matched %d / %d entries (%.1f%%). Updated %d entries for lang %s.' % (self.fuzzy_matches, self.fuzzy_matches + self.fuzzy_non_matches, 100 * self.fuzzy_matches / (self.fuzzy_matches + self.fuzzy_non_matches), self.fuzzy_non_matches, self.lang)) + if self.validate: + assert self.before == self.after, 'Validation error translating book to lang \'%s\'' % self.lang + with open(self.lang_path, 'w', encoding='utf-8') as f: + unique_count = len(self.after) if self.is_root() else sum(k != v for k, v in self.after.items()) + if unique_count > 0: + print('Writing updated translation for language %s: %d / %d (%.2f%%)' % (self.lang, unique_count, len(self.after), 100 * unique_count / len(self.after))) + json.dump(self.after, f, indent=2, ensure_ascii=False) + diff --git a/resources/models/Nether deer.bbmodel b/resources/models/Nether deer.bbmodel new file mode 100644 index 0000000..7cf899c --- /dev/null +++ b/resources/models/Nether deer.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"4.10","model_format":"bedrock","box_uv":true},"name":"Nether deer","model_identifier":"","visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"bedrock_animation_mode":"entity","timeline_setups":[],"unhandled_root_fields":{},"resolution":{"width":64,"height":64},"elements":[{"name":"main","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-3,9,-9],"to":[3,17,8],"autouv":0,"color":7,"origin":[0,-1,0],"faces":{"north":{"uv":[17,17,23,25],"texture":1},"east":{"uv":[0,17,17,25],"texture":1},"south":{"uv":[40,17,46,25],"texture":1},"west":{"uv":[23,17,40,25],"texture":1},"up":{"uv":[23,17,17,0],"texture":1},"down":{"uv":[29,0,23,17],"texture":1}},"type":"cube","uuid":"0deb25a0-b63c-ff93-4146-8b1f70152ef1"},{"name":"tail0","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-1,15,8],"to":[1,17,11],"autouv":0,"color":2,"origin":[0,16,8],"uv_offset":[38,8],"faces":{"north":{"uv":[41,11,43,13],"texture":1},"east":{"uv":[38,11,41,13],"texture":1},"south":{"uv":[46,11,48,13],"texture":1},"west":{"uv":[43,11,46,13],"texture":1},"up":{"uv":[43,11,41,8],"texture":1},"down":{"uv":[45,8,43,11],"texture":1}},"type":"cube","uuid":"a6bf1b24-e832-f2a8-fad2-5374aa2d82fa"},{"name":"haunch","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[2,8,3],"to":[4,15,7],"autouv":0,"color":1,"origin":[3,13,5],"uv_offset":[29,0],"faces":{"north":{"uv":[33,4,35,11],"texture":1},"east":{"uv":[29,4,33,11],"texture":1},"south":{"uv":[39,4,41,11],"texture":1},"west":{"uv":[35,4,39,11],"texture":1},"up":{"uv":[35,4,33,0],"texture":1},"down":{"uv":[37,0,35,4],"texture":1}},"type":"cube","uuid":"16267690-76cb-cc32-0dae-7cd5887e1eaf"},{"name":"leg","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[2,0,5],"to":[4,8,7],"autouv":0,"color":5,"origin":[0,-1,0],"uv_offset":[16,36],"faces":{"north":{"uv":[18,38,20,46],"texture":1},"east":{"uv":[16,38,18,46],"texture":1},"south":{"uv":[22,38,24,46],"texture":1},"west":{"uv":[20,38,22,46],"texture":1},"up":{"uv":[20,38,18,36],"texture":1},"down":{"uv":[22,36,20,38],"texture":1}},"type":"cube","uuid":"9cb10539-72bd-0b60-1e2c-c687b29f8453"},{"name":"haunch","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-4,8,3],"to":[-2,15,7],"autouv":0,"color":1,"origin":[-3,14,5],"uv_offset":[18,25],"faces":{"north":{"uv":[22,29,24,36],"texture":1},"east":{"uv":[18,29,22,36],"texture":1},"south":{"uv":[28,29,30,36],"texture":1},"west":{"uv":[24,29,28,36],"texture":1},"up":{"uv":[24,29,22,25],"texture":1},"down":{"uv":[26,25,24,29],"texture":1}},"type":"cube","uuid":"48807340-9127-b147-e4a4-23c129fbc760"},{"name":"leg","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-4,0,5],"to":[-2,8,7],"autouv":0,"color":5,"origin":[-6,-1,0],"uv_offset":[8,35],"faces":{"north":{"uv":[10,37,12,45],"texture":1},"east":{"uv":[8,37,10,45],"texture":1},"south":{"uv":[14,37,16,45],"texture":1},"west":{"uv":[12,37,14,45],"texture":1},"up":{"uv":[12,37,10,35],"texture":1},"down":{"uv":[14,35,12,37],"texture":1}},"type":"cube","uuid":"f1a4a78b-8517-473f-a281-c83113fa559e"},{"name":"leg","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-4,0,-7],"to":[-2,10,-5],"autouv":0,"color":7,"origin":[-5,-1,0],"uv_offset":[0,35],"faces":{"north":{"uv":[2,37,4,47],"texture":1},"east":{"uv":[0,37,2,47],"texture":1},"south":{"uv":[6,37,8,47],"texture":1},"west":{"uv":[4,37,6,47],"texture":1},"up":{"uv":[4,37,2,35],"texture":1},"down":{"uv":[6,35,4,37],"texture":1}},"type":"cube","uuid":"0d5ac48b-b679-bd9d-3ff8-f90ca2a549d0"},{"name":"haunch","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-4,10,-8],"to":[-2,14,-5],"autouv":0,"color":6,"origin":[0,-1,0],"uv_offset":[24,37],"faces":{"north":{"uv":[27,40,29,44],"texture":1},"east":{"uv":[24,40,27,44],"texture":1},"south":{"uv":[32,40,34,44],"texture":1},"west":{"uv":[29,40,32,44],"texture":1},"up":{"uv":[29,40,27,37],"texture":1},"down":{"uv":[31,37,29,40],"texture":1}},"type":"cube","uuid":"20f2e01c-5c3f-1257-4bab-a078ea9fbf8f"},{"name":"haunch","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[2,10,-8],"to":[4,14,-5],"autouv":0,"color":2,"origin":[3,12,-7],"uv_offset":[35,34],"faces":{"north":{"uv":[38,37,40,41],"texture":1},"east":{"uv":[35,37,38,41],"texture":1},"south":{"uv":[43,37,45,41],"texture":1},"west":{"uv":[40,37,43,41],"texture":1},"up":{"uv":[40,37,38,34],"texture":1},"down":{"uv":[42,34,40,37],"texture":1}},"type":"cube","uuid":"a1e4906e-40e3-75c3-5b21-bc1826ec77ef"},{"name":"leg","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[2,0,-7],"to":[4,10,-5],"autouv":0,"color":3,"origin":[3,12,-7],"uv_offset":[30,25],"faces":{"north":{"uv":[32,27,34,37],"texture":1},"east":{"uv":[30,27,32,37],"texture":1},"south":{"uv":[36,27,38,37],"texture":1},"west":{"uv":[34,27,36,37],"texture":1},"up":{"uv":[34,27,32,25],"texture":1},"down":{"uv":[36,25,34,27],"texture":1}},"type":"cube","uuid":"cf310a51-e057-ae3f-645d-acc9a3aacb5f"},{"name":"neck0","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-1.5,12.398309467391702,-8.184591911282514],"to":[1.5,23.3983094673917,-4.184591911282514],"autouv":0,"color":7,"rotation":[-37.5,0,0],"origin":[-0.0871557427476582,13.996194698091745,-7],"faces":{"north":{"uv":[4,4,7,15],"texture":1},"east":{"uv":[0,4,4,15],"texture":1},"south":{"uv":[11,4,14,15],"texture":1},"west":{"uv":[7,4,11,15],"texture":1},"up":{"uv":[7,4,4,0],"texture":1},"down":{"uv":[10,0,7,4],"texture":1}},"type":"cube","uuid":"96ffc16a-7d56-8aae-41b4-aabcb6e58750"},{"name":"skull","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-2,20,-15],"to":[2,25,-10],"autouv":0,"color":6,"origin":[-0.0871557427476582,20.996194698091745,-12],"uv_offset":[0,25],"faces":{"north":{"uv":[5,30,9,35],"texture":1},"east":{"uv":[0,30,5,35],"texture":1},"south":{"uv":[14,30,18,35],"texture":1},"west":{"uv":[9,30,14,35],"texture":1},"up":{"uv":[9,30,5,25],"texture":1},"down":{"uv":[13,25,9,30],"texture":1}},"type":"cube","uuid":"f6150925-fce9-e026-44d1-bf6ccf9684d2"},{"name":"snout","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-1.5,20,-18],"to":[1.5,23,-15],"autouv":0,"color":4,"origin":[-0.0871557427476582,22.996194698091745,-15],"uv_offset":[29,11],"faces":{"north":{"uv":[32,14,35,17],"texture":1},"east":{"uv":[29,14,32,17],"texture":1},"south":{"uv":[38,14,41,17],"texture":1},"west":{"uv":[35,14,38,17],"texture":1},"up":{"uv":[35,14,32,11],"texture":1},"down":{"uv":[38,11,35,14],"texture":1}},"type":"cube","uuid":"640b887f-10a0-bca1-5d80-c428b79b3ace"},{"name":"ear","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-3.087155742747658,23.996194698091745,-11],"to":[-1.0871557427476581,26.996194698091745,-10],"autouv":0,"color":3,"origin":[-2.087155742747658,24.996194698091745,-11],"uv_offset":[41,4],"faces":{"north":{"uv":[42,5,44,8],"texture":1},"east":{"uv":[41,5,42,8],"texture":1},"south":{"uv":[45,5,47,8],"texture":1},"west":{"uv":[44,5,45,8],"texture":1},"up":{"uv":[44,5,42,4],"texture":1},"down":{"uv":[46,4,44,5],"texture":1}},"type":"cube","uuid":"97517338-b119-3fb1-966e-9e64353ccc7b"},{"name":"ear","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[0.9128442572523419,23.996194698091745,-11],"to":[2.912844257252342,26.996194698091745,-10],"autouv":0,"color":4,"origin":[1.9128442572523419,24.996194698091745,-11],"uv_offset":[10,0],"faces":{"north":{"uv":[11,1,13,4],"texture":1},"east":{"uv":[10,1,11,4],"texture":1},"south":{"uv":[14,1,16,4],"texture":1},"west":{"uv":[13,1,14,4],"texture":1},"up":{"uv":[13,1,11,0],"texture":1},"down":{"uv":[15,0,13,1],"texture":1}},"type":"cube","uuid":"82f51c69-d329-356c-fb0f-09960b6a8ec9"},{"name":"antler0","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[0.9128442572523419,24.496194698091745,-12.5],"to":[1.9128442572523419,29.496194698091745,-11.5],"autouv":0,"color":5,"rotation":[-18.076385285113698,-9.307268232795982,-23.306962347777123],"origin":[0.9128442572523419,24.996194698091745,-12.5],"uv_offset":[34,41],"faces":{"north":{"uv":[35,42,36,47],"texture":1},"east":{"uv":[34,42,35,47],"texture":1},"south":{"uv":[37,42,38,47],"texture":1},"west":{"uv":[36,42,37,47],"texture":1},"up":{"uv":[36,42,35,41],"texture":1},"down":{"uv":[37,41,36,42],"texture":1}},"type":"cube","uuid":"da2cdb53-5fdb-1487-b6c1-afe25a3eb15a"},{"name":"antler1","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[1.4128442572523419,26.246194698091745,-12.5],"to":[5.412844257252342,27.246194698091745,-11.5],"autouv":0,"color":2,"rotation":[-2.6214441557214974,34.73948288349534,-13.810458721109068],"origin":[0.9128442572523419,24.996194698091745,-12.5],"uv_offset":[36,25],"faces":{"north":{"uv":[37,26,41,27],"texture":1},"east":{"uv":[36,26,37,27],"texture":1},"south":{"uv":[42,26,46,27],"texture":1},"west":{"uv":[41,26,42,27],"texture":1},"up":{"uv":[41,26,37,25],"texture":1},"down":{"uv":[45,25,41,26],"texture":1}},"type":"cube","uuid":"ba3e39db-0de5-fdce-6d34-79f8cc1eb4bc"},{"name":"antler2","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[4.2773320681597875,25.34212436244039,-17.02158900559678],"to":[5.2773320681597875,26.34212436244039,-14.021589005596779],"autouv":0,"color":2,"rotation":[-1.73636916530082,9.72672792679023,-19.516647797316583],"origin":[4.912844257252342,25.996194698091745,-14.5],"uv_offset":[37,0],"faces":{"north":{"uv":[40,3,41,4],"texture":1},"east":{"uv":[37,3,40,4],"texture":1},"south":{"uv":[44,3,45,4],"texture":1},"west":{"uv":[41,3,44,4],"texture":1},"up":{"uv":[41,3,40,0],"texture":1},"down":{"uv":[42,0,41,3],"texture":1}},"type":"cube","uuid":"217a6860-9f04-1735-0e80-09e2bb9294f5"},{"name":"antler3","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[4.162844257252342,25.996194698091745,-15.25],"to":[5.162844257252342,27.996194698091745,-14.25],"autouv":0,"color":6,"rotation":[-16.240740940758293,-6.607958304498809,-21.55612609197072],"origin":[4.412844257252342,26.496194698091745,-15],"uv_offset":[13,14],"faces":{"north":{"uv":[14,15,15,17],"texture":1},"east":{"uv":[13,15,14,17],"texture":1},"south":{"uv":[16,15,17,17],"texture":1},"west":{"uv":[15,15,16,17],"texture":1},"up":{"uv":[15,15,14,14],"texture":1},"down":{"uv":[16,14,15,15],"texture":1}},"type":"cube","uuid":"68563f4e-6394-beb2-4832-b41568f378a4"},{"name":"antler0","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-1.9128442572523419,24.496194698091745,-12.5],"to":[-0.9128442572523419,29.496194698091745,-11.5],"autouv":0,"color":5,"rotation":[-18.076385285113698,9.307268232795982,23.306962347777123],"origin":[-0.9128442572523419,24.996194698091745,-12.5],"uv_offset":[38,27],"faces":{"north":{"uv":[39,28,40,33],"texture":1},"east":{"uv":[38,28,39,33],"texture":1},"south":{"uv":[41,28,42,33],"texture":1},"west":{"uv":[40,28,41,33],"texture":1},"up":{"uv":[40,28,39,27],"texture":1},"down":{"uv":[41,27,40,28],"texture":1}},"type":"cube","uuid":"5b22c2ee-9ee2-29b4-a15f-d99b46d94be6"},{"name":"antler1","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-5.412844257252342,26.246194698091745,-12.5],"to":[-1.4128442572523419,27.246194698091745,-11.5],"autouv":0,"color":2,"rotation":[-2.6214441557214974,-34.73948288349534,13.810458721109068],"origin":[-0.9128442572523419,24.996194698091745,-12.5],"uv_offset":[0,15],"faces":{"north":{"uv":[1,16,5,17],"texture":1},"east":{"uv":[0,16,1,17],"texture":1},"south":{"uv":[6,16,10,17],"texture":1},"west":{"uv":[5,16,6,17],"texture":1},"up":{"uv":[5,16,1,15],"texture":1},"down":{"uv":[9,15,5,16],"texture":1}},"type":"cube","uuid":"4b07a0b6-5530-3a60-f7a8-fdd5635f1076"},{"name":"antler2","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-5.2773320681597875,25.34212436244039,-17.02158900559678],"to":[-4.2773320681597875,26.34212436244039,-14.021589005596779],"autouv":0,"color":2,"rotation":[-1.73636916530082,-9.72672792679023,19.516647797316583],"origin":[-4.912844257252342,25.996194698091745,-14.5],"uv_offset":[13,25],"faces":{"north":{"uv":[16,28,17,29],"texture":1},"east":{"uv":[13,28,16,29],"texture":1},"south":{"uv":[20,28,21,29],"texture":1},"west":{"uv":[17,28,20,29],"texture":1},"up":{"uv":[17,28,16,25],"texture":1},"down":{"uv":[18,25,17,28],"texture":1}},"type":"cube","uuid":"8ef9434c-ca2d-9c45-0fb1-98258a1c6bdb"},{"name":"antler3","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-5.162844257252342,25.996194698091745,-15.25],"to":[-4.162844257252342,27.996194698091745,-14.25],"autouv":0,"color":6,"rotation":[-16.240740940758293,6.607958304498809,21.55612609197072],"origin":[-4.412844257252342,26.496194698091745,-15],"faces":{"north":{"uv":[1,1,2,3],"texture":1},"east":{"uv":[0,1,1,3],"texture":1},"south":{"uv":[3,1,4,3],"texture":1},"west":{"uv":[2,1,3,3],"texture":1},"up":{"uv":[2,1,1,0],"texture":1},"down":{"uv":[3,0,2,1],"texture":1}},"type":"cube","uuid":"497e5b05-7f41-b1b2-a682-a2bb00138058"}],"outliner":[{"name":"body","origin":[0,-1,0],"bedrock_binding":"","color":0,"uuid":"e5fe8298-cea8-344f-6257-9f18adaa219e","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":[{"name":"neck","origin":[0,14,-6],"bedrock_binding":"","color":0,"uuid":"8cc81a55-f0f2-12ea-f6d5-0930fc3dff4e","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":[{"name":"head","origin":[-0.0871557427476582,20.996194698091745,-11],"bedrock_binding":"","color":0,"uuid":"8d1fd0f9-a43f-7d42-0733-694ef49f7f1a","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["f6150925-fce9-e026-44d1-bf6ccf9684d2","640b887f-10a0-bca1-5d80-c428b79b3ace",{"name":"earL","origin":[-2.087155742747658,24.996194698091745,-11],"rotation":[5,-1,8],"bedrock_binding":"","color":0,"uuid":"d5a224db-376f-8330-8585-4aefec418fcb","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["97517338-b119-3fb1-966e-9e64353ccc7b"]},{"name":"earR","origin":[1.9128442572523419,24.996194698091745,-11],"rotation":[5,-1,-8],"bedrock_binding":"","color":0,"uuid":"e4f85fc0-8cc0-44df-017a-4e18ef902383","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["82f51c69-d329-356c-fb0f-09960b6a8ec9"]},{"name":"antlerL","origin":[0.9128442572523419,24.996194698091745,-12.5],"rotation":[0,-10,0],"bedrock_binding":"","color":0,"uuid":"1f8d908b-8aaa-53ac-3114-5a2f0fb57de1","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["da2cdb53-5fdb-1487-b6c1-afe25a3eb15a","ba3e39db-0de5-fdce-6d34-79f8cc1eb4bc","217a6860-9f04-1735-0e80-09e2bb9294f5","68563f4e-6394-beb2-4832-b41568f378a4"]},{"name":"antlerL2","origin":[-0.9128442572523419,24.996194698091745,-12.5],"rotation":[0,10,0],"bedrock_binding":"","color":0,"uuid":"b4a8678f-2bef-c5df-f8d9-ef765ad8d928","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["5b22c2ee-9ee2-29b4-a15f-d99b46d94be6","4b07a0b6-5530-3a60-f7a8-fdd5635f1076","8ef9434c-ca2d-9c45-0fb1-98258a1c6bdb","497e5b05-7f41-b1b2-a682-a2bb00138058"]}]},"96ffc16a-7d56-8aae-41b4-aabcb6e58750"]},"0deb25a0-b63c-ff93-4146-8b1f70152ef1",{"name":"tail","origin":[0,16,8],"rotation":[50,0,0],"bedrock_binding":"","color":0,"uuid":"47e29571-c3ef-b5fb-89f1-b3567476af77","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["a6bf1b24-e832-f2a8-fad2-5374aa2d82fa"]},{"name":"legBR","origin":[3,13,5],"bedrock_binding":"","color":0,"uuid":"525b418e-bc74-7cc7-e6d9-525257dfe8a8","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["16267690-76cb-cc32-0dae-7cd5887e1eaf","9cb10539-72bd-0b60-1e2c-c687b29f8453"]},{"name":"legBL","origin":[-3,13,5],"bedrock_binding":"","color":0,"uuid":"d7345c05-fc55-9b1f-e0b7-2a46bb6f170f","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["48807340-9127-b147-e4a4-23c129fbc760","f1a4a78b-8517-473f-a281-c83113fa559e"]},{"name":"legFR","origin":[3,13,-6],"bedrock_binding":"","color":0,"uuid":"0c6317ce-4f2c-c4e4-fa04-6df0b8b050ce","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["a1e4906e-40e3-75c3-5b21-bc1826ec77ef","cf310a51-e057-ae3f-645d-acc9a3aacb5f"]},{"name":"legFL","origin":[-3,13,-6],"bedrock_binding":"","color":0,"uuid":"ddee54d8-11f9-19b6-df85-558d120f17f5","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["0d5ac48b-b679-bd9d-3ff8-f90ca2a549d0","20f2e01c-5c3f-1257-4bab-a078ea9fbf8f"]}]}],"textures":[{"path":"C:\\Users\\andre\\OneDrive\\Рабочий стол\\deerqqq.png","name":"nether_deer_fawn.png","folder":"","namespace":"","id":"3","width":64,"height":64,"uv_width":64,"uv_height":64,"particle":false,"use_as_default":false,"layers_enabled":false,"sync_to_project":"","render_mode":"default","render_sides":"auto","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"internal":true,"saved":true,"uuid":"77d92480-9abc-7570-0d59-7f0637596675","relative_path":"deerqqq.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAFTdJREFUeF7tWgmUHFW5/qq6q6qru6v3ZbaezCQzSWayBxKWALKqBFlVUFB58kTC8nABFTzyULaHgE9EUDZRFoNGxCdgFFAQshgSMllIMjPJZJm1p6f3vaqru+5793amSUgQz2MGc97jnjOn5t6qrrr3u9///9//V3F4R7vjnBMIHRqJx2pnTm+sx3krXuVua3eQoSGNjc8/eTGW/XEVG5taUMCFfKhEI0g8vwVTzl0MUSDQGhrwkZ8+BWuoCWVVQ6GnB6u+dRUueG0jd+Bjnz5mPqkAiHntbPirK1cfdP6dc5zI/iEPumbJTAZArlisPee05kb0b9+Ga1a8xsZuOP5YdmxqktCnuLHwqfWwfvZElEZTsAadqC+XEM3ocM9uweJ7HoajrY1dn1y/Hn+98Vp8Zs3mg577m8XzCeGA0f0AXPvPBGCZLDEA6OLGW8fChXj5ub/hRztHAb+Mr7id7Dxlg7iwBcckysglciiBwN9SD2MkDovM4ejv3wdl9py3GdDbi/TWLWi7/PKDAPjlsfPp+lG0SeAN4IuvvvHPYwClNF34aKChBsBJwXq88se1uHf7MLgGOwOALpy2Oq8frZv7AamCsbSOjiYbep56A3MuPg4ddz0IU0PDQQwoDQ6i+ZJLDlrgk0uOIiZCQDgOPCH47NquDw6A245qJ7GeIVh4E6588CE4Fh8D0e9HKRpF7E9/xG9/eg+4SAZT6kX0h0uQV/WgdMkJuH7Trtoklzc2ktjLXdBP6oTVZIYz6IIsWXDUt78L99FHs/tRH6Dt2Y3Exo147d+/w8DjPQpkSUI2E2X9CKei4m1ASzLN+k6OZ8fzeoY5ykzKOkf7XOx4dQMeLGoTAhL3k1MWkT1qFhaD4PJr//0gADLr38BTP/wegnLVOSW694EPedEplLB0fX9tAr9qDpFyyAcpM4qESYG2fBU8H12A0x/7BWwdHQwANZVCJRxGdscOPH/7d2A8sw7CKXMBjiCrl0EIwXBHANPtbpB4CpWBGIIOiY2//j8mdefadWwO91/4EXak5jcRIHB3LZxOLE+twnm9a9mNqc3SCRf222vPY7cil9GgWCRs0ngI4TTcbgFf7hurAfCb2dNJUctAIwbKdhesugFF12o+gN7PbJGQ2bKV+YDf3/AtGADcLjOydgcs+TRi8RLqWnn0766gvc6GjOKE01z1Q2u39OBHlBXRIr4yva7mgL+zK/O+WcD90O8loosDDx5n3fUQoyyvOGp0FX0+vPLNK8ETIPXcFpQvOQGOXBpf2vU2ACvmzCCjv34d2okdsId8cBEelXgGZzz2C+YDlAOiAPUBLz56L5LZNMp7orCv7oHpvNkYG9MQ0TTUz2uFp1x1PzmtBNNICnsKeQYAGcnhq7Maa/7nvjW97x+AJ6cGidxUj8VfuxmizcYoawhCja4r/u0aSKt70PjJBdgzpsLpMkF9fhuu7Qwe5ANSfhsExQa9dwj1TgsGf/8mLhzaUruf2SIzULPd3XjimqvgXLMT7ZcvxmZVgtPhRDKTwi5SQlNfAs7WACyCgHRfmJmAWRBh5zhctquPMUmyWN73wsc9PPdARyup/HYdXJd9FB+75e7ajtGYTXcLViv+tGwZFLsJ0ec3wXruXKRSZVwfjb9tAnNnkCgPaGbAMpiCJ+BCJZnDCT++vxYGqQ8o9Q8wE3jtnu/AaeEBjkO6UMZYTIfbY0aicwb0sRice2LM6faZ7chrJXgjedT7BZzdtYf5Emdd3cQB8MtFc0i0VATRy/jk7T9kE+YVe22yK5ecg8DnTkNRUxGPJGBu9GC6uYSlGwdqk/iv9hAZscnIDcbhMpvhEATIMo9jHngUUutUpgNooz6g0LcLrz1yL9K5LHN0er0TxlCCna8smQWlpxtNsoQ+yGyc+puAWUA8Xcbn9vaz6yaUAQ8FA0R0mKBa7Tj/7gdqXjvf3Y3cjh1YdfM3YHZ5kR8eQ7LeCbVUgrLijYNM4KVZrSSiayhT1yY7kH16FfyfWoJT7v1JzQQsLhfG73mgDnht6Unk2GdfwroLPoqFD/2yZn4PnXYaW6y51Y/ErhEk9RKmyDbWL++thk3abkwk3hcbuIdnTyO50SSkBg8aAz6m3VkU2K/bERmBVRARNgQMc+XDRoHftYVI3u9F4mcvInjpGZBTaahqBeKMpvfMBdKjo6Q8MgJ7ZyeyfX3MYVLzcy9eXFsk3Qh6/sBGTYGC+n7ZwD0YDJCiUYHHKcLd1oxTHnmmtgtf/9fzsKjIw8abUElkYdgBRQKGRSeu69r5thPsbCNZkYdcyIKzKLAZHIxMAXJn6D1zgXmLjmfKk7a/Ln+iZn43nXwiG5uIWH8Qcu/ocA/PaSNJo4w6uwP7evtx7YaNzGYzm7dgzQ1XIzc0AhMBZIFDb7QAU7MPjmz6IB1w344I4T99LLhYHkFFwMhzXZh67mIY0+oYoDSsltUiiywU1FP0HD7x+MtY+o2b2HTUTBIWh5v9v/LuW/HCpWdgUNVZ39s+D1euXPW+aP53AaASc+j6W6GnkxCc7sMeZ2x8FoGxcO0+7xQgy2e1k1wsg4BPgGCYUCoAksRhs0PEVU+vBKfYGV2pE3zk9q/jstt+CkmWoY0MQ1AUnHrFNXj9+WeRXb0a5kAAcLnx3WOOxsfPPRalEo8Ln3118gA456a7GAW1dBKS082O4228T48N99zEBEimqOIXXW/LYHrt79pDhBcNjERLCCginIKIUoVgQzRZYxS9bpxVx97ynyjF4yzi0EajjpHNQQuPsHHR68Vj93wbIZ6DxJsnF4Cf1QdZKgqPApssgxgEtG+kE+B5HrmcDrvVhLzFCltJhWEYoCkKlbJWyQRiGCgTCziLBWWBR6FYhJgqQLDLcFoMJHIaioUKKMomnwMWQTrs/QsWK6z770/1RvMFC8FxPKZ//kpseuAB5MplhDUVdrMZZ119DWZ+73sTwgru4dltRF2xBt4vnA6PnmE7MlgR2JHEsrDbTMz+h57tgnTqXNanLf78JnjPXoBcvoKm+dMO6+yyu8MovrIV4gXVAoopVQDvU5BfsQbyqXPZmM1mQlG2sjHrhUtgKeaRy1Vgs1efc9ItP4AQaoLS2sr6ya4ulMNhTF22bGIAeGBeOzFGUtD9djSjWu7KlwzERRnmZ9bB9NkTYJdtCJSSGBPdyBXz7Br6G77BhammEhbc+chh836qIQqyFUY0CxACu2JGSpAgmE2wFvNIZyvQvTaEoGEkqsPhNAH+OmSKeditNqYUz7z5+ywECj5fdW5Un3R3o/niiycGgDs9NHUBnG4BMdkOQgxYJAlKOol0uoJSUEE7itgbLsHrlYBAPTONRDYDj+Jgx4tuvruWRR6Y9b3847tgEAPGaBpcvYstiJlZLAKbCORKQNApIq+WMCgo6BBL2KGLKOplmIaT8HhFlqApc+YybULvTTVBcuPGQ6pKf8/T/90oQENY9tJqju1RlCr1B/fBJfNIFQ1M8cnY/bMNoNfMNxewuWxl16iaBmEoCf/8dpx/w+2HTXr+cvN1iCer4YyAwOUxI57QYWrxw/LkKkhXn4XK4D6MWBUIgwmY2+qg7wrD6xfhljn0yR5wvaO4btt2xoDxmsKjZ5yGb8benwIcB4W7yamwKOD3CYjGqpM1tdfB88RqcFefBTKwByNydYLj49Hj2tj1bpnHbosby+544LCa/407rsfAqApzsw+2dArFF7ahdPESgOeg742C4zhYV/dAPGc2ojENXp8EhwXYM1wC1+qHO5NCPKbjqtVramW19OYt+PlZH8e34smJMYHbPS5inlqHWaYCwtYgo2wql4fLbkM6l4e+ZxTlRjfMw0lUGt0IFHPgeA5JuwukP8aun7+487BOML47jKCHRzhegaJwSGcN8HVOOBQHKqPDyClO2K1WwFSNJtlCHvZMinl/aoqptIG8rjMGcHaFmQD1ARPKgIfbAsSxP73OqDVVimRSZ5lYWnHCZVeQymVhDMTYGG30N4OCA85sGjGX67CCpy6WQ6J3AB2tdvSWRZQHE+BDHqjlMgJuD8aSCciigMZSBvvCJbTUi+woTPGh3F99Vjiq4uvbttfKajRvoABMGAPGi420xmZeWA0183krjPAQMg4XKv1RuGc0s3GawlIZHDVXTYW2dytL/Wp2kGS9TXirnEOpa98hmv4KWSKWo1oR8PpAdmzFyhO/AKJrOGvdr7HqzKvfVZVStfrCrd+cEPrT+XP0TRB9C1Tu2lsDIJQsQohUNQHX6AEX8IDs3QWP1YRijiBmLrMXIpbu0XdNVl5YHCI8x2OFDrRlk4cA9S8LpxCpe7QG5NZPfQGcIEGxVx3xgbKc9mmkOlCtvnjff0wICIe9yeNTA8Qq8hiN6lCcJpz6g4fw4q2XIZ8muOCen6P5/PPf8+EPt/lJ1umGKRNDwuPHLW/0cpqqElrXs0z1cfcvmkmKJR0BtYBEUoens8q+0bf6MGeaC0vX7+WoTKeKcyJ3vIb4/n8Ou5Bfz/CTrEbABeuR2jmIy9a/WYvDhcEhuNvb3hOA22a3ELq4cV9Cq8gUAFrZlUJu7h6/l3g9AvKKE/pAnNk/9UFhuwKHQ8HKEy6qSW66+89NIO0PBOGwC3m41UsiFitkQUB5IIYrNnQdVNbyH7P4kN+Nvzi1LmzBVLsb4u49LMzxObBcgu4kFVA0l6A5RHckD2FaAO50iuUGDgsPp1XGS/kKGotZrDzzywdt1kRR/hAG3Dx7ClF5oLI3ho52CQYIxKwJeyMaVMNAMCjA4ay+odlZVuAYTGNaowRZNyOZrbDanyrJ2Og2s0zRtzMKX2cI3O4x9psml8zyButFSyAXCix3oPlEbmoIYxt7YWLLrzaxLYgET6BuG8TOr333oLlOlhlwdx41nWgmDg6PG8uWr4QtNA13zZSgZgpsAiGLgC/uMZDsWod7P38OgrICMyEwUlkYkTT4oBPNphJWWiUYmwcwo9GKrNUFXy6DRMqAHHCgmS8hrxrgAnVI5rPM0fVt341gQETW7YPb6cJQJAKbbAHiI4gGG7B94XkfDAOWzw6QCk8QKZYhhaZBUnXs2doHoaP6cjSvapD3xVmaNK/VilyewNzQjMSOvaw6pOo6qxPqngryvnrYeiMI+WUUKmUkEzpm1MkYiZVB/roNni99DKPFPFSthKTEY0pdHZKJBEo9YdQFq/pi22AOoSYJ6z9TfX9ITYe2SWPA8mOaiGLmkU0X4RQlptm7yxJbGCWnOZyG1y1A54FQnQ3ZjAaXRcKOsgStXIZ5JAUPTaR4DSVPPY7nVIQlP4qGgXQ+C/tQCuWAwrJBr65ixGZn2kLwAj6bCYl8dYlc20yMrN6K9jYBa+A4pOjyTtudqD5HfYBgEDQUC1j6+LOsIkPb8i9eyo4X//zxqn16vXh02efg1QowcTxTgvRt8XiNcOdoDoumKRBhYt58JKrC4zHDcHqgP/k6uFPmgLz6Fvyfnoth0YGBnUNVEzt5AWLJBHxuDzsq0REMDmlYetJCqBxBxsSBlmCu+MOa94w8/xtQajelX4ZQMbRlvyBZ+9j97Nzt51Y/mRl4aQO0jjrsnH82U2yXbX+G7RQVM3T8DKMIC8wYGCkxRsRtdpQH4pBbAnDaFSjJYQbMEK0HjGZQOb4Tg39+E9rMIKTeMYROW4jAcA9WETsTTh3T5kAAAeWhWinhkpc3TC4A44qwa8bpbIF/e/IR9kAa3uiO0Eal6/rWE5liW7rqCbZT1F6p0/JHRtg145KWAnR517tnbB+79kaSzVUdYioagcsfxHifHm/cvQ4mU7UqVKlUcPZrb04OAI+fvIjQpEQSBGi6zmyeipLeoSLEFj8q5QpLWPT+GFNr1lS26hzHMlDsPBL2PLZZg1A37mVg/OHYixhAc55+BFPOWMSuHXh5A9SOOsxC1ceUshEEFRNjEJXT9NwSZBBQ7YglS7DbBURsMkJ2BVrQARk8kroOx1AKIgg+0bVtwsDg7ls0k9BdSG/fy7Ivats0IwsGTdg9pEFpq0OhVKLfMcAczsAvisw55vQye78fdTjgUBTYk1lIahH5fIXV+TSjAh4cXh6s6gFaUZ5lqn5oEQ3vYkeagNGvPsYC9azsXk9kVjpRJBPMPAezuwFpjwyHSUDFqLACDK3gnrN+68QBcOu8qUQYSiHgE5FxuNni6N9I7xALTXJLO1LZDMo7R6GH3GhTVUTpq+7BJIT2IMvtm4sxFIkTeU1FZSwDwa8gYNbRUyDodZpZNth8xiLMHx1Ety6i38qzMbp4yoS35ADrzws5WSUoWSTQUgY6509DzmZBnhioGIBTK0Mr6fjMqxNnDtwtbicJ+EVkXV7ofRG0hSSkiwZ6fW74PV6o0TiL0yYOCARE5F1eOFMJDEY06K1eLCAF9A6oaAvYgLoGaFlaSbYjawKy2Sy2kP3+o3sU7TNDKPfH4ZNExgCr1QSVSm7JgrWyjqNiGSQSJXg81fOhKS3IuW0ol3RkKgasZjPSmorL//C3iWPA/dN9JOXxwas44Y72I1Eog29pQ3chxeya1uHr60VEI2VYOpvgdbkwvHYbOqdWP1/J5AmSHj/qFCeiXTvhaA2iqOvI90cRXNyJnnyS7S6186VaCVnNgCragFgOqHfWKs6bmkJYN++c2guYU6U8zntlaMIW+m4hkrvvzONIeM028Nzbz5I6GhA3owrAwhaom/qhzK9+FueNRuCz8xjN6ehs8iCdzGGn1Y/jTEW8UZZh5IsQh1JweHnEvH7Etuxjv6N0N4ke9uWHO5/BaKKEXKMT7chix14V3V+9uTbHyU6BDwSDu06xkYZ6ESlfHbwuN/aFw1BkC6TocC28cZ1zkYjHoW6qLqaxQUT/kIqjO6zYvlODZd4UpvSomEklE8gUNZh3Rdi1nnpz7YPKOWMpcHWNyPUOINQgsu8JduULzAn2HnXBQZs0WdnfO5nALVvQQqY2NiKeiEPb0o+Ghiq1dw8VWVijcf3AWE3PHRi/Z/X+BZaeCCwLWqBt2ofGRgkBO48drMBKcO/af+xDpk/sf0c5/tptsrT/IQDc0e4kAcWEsSz9XBngOmZj8M8bsWCm/A9p8uMvu4aF0XFg6PHA/riifDcbHB+nwujAaz4wBowvgO5qpVioKbLxhXxQExkvf9HnTmYF6BAGvNfO/F8/P+lh5kgH8EMAjvQdmuz5fciAyUb4SL//hww40ndosuf3IQMmG+Ej/f4fMuBI36HJnt+HDJhshI/0+3/IgCN9hyZ7fv/vGfDfOZsE196ALzAAAAAASUVORK5CYII="},{"path":"","name":"nether_deer.png","folder":"","namespace":"","id":"3","width":64,"height":64,"uv_width":64,"uv_height":64,"particle":false,"use_as_default":false,"layers_enabled":false,"sync_to_project":"","render_mode":"default","render_sides":"auto","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"internal":true,"saved":false,"uuid":"d5ac349d-c78c-1d2f-5feb-922aaa3baf6e","source":"data:image/png;base64,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"}],"animations":[{"uuid":"48bee7e9-807c-ff4a-84f7-98b180461d39","name":"animation.deer.run","loop":"loop","override":false,"length":0.5,"snapping":24,"selected":false,"saved":true,"path":"E:\\Beautiful Artwork\\TFC Plants\\00_TFC Animals\\2022\\.Animations\\deer.animation.run.json","anim_time_update":"","blend_weight":"","start_delay":"","loop_delay":"","animators":{"e5fe8298-cea8-344f-6257-9f18adaa219e":{"name":"body","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":-5,"y":0,"z":0}],"uuid":"4b3f8e3d-fbb8-e9eb-4c74-7d8c72dd81ab","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"4d30c2c9-568b-ebdc-34ce-46f0580dcc8c","time":0.125,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"0f8305cc-eac0-487b-c625-d7bfc65b30d1","time":0.25,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"eec84de6-e883-6ff7-a039-96b0fa373f4b","time":0.375,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-5,"y":0,"z":0}],"uuid":"1b933880-8746-83f8-4b13-4ac1da32cdaf","time":0.5,"color":-1,"interpolation":"linear"},{"channel":"position","data_points":[{"x":"0","y":"0","z":"0"}],"uuid":"18a132e0-a404-226b-4fb6-36d883e77e00","time":0,"color":-1,"interpolation":"linear"},{"channel":"position","data_points":[{"x":0,"y":0,"z":0}],"uuid":"0e3b22c4-f676-9b18-c01b-7e04af337a35","time":0.5,"color":-1,"interpolation":"linear"},{"channel":"position","data_points":[{"x":0,"y":"1","z":0}],"uuid":"e5afa984-f891-3fe2-9e58-18c31bcf2802","time":0.125,"color":-1,"interpolation":"linear"},{"channel":"position","data_points":[{"x":0,"y":"1.5\n","z":0}],"uuid":"3e95165f-2f9b-cd7a-487d-f36b0d519d55","time":0.25,"color":-1,"interpolation":"linear"},{"channel":"position","data_points":[{"x":0,"y":"1","z":0}],"uuid":"4db97f4f-dbf4-72e9-7ad5-2c2fe428c2aa","time":0.375,"color":-1,"interpolation":"linear"}]},"47e29571-c3ef-b5fb-89f1-b3567476af77":{"name":"tail","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":22.5,"y":0,"z":0}],"uuid":"d2e6a862-a47c-c3c0-6e16-a0102679e06e","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":60,"y":0,"z":0}],"uuid":"65063576-3ea4-8dac-5f7b-8ccac9d4fcd1","time":0.2083,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":22.5,"y":0,"z":0}],"uuid":"5dc1a6eb-151a-b380-93d5-6776631bc4db","time":0.5,"color":-1,"interpolation":"linear"}]},"42ea09b3-02ec-2f2f-0e06-4704d0dc9e77":{"name":"tail1","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"73e5db6f-73d0-d605-6222-b730d33488e0","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-90,"y":0,"z":0}],"uuid":"b9aa9162-446c-77a8-8b3b-1478d4b8e680","time":0.25,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-2.5,"y":0,"z":0}],"uuid":"f0e329bb-7dc8-1e71-e274-e53c8efbd185","time":0.4167,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"3d3dcdae-82a5-70c8-791e-35ed6767e4b0","time":0.5,"color":-1,"interpolation":"linear"}]},"8d1fd0f9-a43f-7d42-0733-694ef49f7f1a":{"name":"head","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"728912da-742c-57c2-5e06-44d41dfa1014","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-7.5,"y":0,"z":0}],"uuid":"9d9d7103-d8cd-11b5-8d74-023d306e8555","time":0.0833,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-5,"y":0,"z":0}],"uuid":"b44719a8-2c0a-c9d0-8ade-2f33226817c1","time":0.25,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":7.5,"y":0,"z":0}],"uuid":"733baea4-792f-b3bb-737f-f0919804257f","time":0.3333,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"a2d454b7-470e-4eed-cc5d-0a4327b25e02","time":0.5,"color":-1,"interpolation":"linear"}]},"0c6317ce-4f2c-c4e4-fa04-6df0b8b050ce":{"name":"legFR","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"8bc2f8d0-0cc0-afa7-8c33-9afd7ee1da0e","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-40,"y":0,"z":0}],"uuid":"c33fd333-21df-85b7-b44c-75428531dda5","time":0.0833,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-40,"y":0,"z":0}],"uuid":"cc024600-6df1-ce87-a8a1-91daa27d4411","time":0.2083,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":25.5,"y":0,"z":0}],"uuid":"5bc3cb05-ea1d-b00a-76e4-dd2c3ba5323f","time":0.375,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":25.5,"y":0,"z":0}],"uuid":"944941ba-e4c6-d4b0-d9be-d0647aaa518b","time":0.4167,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"e32e117b-9eb1-022d-26b1-fccfececb92b","time":0.5,"color":-1,"interpolation":"linear"}]},"ddee54d8-11f9-19b6-df85-558d120f17f5":{"name":"legFL","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"aaf04897-db62-8d80-10cf-6ffa28e86616","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-40,"y":0,"z":0}],"uuid":"42a80caa-bc43-a5eb-a3b0-d14c533650c1","time":0.0833,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-40,"y":0,"z":0}],"uuid":"8dee62ca-9564-f4c8-1a7c-6ef0c0886eb8","time":0.2083,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":25.5,"y":0,"z":0}],"uuid":"b32f3466-dbd4-bc15-d85f-3d50b786d039","time":0.375,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":25.5,"y":0,"z":0}],"uuid":"fbd44d9b-e9a9-5e73-e012-10d726f02fe9","time":0.4167,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"a03ee944-1177-708d-ffb7-ff92926a86d9","time":0.5,"color":-1,"interpolation":"linear"}]},"d7345c05-fc55-9b1f-e0b7-2a46bb6f170f":{"name":"legBL","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"8a702c3a-0c24-009f-027a-48b062d3e097","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":45,"y":0,"z":0}],"uuid":"6a3d18c5-dfe5-03f7-cd3f-36d9564437ba","time":0.0833,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":45,"y":0,"z":0}],"uuid":"cbfb1f0a-f874-320b-a837-ec2bc202c594","time":0.2083,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":45,"y":0,"z":0}],"uuid":"6153c497-4978-314e-b3dd-30e6dddb9e58","time":0.25,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-30,"y":0,"z":0}],"uuid":"9a9e33d3-adea-839e-6a2a-9d8b8e210bc0","time":0.375,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"b0eb0749-03df-b5c3-d632-819ff8429f3e","time":0.5,"color":-1,"interpolation":"linear"}]},"525b418e-bc74-7cc7-e6d9-525257dfe8a8":{"name":"legBR","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"337292f1-3a5d-0efa-f965-9435f7360600","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":45,"y":0,"z":0}],"uuid":"905d8799-5f31-be95-a78e-9d914ea2afa6","time":0.0833,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":45,"y":0,"z":0}],"uuid":"c53205f2-fb29-6727-56ec-2f56dbb84664","time":0.2083,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":45,"y":0,"z":0}],"uuid":"27c6dfa6-3cb7-3a2f-e6fe-94214eaf7619","time":0.25,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-30,"y":0,"z":0}],"uuid":"95b87560-1a3c-6ff2-77ec-75b7067fec0f","time":0.375,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"68f44c20-0a1a-8d30-2d71-1906c2749996","time":0.5,"color":-1,"interpolation":"linear"}]},"e4f85fc0-8cc0-44df-017a-4e18ef902383":{"name":"earR","type":"bone","keyframes":[{"channel":"scale","data_points":[{"x":1,"y":1.1,"z":1}],"uuid":"270e51cf-675e-1eda-22c6-4d3c21132393","time":0,"color":-1,"uniform":true,"interpolation":"linear"}]},"8cc81a55-f0f2-12ea-f6d5-0930fc3dff4e":{"name":"neck","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"0a43edb7-cbbf-1d27-b2c5-4a649499dfa0","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":7.5,"y":0,"z":0}],"uuid":"c843648d-e90e-a4fd-91ea-9ce12d5ccbfe","time":0.0833,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"8899652c-f420-647d-a51b-e19feb7d76c1","time":0.25,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-7.5,"y":0,"z":0}],"uuid":"5908efaa-049c-531c-fc5f-c31e2670a6e7","time":0.3333,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"335a55fe-a7bb-9bdc-6ba6-edccb6dc14ed","time":0.5,"color":-1,"interpolation":"linear"}]}}},{"uuid":"9642971a-ff86-6012-98bc-ac4c0a0d512b","name":"animation.deer.walk","loop":"loop","override":false,"length":1,"snapping":24,"selected":false,"saved":true,"path":"E:\\Beautiful Artwork\\TFC Plants\\00_TFC Animals\\2022\\.Animations\\deer.animation.walk.json","anim_time_update":"","blend_weight":"","start_delay":"","loop_delay":"","animators":{"8cc81a55-f0f2-12ea-f6d5-0930fc3dff4e":{"name":"neck","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"42418c28-3469-c378-73c6-a5982532a5ac","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":5,"y":0,"z":0}],"uuid":"53ef2f8e-72e7-49c1-6041-46a87a7eb8a4","time":0.2917,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-1,"y":0,"z":0}],"uuid":"43bb92d9-1016-7b1c-9c0e-567135a34a01","time":0.8333,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"e69adc1a-56f9-37be-15ce-c615e734712f","time":1,"color":-1,"interpolation":"linear"}]},"8d1fd0f9-a43f-7d42-0733-694ef49f7f1a":{"name":"head","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"2d4b6bc6-ec2e-e149-6d38-5c2382d9ec46","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-5,"y":0,"z":0}],"uuid":"f5b1b39a-27e9-6b47-6c00-afbc7c868e41","time":0.3333,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":1,"y":0,"z":0}],"uuid":"4ba833e2-cd8d-60b1-8626-00689348b777","time":0.8333,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"7d5d4b0c-73bb-7a80-5ed8-382ab21d72a4","time":1,"color":-1,"interpolation":"linear"}]},"47e29571-c3ef-b5fb-89f1-b3567476af77":{"name":"tail","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"e86d2dbf-74b4-69e8-e3d6-fea5f6297ccd","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":10,"y":0,"z":0}],"uuid":"5f2d7b99-46bb-826c-36f0-a33745541f77","time":0.3333,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":3,"y":0,"z":0}],"uuid":"d0d7e1e9-82cd-40b1-92ea-fcf37a1422dc","time":0.625,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"cf2c92b5-7204-b95b-23d1-849d2da23f7f","time":1,"color":-1,"interpolation":"linear"}]},"525b418e-bc74-7cc7-e6d9-525257dfe8a8":{"name":"legBR","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"3cf2f266-9572-a06a-aebc-ccb5061a04fb","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":22.5,"y":0,"z":0}],"uuid":"e16c47d7-c033-60fd-0621-5cf80dd711c2","time":0.4167,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-27.5,"y":0,"z":0}],"uuid":"d9e65e17-1111-da64-57e7-e2349641264f","time":0.75,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"97e84dbe-b763-3d5f-c467-687d0a901676","time":1,"color":-1,"interpolation":"linear"}]},"d7345c05-fc55-9b1f-e0b7-2a46bb6f170f":{"name":"legBL","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"ed1da32f-eef7-50c5-4d15-d935655efdf1","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-27.5,"y":0,"z":0}],"uuid":"053e2e87-aabe-7580-4421-2319a88dc64f","time":0.1667,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":22.5,"y":0,"z":0}],"uuid":"a85f7d64-8498-0b0d-f21d-2fff429201e8","time":0.8333,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"eeabf408-9241-d041-2820-01235825b217","time":1,"color":-1,"interpolation":"linear"}]},"0c6317ce-4f2c-c4e4-fa04-6df0b8b050ce":{"name":"legFR","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"42d3d0fd-8e50-d8b8-a30f-f84d0b69ca48","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-27.5,"y":0,"z":0}],"uuid":"db320c04-70aa-16d3-158e-8055da1c5b9e","time":0.1667,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":22.5,"y":0,"z":0}],"uuid":"ab100968-40f0-beab-fdf5-628c5055387c","time":0.7917,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"3b18db61-3a06-d9a1-9cf8-9c73fe64e225","time":1,"color":-1,"interpolation":"linear"}]},"ddee54d8-11f9-19b6-df85-558d120f17f5":{"name":"legFL","type":"bone","keyframes":[{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"5f10aa6f-4b42-1714-38db-14baee2d9c63","time":0,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":22.5,"y":0,"z":0}],"uuid":"355a6a77-9e4b-22e5-a227-cf647807f322","time":0.4167,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":-27.5,"y":0,"z":0}],"uuid":"429f3b6f-7bfb-d306-01dd-5cfdfdc6ae02","time":0.75,"color":-1,"interpolation":"linear"},{"channel":"rotation","data_points":[{"x":0,"y":0,"z":0}],"uuid":"ae149a75-25d3-88fc-1dd3-0ae5aaeb7a31","time":1,"color":-1,"interpolation":"linear"}]}}}]} \ No newline at end of file diff --git a/resources/patchouli.py b/resources/patchouli.py new file mode 100644 index 0000000..cd7967b --- /dev/null +++ b/resources/patchouli.py @@ -0,0 +1,521 @@ +import json +import os +import re +from typing import NamedTuple, Tuple, List, Mapping, Set, Any, Dict + +from mcresources import ResourceManager, utils +from mcresources.type_definitions import JsonObject, ResourceLocation, ResourceIdentifier + +from constants import ROCK_CATEGORIES, lang +from i18n import I18n + +NON_TEXT_FIRST_PAGE = 'non_text_first_page' +PAGE_BREAK = 'page_break' +EMPTY_LAST_PAGE = 'empty_last_page' +TABLE_PAGE = 'table' +TABLE_PAGE_SMALL = 'table_small' +TABLE_KEYS = {'strings': '#strings', 'columns': '#columns', 'first_column_width': '#first_column_width', 'column_width': '#column_width', 'row_height': '#row_height', 'left_buffer': '#left_buffer', 'top_buffer': '#top_buffer', 'title': '#title', 'legend': '#legend', 'draw_background': '#draw_background'} + + +class Component(NamedTuple): + type: str + x: int + y: int + data: JsonObject + + +class SubstitutionStr(NamedTuple): + value: str + params: Tuple[Any, ...] + + def __str__(self) -> str: return self.value + + +def defer(text_contents: str, *params) -> SubstitutionStr: + return SubstitutionStr(text_contents, params) + + +TranslatableStr = str | SubstitutionStr + + +class Page(NamedTuple): + type: str + data: JsonObject + custom: bool # If this page is a custom template. + anchor_id: str | None # Anchor for referencing from other pages + link_ids: List[str] # Items that are linked to this page + translation_keys: Tuple[str, ...] # Keys into 'data' that need to be passed through the Translation + + def anchor(self, anchor_id: str) -> 'Page': + return Page(self.type, self.data, self.custom, anchor_id, self.link_ids, self.translation_keys) + + def link(self, *link_ids: str) -> 'Page': + for link_id in link_ids: + if link_id.startswith('#'): # Patchouli format for linking tags + link_id = 'tag:' + link_id[1:] + self.link_ids.append(link_id) + return self + + def translate(self, i18n: I18n): + for key in self.translation_keys: + if key in self.data and self.data[key] is not None: + value = self.data[key] + if isinstance(value, SubstitutionStr): + try: + self.data[key] = i18n.translate(value.value).format(*value.params) + except IndexError as e: + raise ValueError('Error performing replacement for lang %s\n \'%s\' -> \'%s\'' % (i18n.lang, value.value, i18n.translate(value.value))) from e + else: + self.data[key] = i18n.translate(value) + + def iter_all_text(self): + for key in self.translation_keys: + if key in self.data and self.data[key] is not None: + yield str(self.data[key]) + + +class Entry(NamedTuple): + entry_id: str + name: str + icon: str + pages: Tuple[Page] + advancement: str | None + + +class Category(NamedTuple): + category_id: str + name: str + description: str + icon: str + parent: str | None + is_sorted: bool + entries: Tuple[Entry, ...] + + +class Book: + + def __init__(self, rm: ResourceManager, root_name: str, macros: JsonObject, i18n: I18n, local_instance: bool, reverse_translate: bool): + self.rm: ResourceManager = rm + self.root_name = root_name + self.category_count = 10 + self.i18n = i18n + self.local_instance = local_instance + self.reverse_translate = reverse_translate + + self.categories: List[Category] = [] + self.macros = macros + + def template(self, template_id: str, *components: Component): + if self.i18n.is_root(): # Templates are only required in root + self.rm.data(('patchouli_books', self.root_name, self.i18n.lang, 'templates', template_id), { + 'components': [{ + 'type': c.type, 'x': c.x, 'y': c.y, **c.data + } for c in components] + }, root_domain='assets') + + def category(self, category_id: str, name: str, description: str, icon: str, parent: str | None = None, is_sorted: bool = False, entries: Tuple[Entry, ...] = ()): + """ + :param category_id: The id of this category. + :param name: The name of this category. + :param description: The description for this category. This displays in the category's main page, and can be formatted. + :param icon: The icon for this category. This can either be an ItemStack String, if you want an item to be the icon, or a resource location pointing to a square texture. If you want to use a resource location, make sure to end it with .png. + :param parent: The parent category to this one. If this is a sub-category, simply put the name of the category this is a child to here. If not, don't define it. This should be fully-qualified and of the form domain:name where domain is the same as the domain of your Book ID. + :param is_sorted: If the entries within this category are sorted + :param entries: A list of entries (call entry() for each) + + https://vazkiimods.github.io/Patchouli/docs/reference/category-json/ + """ + self.categories.append(Category(category_id, name, description, icon, parent, is_sorted, entries)) + + def build(self): + # Only generate the book.json if we're in the root language + # if self.i18n.lang == 'en_us': + # self.rm.data(('patchouli_books', self.root_name, 'book'), { + # 'name': 'tfc.field_guide.book_name', + # 'landing_text': 'tfc.field_guide.book_landing_text', + # 'subtitle': '${version}', + # # Even though we don't use the book item, we still need patchy to make a book item for us, as it controls the title + # # If neither we nor patchy make a book item, this will show up as 'Air'. So we make one to allow the title to work properly. + # 'dont_generate_book': False, + # 'show_progress': False, + # 'macros': self.macros, + # 'use_resource_pack': not self.local_instance, # Required since 1.20 for mod books + # }) + + # Find all valid link targets + link_targets = {} + for c in self.categories: + for e in c.entries: + link_targets['%s/%s' % (c.category_id, e.entry_id)] = {p.anchor_id for p in e.pages if p.anchor_id is not None} + + for c in self.categories: + self.build_category(link_targets, c.category_id, c.name, c.description, c.icon, c.parent, c.is_sorted, c.entries) + + def build_category(self, link_targets: Mapping[str, Set[str]], category_id: str, name: str, description: str, icon: str, parent: str | None, is_sorted: bool, entries: Tuple[Entry, ...]): + if self.reverse_translate: + data = self.load_data(('patchouli_books', self.root_name, self.i18n.lang, 'categories', category_id)) + self.i18n.after[name] = data['name'] + self.i18n.after[description] = data['description'] + else: + self.rm.data(('patchouli_books', self.root_name, self.i18n.lang, 'categories', category_id), { + 'name': self.i18n.translate(name), + 'description': self.i18n.translate(description), + 'icon': icon, + 'parent': parent, + 'sortnum': self.category_count, + }, root_domain='assets') + self.category_count += 1 + + category_res: ResourceLocation = utils.resource_location(self.rm.domain, category_id) + + assert not isinstance(entries, Entry), 'One entry in singleton entries, did you forget a comma after entry(), ?\n at: %s' % str(entries) + for i, e in enumerate(entries): + assert not isinstance(e.pages, Page), 'One entry in singleton pages, did you forget a comma after page(), ?\n at: %s' % str(e.pages) + assert len(e.pages) > 0, 'Entry must have at least one page!\n at: %s' % str(e.name) + + # First page must be either text or a marker that it's not + if e.pages[0].type == NON_TEXT_FIRST_PAGE: + pages = e.pages[1:] + else: + assert e.pages[0].type == 'patchouli:text', 'An entry starts with a non text() page: Patchouli uses a standard title page with text() pages when used first for each entry which should be kept.\nIf this is intentional, add a non_text_first_page() as the first page in this entry!\n at: entry \'%s\'' % str(e.name) + pages = e.pages + + allow_empty_last_page = False + real_pages = [] + for j, p in enumerate(pages): + if p.type == PAGE_BREAK: + assert len(real_pages) % 2 == 0, 'A page_break() required that the next entry must start on a new page, a page has been added that breaks this!\n at: entry \'%s\', page break at index %d' % (str(e.name), j) + elif p.type == EMPTY_LAST_PAGE: + allow_empty_last_page = True + assert j == len(pages) - 1, 'An empty_last_page() was used but it was not the last page?\n at: %s' % str(e.name) + elif p.type == TABLE_PAGE or p.type == TABLE_PAGE_SMALL: + assert len(real_pages) % 2 == 0, 'A table() requires that it starts on a new page!' + real_pages.append(p) + real_pages.append(blank()) # Tables take up two pages + else: + real_pages.append(p) + + assert allow_empty_last_page or len(real_pages) % 2 == 0, 'An entry has an odd number of pages: this leaves a implicit empty() page at the end.\nIf this is intentional, add an empty_last_page() as the last page in this entry!\n at: entry \'%s\'' % str(e.name) + + extra_recipe_mappings = {} + for index, p in enumerate(real_pages): + for link in p.link_ids: + extra_recipe_mappings[link] = index + if not extra_recipe_mappings: # Exclude if there's nothing here + extra_recipe_mappings = None + + # Validate no duplicate anchors or links + seen_anchors = set() + seen_links = set() + for p in real_pages: + if p.anchor_id: + assert p.anchor_id not in seen_anchors, 'Duplicate anchor "%s" on page %s' % (p.anchor_id, p) + seen_anchors.add(p.anchor_id) + for link in p.link_ids: + assert link not in seen_links, 'Duplicate link "%s" on page %s' % (link, p) + seen_links.add(link) + + # Validate all internal links of the form $(l:...) + for p in real_pages: + for page_text in p.iter_all_text(): + for match in re.finditer(r'\$\(l:([^)]*)\)', page_text): + key = match.group(1) + if key.startswith('http'): + continue # Don't validate external links + if '#' in key: + target, anchor = key.split('#') + else: + target, anchor = key, None + assert (target in link_targets or 'mechanics' in target or 'the_world' in target), 'Link target \'%s\' not found for link \'%s\'\n at page: %s\n at entry: \'%s\'' % (target, key, p, e.entry_id) + if anchor is not None and target in link_targets: + assert anchor in link_targets[target], 'Link anchor \'%s\' not found for link \'%s\'\n at page: %s\n at entry: \'%s\'' % (anchor, key, p, e.entry_id) + + # Separately translate each page + if self.reverse_translate: + rev_entry = self.load_data(('patchouli_books', self.root_name, self.i18n.lang, 'entries', category_res.path, e.entry_id)) + if rev_entry: + rev_pages = rev_entry['pages'] + for p, rp in zip(real_pages, rev_pages): + for key in p.translation_keys: + if key in p.data and p.data[key] is not None and key in rp: + self.i18n.after[str(p.data[key])] = rp[key] + + self.i18n.after[e.name] = rev_entry['name'] + else: + print('Warning: missing book entry: %s/%s' % (category_res.path, e.entry_id)) + continue + + entry_name = self.i18n.translate(e.name) + for p in real_pages: + p.translate(self.i18n) + + self.rm.data(('patchouli_books', self.root_name, self.i18n.lang, 'entries', category_res.path, e.entry_id), { + 'name': entry_name, + 'category': self.prefix(category_res.path), + 'icon': e.icon, + 'pages': [{ + 'type': self.prefix(p.type) if p.custom else p.type, + 'anchor': p.anchor_id, + **p.data + } for p in real_pages], + 'advancement': e.advancement, + 'read_by_default': True, + 'sortnum': i if is_sorted else None, + 'extra_recipe_mappings': extra_recipe_mappings + }, root_domain='assets') + + def prefix(self, path: str) -> str: + """ In a local instance, domains are all under patchouli, otherwise under tfc """ + return ('patchouli' if self.local_instance else 'tfc') + ':' + path + + def load_data(self, name_parts: ResourceIdentifier) -> JsonObject: + res = utils.resource_location(self.rm.domain, name_parts) + path = os.path.join(*self.rm.resource_dir, 'assets', res.domain, res.path) + '.json' + if os.path.isfile(path): + # if 'ja_jp' in path: + # js = None + # with open(path, 'r', encoding='utf-8-sig') as f: + # js = json.load(f) + # if js is not None: + # print('Rewriting ' + path) + # with open(path, 'w', encoding='utf-8') as file: + # json.dump(js, file, indent=2, ensure_ascii=False) + # return js + # else: + with open(path, 'r', encoding='utf-8') as f: + return json.load(f) + + +def entry(entry_id: str, name: str, icon: str, advancement: str | None = None, pages: Tuple[Page, ...] = ()) -> Entry: + """ + :param entry_id: The id of this entry. + :param name: The name of this entry. + :param icon: The icon for this entry. This can either be an ItemStack String, if you want an item to be the icon, or a resource location pointing to a square texture. If you want to use a resource location, make sure to end it with .png + :param advancement: The name of the advancement you want this entry to be locked behind. See Locking Content with Advancements for more info on locking content. + :param pages: The array of pages for this entry. + + https://vazkiimods.github.io/Patchouli/docs/reference/entry-json/ + """ + if icon.startswith('tfc:food/'): # Food items decay - this is a stupid hack to just replace them with their .png image, so they don't! Wizard! + icon = icon.replace('tfc:', 'tfc:textures/item/') + '.png' + # This is a heuristic, it is not accurate (as crafting recipes also generate ctrl-links). But it is useful as a start + # requires `import warnings` + # if all(not p.link_ids for p in pages): + # warnings.warn('Entry \'%s\' does not have any .link()s' % entry_id, stacklevel=2) + return Entry(entry_id, name, icon, pages, advancement) + + +def text(text_contents: TranslatableStr, title: TranslatableStr | None = None) -> Page: + """ + Text pages should always be the first page in any entry. If a text page is the first page in an entry, it'll display the header you see in the left page. For all other pages, it'll display as you can see in the right one. + :param text_contents: The text to display on this page. This text can be formatted. + :param title An optional title to display at the top of the page. If you set this, the rest of the text will be shifted down a bit. You can't use "title" in the first page of an entry. + :return: + """ + return page('patchouli:text', {'text': text_contents, 'title': title}, translation_keys=('text', 'title')) + + +def image(*images: str, text_contents: TranslatableStr | None = None, title: TranslatableStr = None, border: bool = True) -> Page: + """ + :param images: An array with images to display. Images should be in resource location format. For example, the value botania:textures/gui/entries/banners.png will point to /assets/botania/textures/gui/entries/banners.png in the resource pack. For best results, make your image file 256 by 256, but only place content in the upper left 200 by 200 area. This area is then rendered at a 0.5x scale compared to the rest of the book in pixel size. + If there's more than one image in this array, arrow buttons are shown like in the picture, allowing the viewer to switch between images. + :param text_contents: The text to display on this page, under the image. This text can be formatted. + :param title: The title of the page, shown above the image. + :param border: Defaults to false. Set to true if you want the image to be bordered, like in the picture. It's suggested that border is set to true for images that use the entire canvas, whereas images that don't touch the corners shouldn't have it. + """ + assert all(re.match('[a-z_/.]+', i) for i in images), ('Invalid images: %s, did you mean to declare one as \'text_contents=\' ?' % str(images)) + return page('patchouli:image', {'images': images, 'text': text_contents, 'title': title, 'border': border}, translation_keys=('text', 'title')) + + +def entity(entity_type: str, text_contents: TranslatableStr = None, title: TranslatableStr = None, scale: float = 0.7, offset: float = None, rotate: bool = None, default_rotation: float = None) -> Page: + """ + :param entity_type: The entity type + :param text_contents: The text to display under the entity display + :param title: The title of the page + :param scale: The scale of the entity. Defaults to 1 + :param offset: The vertical offset of the entity renderer. Defaults to 0 + :param rotate: Whether the entity should rotate in the view. Defaults to true. + :param default_rotation: The rotation at which the entity is displayed. Only used if rotate is False. + """ + if title == '': + title = ' ' # Patchy will draw a title on name == null || name.isEmpty() which is dumb + return page('patchouli:entity', {'entity': entity_type, 'scale': scale, 'offset': offset, 'rotate': rotate, 'default_rotation': default_rotation, 'name': title, 'text': text_contents}, translation_keys=('name', 'text')) + + +def crafting(first_recipe: str, second_recipe: str | None = None, title: TranslatableStr | None = None, text_contents: TranslatableStr | None = None) -> Page: + """ + :param first_recipe: The ID of the first recipe you want to show. + :param second_recipe: The ID of the second recipe you want to show. Displaying two recipes is optional. + :param title: The title of the page, to be displayed above both recipes. This is optional, but if you include it, only this title will be displayed, rather than the names of both recipe output items. + :param text_contents: The text to display on this page, under the recipes. This text can be formatted. + Note: the text will not display if there are two recipes with two different outputs, and "title" is not set. This is the case of the image displayed, in which both recipes have the output names displayed, and there's no space for text. + """ + if second_recipe is not None: + assert ' ' not in second_recipe + return page('patchouli:crafting', {'recipe': first_recipe, 'recipe2': second_recipe, 'title': title, 'text': text_contents}, translation_keys=('text', 'title')) + + +def item_spotlight(item: str | Tuple[str, ...], title: TranslatableStr | None = None, link_recipe: bool = False, text_contents: TranslatableStr | None = None) -> Page: + """ + :param item: An ItemStack String representing the item to be spotlighted. + :param title: A custom title to show instead on top of the item. If this is empty or not defined, it'll use the item's name instead. + :param link_recipe: Defaults to false. Set this to true to mark this spotlight page as the "recipe page" for the item being spotlighted. If you do so, when looking at pages that display the item, you can shift-click the item to be taken to this page. Highly recommended if the spotlight page has instructions on how to create an item by non-conventional means. + :param text_contents: The text to display on this page, under the item. This text can be formatted. + """ + if isinstance(item, tuple): + assert all(re.match('[a-z]+:[a-z_/]+', i) for i in item), 'item_spotlight() item may be a tuple of item names, or a tag, specified with #foo:bar syntax' + item = ','.join(item) + elif isinstance(item, str): + assert re.match('#?[a-z]+:[a-z/_]+', item), 'item_spotlight() item may be a tuple of item names, or a tag, specified with #foo:bar syntax' + if item.startswith('#'): # Patchy format for tags + item = 'tag:' + item[1:] + return page('patchouli:spotlight', {'item': item, 'title': title, 'link_recipes': link_recipe, 'text': text_contents}, translation_keys=('title', 'text')) + + +def block_spotlight(title: TranslatableStr, text_content: TranslatableStr, block: str, lower: str | None = None) -> Page: + """ A shortcut for making a single block multiblock that is meant to act the same as item_spotlight() but for blocks """ + return multiblock(title, text_content, False, pattern=(('X',), ('0',)), mapping={'X': block, '0': lower}) + + +def two_tall_block_spotlight(title: TranslatableStr, text_content: TranslatableStr, lower: str, upper: str) -> Page: + """ A shortcut for making a single block multiblock for a double tall block, such as crops or tall grass """ + return multiblock(title, text_content, False, pattern=(('X',), ('Y',), ('0',)), mapping={'X': upper, 'Y': lower}) + + +def multiblock(title: TranslatableStr = '', text_content: TranslatableStr = '', enable_visualize: bool = False, pattern: Tuple[Tuple[str, ...], ...] | None = None, mapping: Mapping[str, str] | None = None, offset: Tuple[int, int, int] | None = None, multiblock_id: str | None = None) -> Page: + """ + Page type: "patchouli:multiblock" + + :param title: The name of the multiblock you're displaying. Shows as a header above the multiblock display. + :param text_content: The text to display on this page, under the multiblock. This text can be formatted. + :param enable_visualize: Set this to false to disable the "Visualize" button. + :param pattern: Terse explanation of the format: the pattern attribute is an array of array of strings. It is indexed in the following order: y (top to bottom), x (west to east), then z (north to south). + :param mapping: Patchouli already provides built in characters for Air and (Any Block), which are respectively a space, and an underscore, so we don't have to account for those. Patchouli uses the same vanilla logic to parse blockstate predicate as, for example, the /execute if block ~ ~ ~ command. This means you can use block ID's, tags, as well as specify blockstate properties you want to constraint. Therefore, we have: + :param offset: An int array of 3 values ([X, Y, Z]) to offset the multiblock relative to its center. + :param multiblock_id: For modders only. The ID of the multiblock you want to display. + """ + data = {'name': title, 'text': text_content, 'enable_visualize': enable_visualize} + if multiblock_id is not None: + return page('patchouli:multiblock', {'multiblock_id': multiblock_id, **data}, translation_keys=('name', 'text')) + elif pattern is not None and mapping is not None: + return page('patchouli:multiblock', {'multiblock': { + 'pattern': pattern, + 'mapping': mapping, + 'offset': offset, + }, **data}, translation_keys=('name', 'text')) + else: + raise ValueError('multiblock page must have either \'multiblock\' or \'pattern\' and \'mapping\' entries') + + +def empty() -> Page: + return page('patchouli:empty', {}) + + +def blank() -> Page: + return page('patchouli:empty', {'draw_filler': False}) + + +# ============== +# TFC Page Types +# ============== + + +def multimultiblock(text_content: TranslatableStr, *pages) -> Page: + return page('multimultiblock', {'text': text_content, 'multiblocks': [p.data['multiblock'] if 'multiblock' in p.data else p.data['multiblock_id'] for p in pages]}, custom=True, translation_keys=('text',)) + + +def knapping(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('knapping_recipe', recipe, text_content) +def heat_recipe(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('heat_recipe', recipe, text_content) +def quern_recipe(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('quern_recipe', recipe, text_content) +def anvil_recipe(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('anvil_recipe', recipe, text_content) +def welding_recipe(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('welding_recipe', recipe, text_content) +def sealed_barrel_recipe(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('sealed_barrel_recipe', recipe, text_content) +def instant_barrel_recipe(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('instant_barrel_recipe', recipe, text_content) +def loom_recipe(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('loom_recipe', recipe, text_content) +def glassworking_recipe(recipe: str, text_content: TranslatableStr) -> Page: return recipe_page('glassworking_recipe', recipe, text_content) + +def rock_knapping_typical(recipe_with_category_format: str, text_content: TranslatableStr) -> Page: + return page('rock_knapping_recipe', {'recipes': [recipe_with_category_format % c for c in ROCK_CATEGORIES], 'text': text_content}, custom=True, translation_keys=('text',)) + + +def alloy_recipe(title: str, alloy_name: str, text_content: TranslatableStr) -> Page: + # Components can be copied from alloy_recipe() declarations in + alloy_components = ALLOYS[alloy_name] + recipe = ''.join(['$(li)%d - %d %% : $(thing)%s$()' % (round(100 * lo), round(100 * hi), lang(alloy)) for (alloy, lo, hi) in alloy_components]) + return item_spotlight('tfc:metal/ingot/%s' % alloy_name, title, False, '$(br)$(bold)Requirements:$()$(br)' + recipe + '$(br2)' + text_content) + + +def fertilizer(item: str, text_contents: TranslatableStr, n: float = 0, p: float = 0, k: float = 0) -> Page: + text_contents += ' $(br)' + if n > 0: + text_contents += '$(li)$(b)Nitrogen: %d$()' % (n * 100) + if p > 0: + text_contents += '$(li)$(6)Phosphorous: %d$()' % (p * 100) + if k > 0: + text_contents += '$(li)$(d)Potassium: %d$()' % (k * 100) + return item_spotlight(item, text_contents=text_contents) + + +def non_text_first_page() -> Page: + return page(NON_TEXT_FIRST_PAGE, {}) + + +def page_break() -> Page: + return page(PAGE_BREAK, {}) + + +def empty_last_page() -> Page: + return page(EMPTY_LAST_PAGE, {}) + + +def recipe_page(recipe_type: str, recipe: str, text_content: TranslatableStr) -> Page: + return page(recipe_type, {'recipe': recipe, 'text': text_content}, custom=True, translation_keys=('text',)) + + +def table(strings: List[str | Dict], text_content: TranslatableStr, title: TranslatableStr, keywords: Dict[str, Any], legend: List[Dict[str, Any]], columns: int, first_column_width: int, column_width: int, row_height: int, left_buffer: int, top_buffer: int, draw_background: bool = True, small: bool = False) -> Page: + fixed_strings = [] + for string in strings: + fixed_str = string + if keywords: + for k, v in keywords.items(): + if k == string: + fixed_str = v + if isinstance(fixed_str, str): + fixed_strings.append({'text': fixed_str}) + else: + fixed_strings.append(fixed_str) + return page(TABLE_PAGE_SMALL if small else TABLE_PAGE, { + 'strings': fixed_strings, + 'text': text_content, + 'title': title, + 'legend': legend, + 'columns': columns, + 'first_column_width': first_column_width, + 'column_width': column_width, + 'row_height': row_height, + 'left_buffer': left_buffer, + 'top_buffer': top_buffer, + 'draw_background': draw_background + }, custom=True, translation_keys=('text', 'title')) + + +def page(page_type: str, page_data: JsonObject, custom: bool = False, translation_keys: Tuple[str, ...] = ()) -> Page: + return Page(page_type, page_data, custom, None, [], translation_keys) + + +# Components + +def text_component(x: int, y: int) -> Component: + return Component('patchouli:text', x, y, {'text': '#text'}) + + +def header_component(x: int, y: int) -> Component: + return Component('patchouli:header', x, y, {'text': '#header'}) + + +def seperator_component(x: int, y: int) -> Component: + return Component('patchouli:separator', x, y, {}) + + +def custom_component(x: int, y: int, class_name: str, data: JsonObject) -> Component: + return Component('patchouli:custom', x, y, {'class': 'net.dries007.tfc.compat.patchouli.component.' + class_name, **data}) diff --git a/src/main/java/com/eerussianguy/beneath/client/ClientModEvents.java b/src/main/java/com/eerussianguy/beneath/client/ClientModEvents.java index 3b893f9..7b27801 100644 --- a/src/main/java/com/eerussianguy/beneath/client/ClientModEvents.java +++ b/src/main/java/com/eerussianguy/beneath/client/ClientModEvents.java @@ -2,6 +2,7 @@ import java.util.stream.Stream; import com.eerussianguy.beneath.Beneath; +import com.eerussianguy.beneath.client.models.RedElkModel; import com.eerussianguy.beneath.client.render.BeneathHangingSignRenderer; import com.eerussianguy.beneath.client.render.BeneathSignRenderer; import com.eerussianguy.beneath.client.render.HellforgeRenderer; @@ -34,7 +35,6 @@ import net.minecraftforge.registries.RegistryObject; import net.dries007.tfc.client.RenderHelpers; -import net.dries007.tfc.client.model.entity.DeerModel; import net.dries007.tfc.client.particle.GlintParticleProvider; import net.dries007.tfc.client.render.entity.SimpleMobRenderer; import net.dries007.tfc.client.render.entity.TFCBoatRenderer; @@ -90,10 +90,12 @@ private static void setup(FMLClientSetupEvent event) ItemBlockRenderTypes.setRenderLayer(BeneathBlocks.NETHER_PEBBLE.get(), cutout); ItemBlockRenderTypes.setRenderLayer(BeneathBlocks.BLACKSTONE_PEBBLE.get(), cutout); ItemBlockRenderTypes.setRenderLayer(BeneathBlocks.BLACKSTONE_AQUEDUCT.get(), cutout); + ItemBlockRenderTypes.setRenderLayer(BeneathBlocks.UNPOSTER.get(), cutout); } - private static final ResourceLocation RED_ELK_LOCATION = Beneath.identifier("textures/entity/red_elk.png"); + private static final ResourceLocation RED_ELK_LOCATION = Beneath.identifier("textures/entity/nether_deer.png"); + private static final ResourceLocation RED_ELK_F_LOCATION = Beneath.identifier("textures/entity/nether_deer_fawn.png"); private static void onEntityRenderers(EntityRenderersEvent.RegisterRenderers event) { @@ -103,7 +105,7 @@ private static void onEntityRenderers(EntityRenderersEvent.RegisterRenderers eve event.registerEntityRenderer(BeneathEntities.CHEST_BOATS.get(wood).get(), ctx -> new TFCChestBoatRenderer(ctx, wood.getSerializedName())); } - event.registerEntityRenderer(BeneathEntities.RED_ELK.get(), ctx -> new SimpleMobRenderer.Builder<>(ctx, DeerModel::new, "red_elk").shadow(0.6f).texture(p -> RED_ELK_LOCATION).build()); + event.registerEntityRenderer(BeneathEntities.RED_ELK.get(), ctx -> new SimpleMobRenderer.Builder<>(ctx, RedElkModel::new, "red_elk").shadow(0.6f).texture(p -> p.isMale() ? RED_ELK_LOCATION : RED_ELK_F_LOCATION).build()); event.registerBlockEntityRenderer(BeneathBlockEntities.HELLFORGE.get(), ctx -> new HellforgeRenderer()); event.registerBlockEntityRenderer(BeneathBlockEntities.SIGN.get(), BeneathSignRenderer::new); @@ -123,7 +125,7 @@ private static void onLayers(EntityRenderersEvent.RegisterLayerDefinitions event event.registerLayerDefinition(RenderHelpers.modelIdentifier("sign/" + wood.getSerializedName()), () -> signLayer); } - event.registerLayerDefinition(RenderHelpers.modelIdentifier("red_elk"), DeerModel::createBodyLayer); + event.registerLayerDefinition(RenderHelpers.modelIdentifier("red_elk"), RedElkModel::createBodyLayer); } private static void onParticlesRegister(RegisterParticleProvidersEvent event) diff --git a/src/main/java/com/eerussianguy/beneath/client/models/RedElkModel.java b/src/main/java/com/eerussianguy/beneath/client/models/RedElkModel.java new file mode 100644 index 0000000..c837c2c --- /dev/null +++ b/src/main/java/com/eerussianguy/beneath/client/models/RedElkModel.java @@ -0,0 +1,233 @@ +package com.eerussianguy.beneath.client.models; + +import java.util.stream.Stream; +import net.minecraft.client.animation.AnimationChannel; +import net.minecraft.client.animation.AnimationDefinition; +import net.minecraft.client.animation.Keyframe; +import net.minecraft.client.animation.KeyframeAnimations; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.CubeDeformation; +import net.minecraft.client.model.geom.builders.CubeListBuilder; +import net.minecraft.client.model.geom.builders.LayerDefinition; +import net.minecraft.client.model.geom.builders.MeshDefinition; +import net.minecraft.client.model.geom.builders.PartDefinition; + +import net.dries007.tfc.client.model.entity.HierarchicalAnimatedModel; +import net.dries007.tfc.common.entities.prey.Prey; + +public class RedElkModel extends HierarchicalAnimatedModel +{ + + public static final AnimationDefinition RUN = AnimationDefinition.Builder.withLength(0.5F).looping() + .addAnimation("body", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(-5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.125F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.25F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.375F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(-5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("body", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.125F, KeyframeAnimations.posVec(0.0F, 1.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.25F, KeyframeAnimations.posVec(0.0F, 1.5F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.375F, KeyframeAnimations.posVec(0.0F, 1.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("tail", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(22.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.2083F, KeyframeAnimations.degreeVec(60.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(22.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("tail1", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.25F, KeyframeAnimations.degreeVec(-90.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.4167F, KeyframeAnimations.degreeVec(-2.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("head", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.0833F, KeyframeAnimations.degreeVec(-7.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.25F, KeyframeAnimations.degreeVec(-5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(7.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("legFR", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.0833F, KeyframeAnimations.degreeVec(-40.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.2083F, KeyframeAnimations.degreeVec(-40.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.375F, KeyframeAnimations.degreeVec(25.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.4167F, KeyframeAnimations.degreeVec(25.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("legFL", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.0833F, KeyframeAnimations.degreeVec(-40.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.2083F, KeyframeAnimations.degreeVec(-40.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.375F, KeyframeAnimations.degreeVec(25.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.4167F, KeyframeAnimations.degreeVec(25.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("legBL", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.0833F, KeyframeAnimations.degreeVec(45.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.2083F, KeyframeAnimations.degreeVec(45.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.25F, KeyframeAnimations.degreeVec(45.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.375F, KeyframeAnimations.degreeVec(-30.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("legBR", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.0833F, KeyframeAnimations.degreeVec(45.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.2083F, KeyframeAnimations.degreeVec(45.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.25F, KeyframeAnimations.degreeVec(45.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.375F, KeyframeAnimations.degreeVec(-30.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("earR", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.1F, 1.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("neck", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.0833F, KeyframeAnimations.degreeVec(7.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.25F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(-7.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .build(); + + public static final AnimationDefinition WALK = AnimationDefinition.Builder.withLength(1.0F).looping() + .addAnimation("neck", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.2917F, KeyframeAnimations.degreeVec(5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.8333F, KeyframeAnimations.degreeVec(-1.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(1.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("head", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(-5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.8333F, KeyframeAnimations.degreeVec(1.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(1.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("tail", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(10.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.625F, KeyframeAnimations.degreeVec(3.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(1.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("legBR", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.4167F, KeyframeAnimations.degreeVec(22.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.75F, KeyframeAnimations.degreeVec(-27.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(1.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("legBL", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.1667F, KeyframeAnimations.degreeVec(-27.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.8333F, KeyframeAnimations.degreeVec(22.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(1.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("legFR", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.1667F, KeyframeAnimations.degreeVec(-27.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.7917F, KeyframeAnimations.degreeVec(22.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(1.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .addAnimation("legFL", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.4167F, KeyframeAnimations.degreeVec(22.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.75F, KeyframeAnimations.degreeVec(-27.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(1.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + )) + .build(); + + + private final ModelPart head; + private final ModelPart antler1; + private final ModelPart antler2; + + public RedElkModel(ModelPart root) + { + super(root); + this.head = root.getChild("body").getChild("neck").getChild("head"); + this.antler1 = head.getChild("antlerL"); + this.antler2 = head.getChild("antlerL2"); + } + + public static LayerDefinition createBodyLayer() + { + MeshDefinition meshdefinition = new MeshDefinition(); + PartDefinition partdefinition = meshdefinition.getRoot(); + + PartDefinition body = partdefinition.addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 0).addBox(-3.0F, -18.0F, -9.0F, 6.0F, 8.0F, 17.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 25.0F, 0.0F)); + + PartDefinition neck = body.addOrReplaceChild("neck", CubeListBuilder.create(), PartPose.offset(0.0F, -15.0F, -6.0F)); + + PartDefinition neck0_r1 = neck.addOrReplaceChild("neck0_r1", CubeListBuilder.create().texOffs(0, 0).addBox(-1.5872F, -9.4021F, -1.1846F, 3.0F, 11.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0872F, 0.0038F, -1.0F, 0.6545F, 0.0F, 0.0F)); + + PartDefinition head = neck.addOrReplaceChild("head", CubeListBuilder.create().texOffs(0, 25).addBox(-2.0872F, -4.0038F, -4.0F, 4.0F, 5.0F, 5.0F, new CubeDeformation(0.0F)) + .texOffs(29, 11).addBox(-1.5872F, -2.0038F, -7.0F, 3.0F, 3.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0872F, -6.9962F, -5.0F)); + + PartDefinition earL = head.addOrReplaceChild("earL", CubeListBuilder.create().texOffs(41, 4).addBox(-1.0F, -2.0F, 0.0F, 2.0F, 3.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.0F, -4.0F, 0.0F, -0.0873F, 0.0175F, 0.1396F)); + + PartDefinition earR = head.addOrReplaceChild("earR", CubeListBuilder.create().texOffs(10, 0).addBox(-1.0F, -2.0F, 0.0F, 2.0F, 3.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.0F, -4.0F, 0.0F, -0.0873F, 0.0175F, -0.1396F)); + + PartDefinition antlerL = head.addOrReplaceChild("antlerL", CubeListBuilder.create(), PartPose.offsetAndRotation(-1.0F, -4.0F, -1.5F, 0.0F, 0.1745F, 0.0F)); + + PartDefinition antler3_r1 = antlerL.addOrReplaceChild("antler3_r1", CubeListBuilder.create().texOffs(13, 14).addBox(-0.75F, -1.5F, -0.25F, 1.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-3.5F, -1.5F, -2.5F, 0.2835F, 0.1153F, -0.3762F)); + + PartDefinition antler2_r1 = antlerL.addOrReplaceChild("antler2_r1", CubeListBuilder.create().texOffs(37, 0).addBox(-0.3645F, -0.3459F, -2.5216F, 1.0F, 1.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.0F, -1.0F, -2.0F, 0.0303F, -0.1698F, -0.3406F)); + + PartDefinition antler1_r1 = antlerL.addOrReplaceChild("antler1_r1", CubeListBuilder.create().texOffs(36, 25).addBox(-4.5F, -2.25F, 0.0F, 4.0F, 1.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 0.0F, 0.0F, 0.0458F, -0.6063F, -0.241F)); + + PartDefinition antler0_r1 = antlerL.addOrReplaceChild("antler0_r1", CubeListBuilder.create().texOffs(34, 41).addBox(-1.0F, -4.5F, 0.0F, 1.0F, 5.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 0.0F, 0.0F, 0.3155F, 0.1624F, -0.4068F)); + + PartDefinition antlerL2 = head.addOrReplaceChild("antlerL2", CubeListBuilder.create(), PartPose.offsetAndRotation(0.8257F, -4.0F, -1.5F, 0.0F, -0.1745F, 0.0F)); + + PartDefinition antler3_r2 = antlerL2.addOrReplaceChild("antler3_r2", CubeListBuilder.create().texOffs(0, 0).addBox(-0.25F, -1.5F, -0.25F, 1.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(3.5F, -1.5F, -2.5F, 0.2835F, -0.1153F, 0.3762F)); + + PartDefinition antler2_r2 = antlerL2.addOrReplaceChild("antler2_r2", CubeListBuilder.create().texOffs(13, 25).addBox(-0.6355F, -0.3459F, -2.5216F, 1.0F, 1.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(4.0F, -1.0F, -2.0F, 0.0303F, 0.1698F, 0.3406F)); + + PartDefinition antler1_r2 = antlerL2.addOrReplaceChild("antler1_r2", CubeListBuilder.create().texOffs(0, 15).addBox(0.5F, -2.25F, 0.0F, 4.0F, 1.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 0.0F, 0.0F, 0.0458F, 0.6063F, 0.241F)); + + PartDefinition antler0_r2 = antlerL2.addOrReplaceChild("antler0_r2", CubeListBuilder.create().texOffs(38, 27).addBox(0.0F, -4.5F, 0.0F, 1.0F, 5.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 0.0F, 0.0F, 0.3155F, -0.1624F, 0.4068F)); + + PartDefinition tail = body.addOrReplaceChild("tail", CubeListBuilder.create().texOffs(38, 8).addBox(-1.0F, -1.0F, 0.0F, 2.0F, 2.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -17.0F, 8.0F, -0.8727F, 0.0F, 0.0F)); + + PartDefinition legBR = body.addOrReplaceChild("legBR", CubeListBuilder.create().texOffs(29, 0).addBox(-1.0F, -2.0F, -2.0F, 2.0F, 7.0F, 4.0F, new CubeDeformation(0.0F)) + .texOffs(16, 36).addBox(-1.0F, 5.0F, 0.0F, 2.0F, 8.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offset(-3.0F, -14.0F, 5.0F)); + + PartDefinition legBL = body.addOrReplaceChild("legBL", CubeListBuilder.create().texOffs(18, 25).addBox(-1.0F, -2.0F, -2.0F, 2.0F, 7.0F, 4.0F, new CubeDeformation(0.0F)) + .texOffs(8, 35).addBox(-1.0F, 5.0F, 0.0F, 2.0F, 8.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offset(3.0F, -14.0F, 5.0F)); + + PartDefinition legFR = body.addOrReplaceChild("legFR", CubeListBuilder.create().texOffs(35, 34).addBox(-1.0F, -1.0F, -2.0F, 2.0F, 4.0F, 3.0F, new CubeDeformation(0.0F)) + .texOffs(30, 25).addBox(-1.0F, 3.0F, -1.0F, 2.0F, 10.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offset(-3.0F, -14.0F, -6.0F)); + + PartDefinition legFL = body.addOrReplaceChild("legFL", CubeListBuilder.create().texOffs(0, 35).addBox(-1.0F, 3.0F, -1.0F, 2.0F, 10.0F, 2.0F, new CubeDeformation(0.0F)) + .texOffs(24, 37).addBox(-1.0F, -1.0F, -2.0F, 2.0F, 4.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offset(3.0F, -14.0F, -6.0F)); + + return LayerDefinition.create(meshdefinition, 64, 64); + } + + @Override + public void setupAnim(Prey entity, float limbSwing, float limbSwingAmount, float ageInTicks, float headYaw, float headPitch) + { + super.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch); + boolean antlers = entity.displayMaleCharacteristics(); + Stream.concat(this.antler1.getAllParts(), this.antler2.getAllParts()).forEach((p) -> { + p.visible = antlers; + }); + float speed = this.getAdjustedLandSpeed(entity); + if (speed > 1.1F) + { + this.animateWalk(RUN, limbSwing, limbSwingAmount, 1.0F, 2.5F); + } + else + { + this.animateWalk(WALK, limbSwing, limbSwingAmount, 2.5F, 2.5F); + } + + this.head.xRot = headPitch * 0.017453292F; + this.head.yRot = headYaw * 0.017453292F; + } +} diff --git a/src/main/java/com/eerussianguy/beneath/client/models/package-info.java b/src/main/java/com/eerussianguy/beneath/client/models/package-info.java new file mode 100644 index 0000000..bc63d08 --- /dev/null +++ b/src/main/java/com/eerussianguy/beneath/client/models/package-info.java @@ -0,0 +1,9 @@ + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +package com.eerussianguy.beneath.client.models; + +import javax.annotation.ParametersAreNonnullByDefault; +import net.minecraft.FieldsAreNonnullByDefault; +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/eerussianguy/beneath/client/screen/JuicerScreen.java b/src/main/java/com/eerussianguy/beneath/client/screen/JuicerScreen.java index f7b62d2..a684287 100644 --- a/src/main/java/com/eerussianguy/beneath/client/screen/JuicerScreen.java +++ b/src/main/java/com/eerussianguy/beneath/client/screen/JuicerScreen.java @@ -21,10 +21,11 @@ public JuicerScreen(JuicerContainer container, Inventory playerInventory, Compon protected void renderLabels(GuiGraphics graphics, int x, int y) { super.renderLabels(graphics, x, y); - menu.getInventory().getStackInSlot(0).getCapability(Capabilities.FLUID_ITEM).ifPresent(cap -> { + drawCenteredLine(graphics, Component.translatable("beneath.screen.juicer.mushrooms"), 16); + menu.getTargetStack().getCapability(Capabilities.FLUID_ITEM).ifPresent(cap -> { if (!cap.getFluidInTank(0).isEmpty()) { - drawCenteredLine(graphics, Tooltips.fluidUnitsAndCapacityOf(cap.getFluidInTank(0), JuicerItem.CAPACITY), 14); + drawCenteredLine(graphics, Tooltips.fluidUnitsAndCapacityOf(cap.getFluidInTank(0), JuicerItem.CAPACITY), 55); } }); } diff --git a/src/main/java/com/eerussianguy/beneath/common/blockentities/BeneathBlockEntities.java b/src/main/java/com/eerussianguy/beneath/common/blockentities/BeneathBlockEntities.java index fac7085..0e72b6a 100644 --- a/src/main/java/com/eerussianguy/beneath/common/blockentities/BeneathBlockEntities.java +++ b/src/main/java/com/eerussianguy/beneath/common/blockentities/BeneathBlockEntities.java @@ -27,6 +27,7 @@ public class BeneathBlockEntities public static final RegistryObject> HANGING_SIGN = register("hanging_sign", BeneathHangingSignBlockEntity::new, Stream.of( BeneathBlocks.CEILING_HANGING_SIGNS, BeneathBlocks.WALL_HANGING_SIGNS ).flatMap(woodMap -> woodMap.values().stream().flatMap(metalMap -> metalMap.values().stream()))); + public static final RegistryObject> UNPOSTER = register("unposter", UnposterBlockEntity::new, BeneathBlocks.UNPOSTER); private static RegistryObject> register(String name, BlockEntityType.BlockEntitySupplier factory, Supplier block) { diff --git a/src/main/java/com/eerussianguy/beneath/common/blockentities/UnposterBlockEntity.java b/src/main/java/com/eerussianguy/beneath/common/blockentities/UnposterBlockEntity.java new file mode 100644 index 0000000..e59d90e --- /dev/null +++ b/src/main/java/com/eerussianguy/beneath/common/blockentities/UnposterBlockEntity.java @@ -0,0 +1,21 @@ +package com.eerussianguy.beneath.common.blockentities; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import net.dries007.tfc.common.blockentities.TickCounterBlockEntity; + +public class UnposterBlockEntity extends TickCounterBlockEntity +{ + public UnposterBlockEntity(BlockPos pos, BlockState state) + { + super(pos, state); + } + + @Override + public BlockEntityType getType() + { + return BeneathBlockEntities.UNPOSTER.get(); + } +} diff --git a/src/main/java/com/eerussianguy/beneath/common/blocks/BeneathBlockTags.java b/src/main/java/com/eerussianguy/beneath/common/blocks/BeneathBlockTags.java index 6d708a7..1773132 100644 --- a/src/main/java/com/eerussianguy/beneath/common/blocks/BeneathBlockTags.java +++ b/src/main/java/com/eerussianguy/beneath/common/blocks/BeneathBlockTags.java @@ -10,6 +10,7 @@ public class BeneathBlockTags public static final TagKey BREAKS_SLOWLY = create("breaks_slowly"); public static final TagKey HELLFORGE_INSULATION = create("hellforge_insulation"); public static final TagKey NETHER_BUSH_PLANTABLE_ON = create("nether_bush_plantable_on"); + public static final TagKey MUSHROOMS = create("mushrooms"); private static TagKey create(String id) { diff --git a/src/main/java/com/eerussianguy/beneath/common/blocks/BeneathBlocks.java b/src/main/java/com/eerussianguy/beneath/common/blocks/BeneathBlocks.java index 4a1e7ce..27142fc 100644 --- a/src/main/java/com/eerussianguy/beneath/common/blocks/BeneathBlocks.java +++ b/src/main/java/com/eerussianguy/beneath/common/blocks/BeneathBlocks.java @@ -85,6 +85,7 @@ public class BeneathBlocks public static final RegistryObject CURSECOAL_PILE = registerNoItem("cursecoal_pile", () -> new CursecoalPileBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).strength(0.2F).sound(TFCSounds.CHARCOAL).isViewBlocking((state, level, pos) -> state.getValue(CharcoalPileBlock.LAYERS) >= 8).isSuffocating((state, level, pos) -> state.getValue(CharcoalPileBlock.LAYERS) >= 8))); public static final RegistryObject GLEAMFLOWER = register("gleamflower", () -> new NFlowerBlock(ExtendedProperties.of().sound(SoundType.GRASS).instabreak().speedFactor(0.8f).noCollission().lightLevel(s -> 7))); public static final RegistryObject BURPFLOWER = register("burpflower", () -> new BurpingFlowerBlock(ExtendedProperties.of().sound(SoundType.GRASS).instabreak().speedFactor(0.8f).noCollission().randomTicks())); + public static final RegistryObject UNPOSTER = register("unposter", () -> new UnposterBlock(ExtendedProperties.of(MapColor.COLOR_BLUE).strength(0.6F).noOcclusion().sound(SoundType.WOOD).randomTicks().blockEntity(BeneathBlockEntities.UNPOSTER))); public static final Map> SHROOMS = Helpers.mapOfKeys(Shroom.class, shroom -> registerNoItem("mushroom/" + shroom.getSerializedName(), () -> new NFlowerBlock(ExtendedProperties.of(Blocks.CRIMSON_FUNGUS)))); public static final Map>> WOODS = Helpers.mapOfKeys(Stem.class, wood -> diff --git a/src/main/java/com/eerussianguy/beneath/common/blocks/UnposterBlock.java b/src/main/java/com/eerussianguy/beneath/common/blocks/UnposterBlock.java new file mode 100644 index 0000000..95d31f3 --- /dev/null +++ b/src/main/java/com/eerussianguy/beneath/common/blocks/UnposterBlock.java @@ -0,0 +1,125 @@ +package com.eerussianguy.beneath.common.blocks; + +import java.util.ArrayList; +import java.util.List; +import com.eerussianguy.beneath.common.blockentities.UnposterBlockEntity; +import com.eerussianguy.beneath.common.items.BeneathItemTags; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; + +import net.dries007.tfc.common.blocks.EntityBlockExtension; +import net.dries007.tfc.common.blocks.ExtendedProperties; +import net.dries007.tfc.common.blocks.TFCBlockStateProperties; +import net.dries007.tfc.common.blocks.devices.BottomSupportedDeviceBlock; +import net.dries007.tfc.util.Helpers; +import net.dries007.tfc.util.calendar.ICalendar; + +public class UnposterBlock extends BottomSupportedDeviceBlock implements EntityBlockExtension +{ + public static final IntegerProperty STAGE = TFCBlockStateProperties.STAGE_8; + + public UnposterBlock(ExtendedProperties properties) + { + super(properties, InventoryRemoveBehavior.NOOP); + registerDefaultState(this.defaultBlockState().setValue(STAGE, 0)); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) + { + super.createBlockStateDefinition(builder.add(STAGE)); + } + + @Override + @SuppressWarnings("deprecation") + public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) + { + if (state.getValue(STAGE) > 0 && level.getBlockEntity(pos) instanceof UnposterBlockEntity poster) + { + final long ticksSinceUpdate = poster.getTicksSinceUpdate(); + int cyclesLeft = Math.min(state.getValue(STAGE), (int) (ticksSinceUpdate % ICalendar.TICKS_IN_DAY)); + int cyclesUsed = 0; + if (cyclesLeft > 0) + { + final List shrooms = new ArrayList<>(); + for (BlockPos testPos : BlockPos.withinManhattan(pos, 5, 1, 5)) + { + final BlockState stateAt = level.getBlockState(testPos); + if (Helpers.isBlock(stateAt, BeneathBlockTags.MUSHROOMS)) + { + shrooms.add(stateAt); + } + } + if (!shrooms.isEmpty()) + { + for (BlockPos testPos : BlockPos.withinManhattan(pos, 5, 1, 5)) + { + if (shrooms.isEmpty() || cyclesLeft <= 0) + break; + final BlockState stateAt = level.getBlockState(testPos); + if (stateAt.isAir()) + { + final BlockState shroomState = shrooms.get(0); + if (shroomState.canSurvive(level, testPos)) + { + shrooms.remove(0); + cyclesLeft--; + cyclesUsed++; + level.setBlockAndUpdate(testPos, shroomState); + } + } + } + } + + if (cyclesUsed > 0) + { + level.setBlockAndUpdate(pos, state.setValue(STAGE, Math.max(0, state.getValue(STAGE) - cyclesUsed))); + } + poster.resetCounter(); + } + } + } + + @Override + public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) + { + if (level.getBlockEntity(pos) instanceof UnposterBlockEntity poster) + { + poster.resetCounter(); + } + super.setPlacedBy(level, pos, state, placer, stack); + } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) + { + final int stage = state.getValue(STAGE); + final ItemStack held = player.getItemInHand(hand); + + if (stage < 8 && Helpers.isItem(held, BeneathItemTags.UNPOSTABLE)) + { + level.setBlockAndUpdate(pos, state.setValue(STAGE, Math.min(8, stage + Mth.nextInt(level.random, 1, 2)))); + held.shrink(1); + Helpers.playSound(level, pos, SoundEvents.NYLIUM_PLACE); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } +} diff --git a/src/main/java/com/eerussianguy/beneath/common/items/BeneathItemTags.java b/src/main/java/com/eerussianguy/beneath/common/items/BeneathItemTags.java index 7b47f52..383bb70 100644 --- a/src/main/java/com/eerussianguy/beneath/common/items/BeneathItemTags.java +++ b/src/main/java/com/eerussianguy/beneath/common/items/BeneathItemTags.java @@ -10,6 +10,7 @@ public class BeneathItemTags { public static final TagKey SPARKS_ON_SULFUR = create("sparks_on_sulfur"); public static final TagKey USABLE_IN_JUICER = create("usable_in_juicer"); + public static final TagKey UNPOSTABLE = create("unpostable"); private static TagKey create(String id) { diff --git a/src/main/java/com/eerussianguy/beneath/misc/BeneathCreativeTabs.java b/src/main/java/com/eerussianguy/beneath/misc/BeneathCreativeTabs.java index a1b1f53..e8a2a06 100644 --- a/src/main/java/com/eerussianguy/beneath/misc/BeneathCreativeTabs.java +++ b/src/main/java/com/eerussianguy/beneath/misc/BeneathCreativeTabs.java @@ -55,6 +55,7 @@ private static void fillTab(CreativeModeTab.ItemDisplayParameters parameters, Cr accept(out, BeneathBlocks.COBBLERACK); accept(out, BeneathBlocks.FUNGAL_COBBLERACK); accept(out, BeneathBlocks.BLACKSTONE_AQUEDUCT); + accept(out, BeneathBlocks.UNPOSTER); accept(out, BeneathBlocks.SOUL_FARMLAND); accept(out, BeneathBlocks.CRIMSON_THATCH); accept(out, BeneathBlocks.WARPED_THATCH); diff --git a/src/main/resources/assets/beneath/blockstates/unposter.json b/src/main/resources/assets/beneath/blockstates/unposter.json new file mode 100644 index 0000000..ba0d349 --- /dev/null +++ b/src/main/resources/assets/beneath/blockstates/unposter.json @@ -0,0 +1,32 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "variants": { + "stage=0": { + "model": "beneath:block/unposter_0" + }, + "stage=1": { + "model": "beneath:block/unposter_1" + }, + "stage=2": { + "model": "beneath:block/unposter_2" + }, + "stage=3": { + "model": "beneath:block/unposter_3" + }, + "stage=4": { + "model": "beneath:block/unposter_4" + }, + "stage=5": { + "model": "beneath:block/unposter_5" + }, + "stage=6": { + "model": "beneath:block/unposter_6" + }, + "stage=7": { + "model": "beneath:block/unposter_7" + }, + "stage=8": { + "model": "beneath:block/unposter_8" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/lang/en_us.json b/src/main/resources/assets/beneath/lang/en_us.json index 23cf5b0..3cd3818 100644 --- a/src/main/resources/assets/beneath/lang/en_us.json +++ b/src/main/resources/assets/beneath/lang/en_us.json @@ -159,6 +159,7 @@ "beneath.nutrient.sorrow": "Sorrow: §9%s%%", "beneath.block_entity.hellforge": "Hellforge", "beneath.screen.juicer": "Juicer", + "beneath.screen.juicer.mushrooms": "Feed me mushrooms!", "item.beneath.juicer.filled": "Juicer (%s)", "death.attack.beneath.sulfur": "%1$s mined sulfur with an iron tool and blew themselves up.", "death.attack.beneath.sulfur.player": "%1$s mined sulfur with an iron tool and blew themselves up while trying to escape %2$s.", @@ -212,6 +213,7 @@ "item.beneath.seeds.warped_roots": "Warped Roots Seeds", "block.beneath.gleamflower": "Gleamflower", "block.beneath.burpflower": "Burpflower", + "block.beneath.unposter": "Unposter", "block.beneath.cursecoal_pile": "Cursecoal Pile", "block.beneath.hellforge": "Hellforge", "block.beneath.hellforge_side": "Hellforge", @@ -219,26 +221,26 @@ "block.beneath.soul_farmland": "Soul Farmland", "block.beneath.soul_clay": "Soul Clay", "block.beneath.crackrack": "Crackrack", - "block.beneath.mushroom.button": "Button Mushroom", - "item.beneath.food.button": "Button Mushroom", - "block.beneath.mushroom.chantrelle": "Chantrelle Mushroom", - "item.beneath.food.chantrelle": "Chantrelle Mushroom", - "block.beneath.mushroom.death_cap": "Death Cap Mushroom", - "item.beneath.food.death_cap": "Death Cap Mushroom", - "block.beneath.mushroom.destroying_angels": "Destroying Angels Mushroom", - "item.beneath.food.destroying_angels": "Destroying Angels Mushroom", - "block.beneath.mushroom.fools_funnel": "Fool'S Funnel Mushroom", - "item.beneath.food.fools_funnel": "Fool'S Funnel Mushroom", - "block.beneath.mushroom.oyster": "Oyster Mushroom", - "item.beneath.food.oyster": "Oyster Mushroom", - "block.beneath.mushroom.parasol": "Parasol Mushroom", - "item.beneath.food.parasol": "Parasol Mushroom", - "block.beneath.mushroom.portobello": "Portobello Mushroom", - "item.beneath.food.portobello": "Portobello Mushroom", - "block.beneath.mushroom.shittake": "Shittake Mushroom", - "item.beneath.food.shittake": "Shittake Mushroom", - "block.beneath.mushroom.sulfur_tuft": "Sulfur Tuft Mushroom", - "item.beneath.food.sulfur_tuft": "Sulfur Tuft Mushroom", + "block.beneath.mushroom.button": "Button", + "item.beneath.food.button": "Button", + "block.beneath.mushroom.chantrelle": "Chantrelle", + "item.beneath.food.chantrelle": "Chantrelle", + "block.beneath.mushroom.death_cap": "Death Cap", + "item.beneath.food.death_cap": "Death Cap", + "block.beneath.mushroom.destroying_angels": "Destroying Angels", + "item.beneath.food.destroying_angels": "Destroying Angels", + "block.beneath.mushroom.fools_funnel": "Fool'S Funnel", + "item.beneath.food.fools_funnel": "Fool's Funnel", + "block.beneath.mushroom.oyster": "Oyster", + "item.beneath.food.oyster": "Oyster", + "block.beneath.mushroom.parasol": "Parasol", + "item.beneath.food.parasol": "Parasol", + "block.beneath.mushroom.portobello": "Portobello", + "item.beneath.food.portobello": "Portobello", + "block.beneath.mushroom.shittake": "Shittake", + "item.beneath.food.shittake": "Shittake", + "block.beneath.mushroom.sulfur_tuft": "Sulfur Tuft", + "item.beneath.food.sulfur_tuft": "Sulfur Tuft", "block.beneath.cobblerack": "Cobblerack", "block.beneath.fungal_cobblerack": "Fungal Cobblerack", "block.beneath.warped_thatch": "Warped Thatch", diff --git a/src/main/resources/assets/beneath/models/block/compost_1.json b/src/main/resources/assets/beneath/models/block/compost_1.json new file mode 100644 index 0000000..f09d386 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/compost_1.json @@ -0,0 +1,73 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "beneath:block/unposter/unposter_bottom", + "2": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [1, 1, 1], + "to": [15, 2, 15], + "faces": { + "north": {"uv": [0, 0, 14, 1], "texture": "#0"}, + "east": {"uv": [0, 0, 14, 1], "texture": "#0"}, + "south": {"uv": [0, 0, 14, 1], "texture": "#0"}, + "west": {"uv": [0, 0, 14, 1], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#2"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/compost_2.json b/src/main/resources/assets/beneath/models/block/compost_2.json new file mode 100644 index 0000000..23fcb4e --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/compost_2.json @@ -0,0 +1,73 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "beneath:block/unposter/unposter_bottom", + "2": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [1, 1, 1], + "to": [15, 4, 15], + "faces": { + "north": {"uv": [0, 0, 14, 3], "texture": "#0"}, + "east": {"uv": [0, 0, 14, 3], "texture": "#0"}, + "south": {"uv": [0, 0, 14, 3], "texture": "#0"}, + "west": {"uv": [0, 0, 14, 3], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#2"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/compost_3.json b/src/main/resources/assets/beneath/models/block/compost_3.json new file mode 100644 index 0000000..dac6cb6 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/compost_3.json @@ -0,0 +1,73 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "beneath:block/unposter/unposter_bottom", + "2": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [1, 1, 1], + "to": [15, 6, 15], + "faces": { + "north": {"uv": [0, 0, 14, 5], "texture": "#0"}, + "east": {"uv": [0, 0, 14, 5], "texture": "#0"}, + "south": {"uv": [0, 0, 14, 5], "texture": "#0"}, + "west": {"uv": [0, 0, 14, 5], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#2"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/compost_4.json b/src/main/resources/assets/beneath/models/block/compost_4.json new file mode 100644 index 0000000..28b0727 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/compost_4.json @@ -0,0 +1,73 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "beneath:block/unposter/unposter_bottom", + "2": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [1, 1, 1], + "to": [15, 8, 15], + "faces": { + "north": {"uv": [0, 0, 14, 7], "texture": "#0"}, + "east": {"uv": [0, 0, 14, 7], "texture": "#0"}, + "south": {"uv": [0, 0, 14, 7], "texture": "#0"}, + "west": {"uv": [0, 0, 14, 7], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#2"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/compost_5.json b/src/main/resources/assets/beneath/models/block/compost_5.json new file mode 100644 index 0000000..ed76c53 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/compost_5.json @@ -0,0 +1,73 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "beneath:block/unposter/unposter_bottom", + "2": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [1, 1, 1], + "to": [15, 10, 15], + "faces": { + "north": {"uv": [0, 0, 14, 9], "texture": "#0"}, + "east": {"uv": [0, 0, 14, 9], "texture": "#0"}, + "south": {"uv": [0, 0, 14, 9], "texture": "#0"}, + "west": {"uv": [0, 0, 14, 9], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#2"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/compost_6.json b/src/main/resources/assets/beneath/models/block/compost_6.json new file mode 100644 index 0000000..2032476 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/compost_6.json @@ -0,0 +1,83 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "1": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom", + "1_0": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [1, 1, 1], + "to": [15, 12, 15], + "faces": { + "north": {"uv": [0, 0, 14, 11], "texture": "#0"}, + "east": {"uv": [0, 0, 14, 11], "texture": "#0"}, + "south": {"uv": [0, 0, 14, 11], "texture": "#0"}, + "west": {"uv": [0, 0, 14, 11], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1_0"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1_0"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#1"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#1"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#1"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#1"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#1_0"} + } + } + ], + "groups": [ + 0, + { + "name": "unposter", + "origin": [8, 8, 8], + "color": 0, + "children": [1, 2, 3, 4, 5] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/compost_7.json b/src/main/resources/assets/beneath/models/block/compost_7.json new file mode 100644 index 0000000..54d2327 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/compost_7.json @@ -0,0 +1,83 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "1": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom", + "1_0": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [1, 1, 1], + "to": [15, 14, 15], + "faces": { + "north": {"uv": [0, 0, 14, 13], "texture": "#0"}, + "east": {"uv": [0, 0, 14, 13], "texture": "#0"}, + "south": {"uv": [0, 0, 14, 13], "texture": "#0"}, + "west": {"uv": [0, 0, 14, 13], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1_0"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1_0"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#1"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#1"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#1"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#1"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#1_0"} + } + } + ], + "groups": [ + 0, + { + "name": "unposter", + "origin": [8, 8, 8], + "color": 0, + "children": [1, 2, 3, 4, 5] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/compost_8.json b/src/main/resources/assets/beneath/models/block/compost_8.json new file mode 100644 index 0000000..186aa79 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/compost_8.json @@ -0,0 +1,73 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "beneath:block/unposter/unposter_bottom", + "2": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [1, 1, 1], + "to": [15, 16, 15], + "faces": { + "north": {"uv": [0, 0, 14, 15], "texture": "#0"}, + "east": {"uv": [0, 0, 14, 15], "texture": "#0"}, + "south": {"uv": [0, 0, 14, 15], "texture": "#0"}, + "west": {"uv": [0, 0, 14, 15], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#2"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#2"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#2"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter.json b/src/main/resources/assets/beneath/models/block/unposter.json new file mode 100644 index 0000000..52b3369 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter.json @@ -0,0 +1,63 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "0": "beneath:block/unposter/unposter_bottom", + "1": "beneath:block/unposter/unposter_side", + "particle": "beneath:block/unposter/unposter_bottom" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "east": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "south": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "west": {"uv": [0, 15, 16, 16], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#0"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#0"} + } + }, + { + "from": [0, 1, 0], + "to": [16, 16, 1], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#1"} + } + }, + { + "from": [0, 1, 15], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "east": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "south": {"uv": [0, 0, 16, 15], "texture": "#1"}, + "west": {"uv": [0, 0, 1, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 1], "texture": "#1"} + } + }, + { + "from": [0, 1, 1], + "to": [1, 16, 15], + "faces": { + "east": {"uv": [0, 0, 14, 15], "texture": "#1"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "up": {"uv": [0, 0, 14, 1], "rotation": 90, "texture": "#1"} + } + }, + { + "from": [15, 1, 1], + "to": [16, 16, 15], + "faces": { + "east": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "west": {"uv": [1, 0, 15, 15], "texture": "#1"}, + "up": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_0.json b/src/main/resources/assets/beneath/models/block/unposter_0.json new file mode 100644 index 0000000..2dc31d0 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_0.json @@ -0,0 +1,4 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/unposter" +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_1.json b/src/main/resources/assets/beneath/models/block/unposter_1.json new file mode 100644 index 0000000..ec5bb6d --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_1.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/compost_1", + "textures": { + "0": "beneath:block/unposter/normal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_2.json b/src/main/resources/assets/beneath/models/block/unposter_2.json new file mode 100644 index 0000000..222b9fb --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_2.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/compost_2", + "textures": { + "0": "beneath:block/unposter/normal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_3.json b/src/main/resources/assets/beneath/models/block/unposter_3.json new file mode 100644 index 0000000..4676c41 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_3.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/compost_3", + "textures": { + "0": "beneath:block/unposter/normal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_4.json b/src/main/resources/assets/beneath/models/block/unposter_4.json new file mode 100644 index 0000000..edef3fd --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_4.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/compost_4", + "textures": { + "0": "beneath:block/unposter/normal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_5.json b/src/main/resources/assets/beneath/models/block/unposter_5.json new file mode 100644 index 0000000..4301703 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_5.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/compost_5", + "textures": { + "0": "beneath:block/unposter/normal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_6.json b/src/main/resources/assets/beneath/models/block/unposter_6.json new file mode 100644 index 0000000..2bc974f --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_6.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/compost_6", + "textures": { + "0": "beneath:block/unposter/normal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_7.json b/src/main/resources/assets/beneath/models/block/unposter_7.json new file mode 100644 index 0000000..8196daa --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_7.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/compost_7", + "textures": { + "0": "beneath:block/unposter/normal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/block/unposter_8.json b/src/main/resources/assets/beneath/models/block/unposter_8.json new file mode 100644 index 0000000..ce97e42 --- /dev/null +++ b/src/main/resources/assets/beneath/models/block/unposter_8.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/compost_8", + "textures": { + "0": "beneath:block/unposter/normal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/models/item/unposter.json b/src/main/resources/assets/beneath/models/item/unposter.json new file mode 100644 index 0000000..2dc31d0 --- /dev/null +++ b/src/main/resources/assets/beneath/models/item/unposter.json @@ -0,0 +1,4 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "parent": "beneath:block/unposter" +} \ No newline at end of file diff --git a/src/main/resources/assets/beneath/textures/block/unposter/normal.png b/src/main/resources/assets/beneath/textures/block/unposter/normal.png new file mode 100644 index 0000000..bef6cff Binary files /dev/null and b/src/main/resources/assets/beneath/textures/block/unposter/normal.png differ diff --git a/src/main/resources/assets/beneath/textures/block/unposter/unposter_bottom.png b/src/main/resources/assets/beneath/textures/block/unposter/unposter_bottom.png new file mode 100644 index 0000000..542a6a1 Binary files /dev/null and b/src/main/resources/assets/beneath/textures/block/unposter/unposter_bottom.png differ diff --git a/src/main/resources/assets/beneath/textures/block/unposter/unposter_side.png b/src/main/resources/assets/beneath/textures/block/unposter/unposter_side.png new file mode 100644 index 0000000..b513886 Binary files /dev/null and b/src/main/resources/assets/beneath/textures/block/unposter/unposter_side.png differ diff --git a/src/main/resources/assets/beneath/textures/entity/nether_deer.png b/src/main/resources/assets/beneath/textures/entity/nether_deer.png new file mode 100644 index 0000000..6bab5e0 Binary files /dev/null and b/src/main/resources/assets/beneath/textures/entity/nether_deer.png differ diff --git a/src/main/resources/assets/beneath/textures/entity/nether_deer_fawn.png b/src/main/resources/assets/beneath/textures/entity/nether_deer_fawn.png new file mode 100644 index 0000000..e22cef7 Binary files /dev/null and b/src/main/resources/assets/beneath/textures/entity/nether_deer_fawn.png differ diff --git a/src/main/resources/assets/beneath/textures/entity/red_elk.png b/src/main/resources/assets/beneath/textures/entity/red_elk.png deleted file mode 100644 index f1187ce..0000000 Binary files a/src/main/resources/assets/beneath/textures/entity/red_elk.png and /dev/null differ diff --git a/src/main/resources/data/beneath/loot_tables/blocks/unposter.json b/src/main/resources/data/beneath/loot_tables/blocks/unposter.json new file mode 100644 index 0000000..28dcaf6 --- /dev/null +++ b/src/main/resources/data/beneath/loot_tables/blocks/unposter.json @@ -0,0 +1,21 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "type": "minecraft:block", + "pools": [ + { + "name": "loot_pool", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "beneath:unposter" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/beneath/tags/items/unpostable.json b/src/main/resources/data/beneath/tags/items/unpostable.json new file mode 100644 index 0000000..5210fff --- /dev/null +++ b/src/main/resources/data/beneath/tags/items/unpostable.json @@ -0,0 +1,15 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "replace": false, + "values": [ + "#beneath:mushrooms", + "minecraft:warped_fungus", + "minecraft:crimson_fungus", + "beneath:ghost_pepper", + "beneath:gleamflower", + "minecraft:crimson_roots", + "minecraft:warped_roots", + "minecraft:nether_wart", + "minecraft:ghast_tear" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/beneath/tags/items/usable_in_juicer.json b/src/main/resources/data/beneath/tags/items/usable_in_juicer.json index 44790f7..62c4ed9 100644 --- a/src/main/resources/data/beneath/tags/items/usable_in_juicer.json +++ b/src/main/resources/data/beneath/tags/items/usable_in_juicer.json @@ -3,6 +3,8 @@ "replace": false, "values": [ "#tfc:foods/fruits", - "#beneath:mushrooms" + "#beneath:mushrooms", + "minecraft:warped_fungus", + "minecraft:crimson_fungus" ] } \ No newline at end of file diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/blackstone_pebble.json b/src/main/resources/data/beneath/worldgen/configured_feature/blackstone_pebble.json index 22deebd..0baa5a9 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/blackstone_pebble.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/blackstone_pebble.json @@ -5,8 +5,7 @@ "to_place": { "type": "tfc:random_property", "state": { - "Name": "beneath:blackstone_pebble", - "Properties": {} + "Name": "beneath:blackstone_pebble" }, "property": "count" } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/burpflower.json b/src/main/resources/data/beneath/worldgen/configured_feature/burpflower.json index 0aa3a05..f1ba28e 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/burpflower.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/burpflower.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:burpflower", - "Properties": {} + "Name": "beneath:burpflower" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/button.json b/src/main/resources/data/beneath/worldgen/configured_feature/button.json index cf7a893..a7818fb 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/button.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/button.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/button", - "Properties": {} + "Name": "beneath:mushroom/button" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/chantrelle.json b/src/main/resources/data/beneath/worldgen/configured_feature/chantrelle.json index ecfe0d6..3dca55f 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/chantrelle.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/chantrelle.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/chantrelle", - "Properties": {} + "Name": "beneath:mushroom/chantrelle" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/death_cap.json b/src/main/resources/data/beneath/worldgen/configured_feature/death_cap.json index 5e9a395..79c4fad 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/death_cap.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/death_cap.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/death_cap", - "Properties": {} + "Name": "beneath:mushroom/death_cap" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/delta.json b/src/main/resources/data/beneath/worldgen/configured_feature/delta.json index 8817fe1..fc19215 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/delta.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/delta.json @@ -9,8 +9,7 @@ } }, "rim": { - "Name": "tfc:rock/magma/basalt", - "Properties": {} + "Name": "tfc:rock/magma/basalt" }, "rim_size": { "type": "uniform", diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/destroying_angels.json b/src/main/resources/data/beneath/worldgen/configured_feature/destroying_angels.json index d13f68f..5a7fa5d 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/destroying_angels.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/destroying_angels.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/destroying_angels", - "Properties": {} + "Name": "beneath:mushroom/destroying_angels" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/fools_funnel.json b/src/main/resources/data/beneath/worldgen/configured_feature/fools_funnel.json index 45ea76d..03e91ac 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/fools_funnel.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/fools_funnel.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/fools_funnel", - "Properties": {} + "Name": "beneath:mushroom/fools_funnel" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/gleamflower.json b/src/main/resources/data/beneath/worldgen/configured_feature/gleamflower.json index 33c8e92..76a62d8 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/gleamflower.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/gleamflower.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:gleamflower", - "Properties": {} + "Name": "beneath:gleamflower" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/magma_andesite.json b/src/main/resources/data/beneath/worldgen/configured_feature/magma_andesite.json index fbc7786..44e1fc0 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/magma_andesite.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/magma_andesite.json @@ -7,8 +7,7 @@ "targets": [ { "state": { - "Name": "tfc:rock/magma/andesite", - "Properties": {} + "Name": "tfc:rock/magma/andesite" }, "target": { "block": "minecraft:netherrack", diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/magma_basalt.json b/src/main/resources/data/beneath/worldgen/configured_feature/magma_basalt.json index 2eddc34..afbda1f 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/magma_basalt.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/magma_basalt.json @@ -7,8 +7,7 @@ "targets": [ { "state": { - "Name": "tfc:rock/magma/basalt", - "Properties": {} + "Name": "tfc:rock/magma/basalt" }, "target": { "block": "minecraft:netherrack", diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/magma_dacite.json b/src/main/resources/data/beneath/worldgen/configured_feature/magma_dacite.json index 04b5b37..8b44160 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/magma_dacite.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/magma_dacite.json @@ -7,8 +7,7 @@ "targets": [ { "state": { - "Name": "tfc:rock/magma/dacite", - "Properties": {} + "Name": "tfc:rock/magma/dacite" }, "target": { "block": "minecraft:netherrack", diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/magma_rhyolite.json b/src/main/resources/data/beneath/worldgen/configured_feature/magma_rhyolite.json index 1d6ee39..cc25160 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/magma_rhyolite.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/magma_rhyolite.json @@ -7,8 +7,7 @@ "targets": [ { "state": { - "Name": "tfc:rock/magma/rhyolite", - "Properties": {} + "Name": "tfc:rock/magma/rhyolite" }, "target": { "block": "minecraft:netherrack", diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/nether_pebble.json b/src/main/resources/data/beneath/worldgen/configured_feature/nether_pebble.json index 0ef9c76..b9f5231 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/nether_pebble.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/nether_pebble.json @@ -5,8 +5,7 @@ "to_place": { "type": "tfc:random_property", "state": { - "Name": "beneath:nether_pebble", - "Properties": {} + "Name": "beneath:nether_pebble" }, "property": "count" } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/oyster.json b/src/main/resources/data/beneath/worldgen/configured_feature/oyster.json index df1e5d3..da9908a 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/oyster.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/oyster.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/oyster", - "Properties": {} + "Name": "beneath:mushroom/oyster" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/parasol.json b/src/main/resources/data/beneath/worldgen/configured_feature/parasol.json index a99478d..0d5958b 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/parasol.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/parasol.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/parasol", - "Properties": {} + "Name": "beneath:mushroom/parasol" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/portobello.json b/src/main/resources/data/beneath/worldgen/configured_feature/portobello.json index baf3403..7bc5ceb 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/portobello.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/portobello.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/portobello", - "Properties": {} + "Name": "beneath:mushroom/portobello" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/shittake.json b/src/main/resources/data/beneath/worldgen/configured_feature/shittake.json index 1b74668..debed81 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/shittake.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/shittake.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/shittake", - "Properties": {} + "Name": "beneath:mushroom/shittake" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/sulfur.json b/src/main/resources/data/beneath/worldgen/configured_feature/sulfur.json index 29c1762..daeaccd 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/sulfur.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/sulfur.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:sulfur", - "Properties": {} + "Name": "beneath:sulfur" } } } diff --git a/src/main/resources/data/beneath/worldgen/configured_feature/sulfur_tuft.json b/src/main/resources/data/beneath/worldgen/configured_feature/sulfur_tuft.json index 8f756d3..9cf7f7c 100644 --- a/src/main/resources/data/beneath/worldgen/configured_feature/sulfur_tuft.json +++ b/src/main/resources/data/beneath/worldgen/configured_feature/sulfur_tuft.json @@ -5,8 +5,7 @@ "to_place": { "type": "minecraft:simple_state_provider", "state": { - "Name": "beneath:mushroom/sulfur_tuft", - "Properties": {} + "Name": "beneath:mushroom/sulfur_tuft" } } } diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/blackstone_pebble.json b/src/main/resources/data/beneath/worldgen/placed_feature/blackstone_pebble.json index 0cfe17e..e846499 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/blackstone_pebble.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/blackstone_pebble.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:nether_pebble", - "Properties": {} + "Name": "beneath:nether_pebble" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/burpflower.json b/src/main/resources/data/beneath/worldgen/placed_feature/burpflower.json index e0e1c0e..658bf60 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/burpflower.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/burpflower.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:burpflower", - "Properties": {} + "Name": "beneath:burpflower" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/button.json b/src/main/resources/data/beneath/worldgen/placed_feature/button.json index 0762c3f..6471242 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/button.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/button.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/button", - "Properties": {} + "Name": "beneath:mushroom/button" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/chantrelle.json b/src/main/resources/data/beneath/worldgen/placed_feature/chantrelle.json index 5a668cd..bb2e295 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/chantrelle.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/chantrelle.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/chantrelle", - "Properties": {} + "Name": "beneath:mushroom/chantrelle" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/death_cap.json b/src/main/resources/data/beneath/worldgen/placed_feature/death_cap.json index c92e9c0..ee0ec1f 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/death_cap.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/death_cap.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/death_cap", - "Properties": {} + "Name": "beneath:mushroom/death_cap" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/destroying_angels.json b/src/main/resources/data/beneath/worldgen/placed_feature/destroying_angels.json index 2432680..b5f3fb2 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/destroying_angels.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/destroying_angels.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/destroying_angels", - "Properties": {} + "Name": "beneath:mushroom/destroying_angels" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/fools_funnel.json b/src/main/resources/data/beneath/worldgen/placed_feature/fools_funnel.json index 3b1a09b..75c94e5 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/fools_funnel.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/fools_funnel.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/fools_funnel", - "Properties": {} + "Name": "beneath:mushroom/fools_funnel" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/gleamflower.json b/src/main/resources/data/beneath/worldgen/placed_feature/gleamflower.json index dc5d9e8..043d903 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/gleamflower.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/gleamflower.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:gleamflower", - "Properties": {} + "Name": "beneath:gleamflower" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/nether_pebble.json b/src/main/resources/data/beneath/worldgen/placed_feature/nether_pebble.json index 2579842..692b895 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/nether_pebble.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/nether_pebble.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:nether_pebble", - "Properties": {} + "Name": "beneath:nether_pebble" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/oyster.json b/src/main/resources/data/beneath/worldgen/placed_feature/oyster.json index 6144c46..2ab7326 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/oyster.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/oyster.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/oyster", - "Properties": {} + "Name": "beneath:mushroom/oyster" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/parasol.json b/src/main/resources/data/beneath/worldgen/placed_feature/parasol.json index 2b66d48..86eaba7 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/parasol.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/parasol.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/parasol", - "Properties": {} + "Name": "beneath:mushroom/parasol" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/portobello.json b/src/main/resources/data/beneath/worldgen/placed_feature/portobello.json index d8efcee..9e9b8ec 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/portobello.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/portobello.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/portobello", - "Properties": {} + "Name": "beneath:mushroom/portobello" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/shittake.json b/src/main/resources/data/beneath/worldgen/placed_feature/shittake.json index cdfe041..3f3f045 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/shittake.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/shittake.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/shittake", - "Properties": {} + "Name": "beneath:mushroom/shittake" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/sulfur.json b/src/main/resources/data/beneath/worldgen/placed_feature/sulfur.json index 5e01c68..ded07fa 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/sulfur.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/sulfur.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:sulfur", - "Properties": {} + "Name": "beneath:sulfur" } } }, diff --git a/src/main/resources/data/beneath/worldgen/placed_feature/sulfur_tuft.json b/src/main/resources/data/beneath/worldgen/placed_feature/sulfur_tuft.json index ff7b3de..ad60d99 100644 --- a/src/main/resources/data/beneath/worldgen/placed_feature/sulfur_tuft.json +++ b/src/main/resources/data/beneath/worldgen/placed_feature/sulfur_tuft.json @@ -13,8 +13,7 @@ "predicate": { "type": "would_survive", "state": { - "Name": "beneath:mushroom/sulfur_tuft", - "Properties": {} + "Name": "beneath:mushroom/sulfur_tuft" } } },