diff --git a/CHANGELOG.md b/CHANGELOG.md index a85dd9a36f..8c5d2fa9d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added - Updated to Minecraft 1.21.1 ([#985](https://github.com/FallingColors/HexMod/pull/985)) @SuperKnux @slava110 +- Added Neural Fiber, a new endgame material harvested from villagers using a modified mindflaying process ([#1292](https://github.com/FallingColors/HexMod/pull/1292)) @Robotgiggle @Falkory220 +- Added Neural Mesh, a multipart block which can be attached to Budding Amethyst to make it grow faster ([#1292](https://github.com/FallingColors/HexMod/pull/1292)) @Robotgiggle +- Added Grand Caster Robes, a hex-based armor set with a variety of abilities ([#1292](https://github.com/FallingColors/HexMod/pull/1292)) @Robotgiggle @Falkory220 + - Provides defense values midway between iron and diamond + - Provides the scrying lens effect, increased ambit, and a casting cost discount + - Allows you to pan the hex grid to fit in significantly more patterns - Added Simulate, which causes the next pattern drawn to be simulated (to check for mishaps) rather than executed ([#1194](https://github.com/FallingColors/HexMod/pull/1194)) @Robotgiggle - Added the `hex_unbreakable` tag for blocks that should be immune to Break Block regardless of the configured mining tier ([#1186](https://github.com/FallingColors/HexMod/pull/1186)) @Robotgiggle @slava110 - Added a new Ancient Cypher hex that impulses nearby items towards the caster ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/neural_fiber.json b/Common/src/generated/resources/assets/hexcasting/models/item/neural_fiber.json new file mode 100644 index 0000000000..0d52422152 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/neural_fiber.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/neural_fiber" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/neural_mesh.json b/Common/src/generated/resources/assets/hexcasting/models/item/neural_mesh.json new file mode 100644 index 0000000000..4f9fe9bf8a --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/neural_mesh.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/neural_mesh" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots.json new file mode 100644 index 0000000000..264198cc15 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "hexcasting:item/robes/boots", + "predicate": { + "hexcasting:variant": 0.0 + } + }, + { + "model": "hexcasting:item/robes/boots_1", + "predicate": { + "hexcasting:variant": 1.0 + } + }, + { + "model": "hexcasting:item/robes/boots_2", + "predicate": { + "hexcasting:variant": 2.0 + } + } + ], + "textures": { + "layer0": "hexcasting:item/robes/0_boots" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots_1.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots_1.json new file mode 100644 index 0000000000..fe6a221473 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/1_boots" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots_2.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots_2.json new file mode 100644 index 0000000000..27a0c192a7 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/boots_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/2_boots" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood.json new file mode 100644 index 0000000000..d2218f4994 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "hexcasting:item/robes/hood", + "predicate": { + "hexcasting:variant": 0.0 + } + }, + { + "model": "hexcasting:item/robes/hood_1", + "predicate": { + "hexcasting:variant": 1.0 + } + }, + { + "model": "hexcasting:item/robes/hood_2", + "predicate": { + "hexcasting:variant": 2.0 + } + } + ], + "textures": { + "layer0": "hexcasting:item/robes/0_hood" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood_1.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood_1.json new file mode 100644 index 0000000000..4631bfe281 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/1_hood" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood_2.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood_2.json new file mode 100644 index 0000000000..0761f55547 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/hood_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/2_hood" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs.json new file mode 100644 index 0000000000..03d57e0536 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "hexcasting:item/robes/legs", + "predicate": { + "hexcasting:variant": 0.0 + } + }, + { + "model": "hexcasting:item/robes/legs_1", + "predicate": { + "hexcasting:variant": 1.0 + } + }, + { + "model": "hexcasting:item/robes/legs_2", + "predicate": { + "hexcasting:variant": 2.0 + } + } + ], + "textures": { + "layer0": "hexcasting:item/robes/0_legs" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs_1.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs_1.json new file mode 100644 index 0000000000..93054eafd4 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/1_legs" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs_2.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs_2.json new file mode 100644 index 0000000000..b5667a0aec --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/legs_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/2_legs" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic.json new file mode 100644 index 0000000000..da671641b8 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "hexcasting:item/robes/tunic", + "predicate": { + "hexcasting:variant": 0.0 + } + }, + { + "model": "hexcasting:item/robes/tunic_1", + "predicate": { + "hexcasting:variant": 1.0 + } + }, + { + "model": "hexcasting:item/robes/tunic_2", + "predicate": { + "hexcasting:variant": 2.0 + } + } + ], + "textures": { + "layer0": "hexcasting:item/robes/0_tunic" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic_1.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic_1.json new file mode 100644 index 0000000000..797dbbc608 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/1_tunic" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic_2.json b/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic_2.json new file mode 100644 index 0000000000..a665bce0cb --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/robes/tunic_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/2_tunic" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/item/staff/neural.json b/Common/src/generated/resources/assets/hexcasting/models/item/staff/neural.json new file mode 100644 index 0000000000..9d11027240 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/item/staff/neural.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld_rod", + "textures": { + "layer0": "hexcasting:item/staff/neural" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/assets/hexcasting/models/staff/neural.json b/Common/src/generated/resources/assets/hexcasting/models/staff/neural.json new file mode 100644 index 0000000000..4890c91a60 --- /dev/null +++ b/Common/src/generated/resources/assets/hexcasting/models/staff/neural.json @@ -0,0 +1,16 @@ +{ + "overrides": [ + { + "model": "hexcasting:item/neural_staff", + "predicate": { + "hexcasting:funny_level": 0.0 + } + }, + { + "model": "hexcasting:item/cherry_staff", + "predicate": { + "hexcasting:funny_level": 2.0 + } + } + ] +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json new file mode 100644 index 0000000000..e2c37e3408 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/boots" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/boots" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json new file mode 100644 index 0000000000..0b7770cf3f --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/hood" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/hood" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json new file mode 100644 index 0000000000..7076892ac0 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/legs" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/legs" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json new file mode 100644 index 0000000000..9e5bac0e88 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/tunic" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/tunic" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json new file mode 100644 index 0000000000..5a76172263 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:neural_mesh" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:neural_mesh" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json new file mode 100644 index 0000000000..c3502060e1 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:charged_amethyst" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:staff/neural" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:staff/neural" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/damage_type/forgot_to_breathe.json b/Common/src/generated/resources/data/hexcasting/damage_type/forgot_to_breathe.json new file mode 100644 index 0000000000..d3a0ca991f --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/damage_type/forgot_to_breathe.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "hexcasting.forgot_to_breathe", + "scaling": "when_caused_by_living_non_player" +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json b/Common/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json new file mode 100644 index 0000000000..49ecc8425a --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json @@ -0,0 +1,106 @@ +{ + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "add": true, + "count": -1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "down": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "up": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "north": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "south": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "west": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "east": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + } + ], + "name": "hexcasting:neural_mesh" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "hexcasting:blocks/neural_mesh" +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/neural_mesh.json b/Common/src/generated/resources/data/hexcasting/recipe/neural_mesh.json new file mode 100644 index 0000000000..b1ae10c52c --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/neural_mesh.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "redstone", + "key": { + "C": { + "item": "hexcasting:neural_fiber" + }, + "D": { + "item": "hexcasting:neural_fiber" + }, + "I": { + "item": "minecraft:bone_block" + } + }, + "pattern": [ + "DCD", + "CIC", + "DCD" + ], + "result": { + "count": 1, + "id": "hexcasting:neural_mesh" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/robes/boots.json b/Common/src/generated/resources/data/hexcasting/recipe/robes/boots.json new file mode 100644 index 0000000000..3c2411b6fc --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/robes/boots.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "B": { + "item": "minecraft:bone" + }, + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + " ", + "B B", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/boots" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/robes/hood.json b/Common/src/generated/resources/data/hexcasting/recipe/robes/hood.json new file mode 100644 index 0000000000..1f2cd42944 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/robes/hood.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "B": { + "item": "minecraft:bone" + }, + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "BFB", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/hood" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/robes/legs.json b/Common/src/generated/resources/data/hexcasting/recipe/robes/legs.json new file mode 100644 index 0000000000..3715882308 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/robes/legs.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "FFF", + "F F", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/legs" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/robes/tunic.json b/Common/src/generated/resources/data/hexcasting/recipe/robes/tunic.json new file mode 100644 index 0000000000..c162bb6405 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/robes/tunic.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "F F", + "FFF", + "FFF" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/tunic" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/staff/neural.json b/Common/src/generated/resources/data/hexcasting/recipe/staff/neural.json new file mode 100644 index 0000000000..a4288d0288 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/staff/neural.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "A": { + "item": "hexcasting:charged_amethyst" + }, + "S": { + "item": "minecraft:stick" + }, + "W": { + "item": "hexcasting:neural_mesh" + } + }, + "pattern": [ + " SA", + " WS", + "S " + ], + "result": { + "count": 1, + "id": "hexcasting:staff/neural" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/tags/item/staves.json b/Common/src/generated/resources/data/hexcasting/tags/item/staves.json index 29f4595c62..c3b2e7c4f8 100644 --- a/Common/src/generated/resources/data/hexcasting/tags/item/staves.json +++ b/Common/src/generated/resources/data/hexcasting/tags/item/staves.json @@ -13,6 +13,7 @@ "hexcasting:staff/cherry", "hexcasting:staff/bamboo", "hexcasting:staff/quenched", - "hexcasting:staff/mindsplice" + "hexcasting:staff/mindsplice", + "hexcasting:staff/neural" ] } \ No newline at end of file diff --git a/Common/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json b/Common/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json index 4209c89aa3..319bb24df4 100644 --- a/Common/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json +++ b/Common/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json @@ -1,5 +1,6 @@ { "values": [ - "hexcasting:overcast" + "hexcasting:overcast", + "hexcasting:forgot_to_breathe" ] } \ No newline at end of file diff --git a/Common/src/generated/resources/data/minecraft/tags/damage_type/bypasses_effects.json b/Common/src/generated/resources/data/minecraft/tags/damage_type/bypasses_effects.json index 4209c89aa3..319bb24df4 100644 --- a/Common/src/generated/resources/data/minecraft/tags/damage_type/bypasses_effects.json +++ b/Common/src/generated/resources/data/minecraft/tags/damage_type/bypasses_effects.json @@ -1,5 +1,6 @@ { "values": [ - "hexcasting:overcast" + "hexcasting:overcast", + "hexcasting:forgot_to_breathe" ] } \ No newline at end of file diff --git a/Common/src/generated/resources/data/minecraft/tags/damage_type/no_knockback.json b/Common/src/generated/resources/data/minecraft/tags/damage_type/no_knockback.json index 4209c89aa3..319bb24df4 100644 --- a/Common/src/generated/resources/data/minecraft/tags/damage_type/no_knockback.json +++ b/Common/src/generated/resources/data/minecraft/tags/damage_type/no_knockback.json @@ -1,5 +1,6 @@ { "values": [ - "hexcasting:overcast" + "hexcasting:overcast", + "hexcasting:forgot_to_breathe" ] } \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java b/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java index c0023ece4f..e25faade11 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java @@ -158,20 +158,6 @@ default FrozenPigment getColorizer(Player player) { return FrozenPigment.DEFAULT.get(); } - ArmorMaterial DUMMY_ARMOR_MATERIAL = new ArmorMaterial( - Collections.emptyMap(), - 0, - SoundEvents.ARMOR_EQUIP_LEATHER, - () -> Ingredient.EMPTY, - Collections.emptyList(), - 0, - 0 - ); - - default ArmorMaterial robesMaterial() { - return DUMMY_ARMOR_MATERIAL; - } - /** * Location in the userdata of the ravenmind */ diff --git a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java index 5a63fdef8a..060dbe5572 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java @@ -51,6 +51,8 @@ public interface ClientConfigAccess { boolean clickingTogglesDrawing(); + int gridPanMouseButton(); + boolean advancedTooltipsShowsIotaNBT(); boolean staticActiveSlates(); @@ -61,6 +63,7 @@ public interface ClientConfigAccess { boolean DEFAULT_INVERT_ABACUS_SCROLL = false; double DEFAULT_GRID_SNAP_THRESHOLD = 0.5; boolean DEFAULT_CLICKING_TOGGLES_DRAWING = false; + int DEFAULT_GRID_PAN_MOUSE_BUTTON = 1; boolean DEFAULT_ADVANCED_TOOLTIPS_SHOWS_IOTA_NBT = false; boolean DEFAULT_STATIC_ACTIVE_SLATES = false; } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt b/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt index fdd0e828ba..a8c383416d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt @@ -10,13 +10,17 @@ import at.petrak.hexcasting.api.casting.math.HexCoord import at.petrak.hexcasting.api.casting.validateSubIotas import at.petrak.hexcasting.api.mod.HexTags import com.mojang.datafixers.util.Function6 +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder import net.minecraft.ChatFormatting import net.minecraft.core.HolderLookup import net.minecraft.core.Registry import net.minecraft.nbt.* +import net.minecraft.network.RegistryFriendlyByteBuf import net.minecraft.network.chat.Component import net.minecraft.network.chat.MutableComponent import net.minecraft.network.chat.Style +import net.minecraft.network.codec.ByteBufCodecs import net.minecraft.network.codec.StreamCodec import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation @@ -61,14 +65,24 @@ fun vecFromNBT(tag: CompoundTag): Vec3 { Vec3(tag.getDouble("x"), tag.getDouble("y"), tag.getDouble("z")) } -fun Vec2.serializeToNBT(): LongArrayTag = - LongArrayTag(longArrayOf(this.x.toDouble().toRawBits(), this.y.toDouble().toRawBits())) +fun Vec2.serializeToNBT(): CompoundTag { + val tag = CompoundTag() + tag.putFloat("x", this.x) + tag.putFloat("y", this.y) + return tag +} fun vec2FromNBT(tag: LongArray): Vec2 = if (tag.size != 2) Vec2.ZERO else Vec2( Double.fromBits(tag[0]).toFloat(), Double.fromBits(tag[1]).toFloat(), ) +fun vec2FromNBT(tag: CompoundTag): Vec2 { + return if (!tag.contains("x") || !tag.contains("y")) + Vec2.ZERO + else + Vec2(tag.getFloat("x"), tag.getFloat("y")) +} fun otherHand(hand: InteractionHand) = if (hand == InteractionHand.MAIN_HAND) InteractionHand.OFF_HAND else InteractionHand.MAIN_HAND @@ -333,6 +347,20 @@ fun validateIotaList(iotaList: TreeList, serverLevel: ServerLevel) return iotaList.map { validateIota(it, serverLevel) } } +// why is there not already a codec defined for vec2 +@JvmField +val VEC2_CODEC: Codec = RecordCodecBuilder.create({ instance -> + instance.group( + Codec.FLOAT.fieldOf("x").forGetter { it.x }, + Codec.FLOAT.fieldOf("y").forGetter { it.y } + ).apply(instance, ::Vec2) +}).orElseGet({ Vec2.ZERO }) +@JvmField +val VEC2_STREAM_CODEC: StreamCodec = StreamCodec.composite( + ByteBufCodecs.FLOAT, Vec2::x, + ByteBufCodecs.FLOAT, Vec2::y, + ::Vec2 +) // vanilla's StreamCodec.composite() only supports up to six fields in 1.21 fun compositeCodecSeven( diff --git a/Common/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java b/Common/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java index 0fcaac0f46..c819d3fc3a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java @@ -67,6 +67,10 @@ public static void init() { registerVariantOverrides(HexItems.CYPHER.get(), HexItems.CYPHER.get()::getVariant); registerVariantOverrides(HexItems.TRINKET.get(), HexItems.TRINKET.get()::getVariant); registerVariantOverrides(HexItems.ARTIFACT.get(), HexItems.ARTIFACT.get()::getVariant); + registerVariantOverrides(HexItems.ROBES_HOOD.get(), HexItems.ROBES_HOOD.get()::getVariant); + registerVariantOverrides(HexItems.ROBES_TUNIC.get(), HexItems.ROBES_TUNIC.get()::getVariant); + registerVariantOverrides(HexItems.ROBES_LEGS.get(), HexItems.ROBES_LEGS.get()::getVariant); + registerVariantOverrides(HexItems.ROBES_BOOTS.get(), HexItems.ROBES_BOOTS.get()::getVariant); IClientXplatAbstractions.INSTANCE.registerItemProperty(HexItems.THOUGHT_KNOT.get(), ItemThoughtKnot.WRITTEN_PRED, (stack, level, holder, holderID) -> { if (stack.has(HexDataComponents.IOTA_HOLDER_IOTA.get())) { @@ -110,6 +114,7 @@ public static void init() { registerWandOverrides(HexItems.STAFF_EDIFIED.get()); // purposely skip quenched registerWandOverrides(HexItems.STAFF_MINDSPLICE.get()); + registerWandOverrides(HexItems.STAFF_NEURAL.get()); registerGaslight4(HexItems.STAFF_QUENCHED.get()); registerGaslight4(HexBlocks.QUENCHED_ALLAY.get().asItem()); @@ -124,6 +129,7 @@ public static void init() { x.setRenderLayer(HexBlocks.EDIFIED_TRAPDOOR.get(), RenderType.cutout()); x.setRenderLayer(HexBlocks.AKASHIC_BOOKSHELF.get(), RenderType.cutout()); x.setRenderLayer(HexBlocks.SCONCE.get(), RenderType.cutout()); + x.setRenderLayer(HexBlocks.NEURAL_MESH.get(), RenderType.cutout()); x.setRenderLayer(HexBlocks.AMETHYST_EDIFIED_LEAVES.get(), RenderType.cutoutMipped()); x.setRenderLayer(HexBlocks.AVENTURINE_EDIFIED_LEAVES.get(), RenderType.cutoutMipped()); diff --git a/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt b/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt index bf29700dbe..deb3a3584a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt @@ -1,5 +1,6 @@ package at.petrak.hexcasting.client.gui +import at.petrak.hexcasting.api.HexAPI import at.petrak.hexcasting.api.casting.eval.ExecutionClientView import at.petrak.hexcasting.api.casting.eval.ResolvedPattern import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType @@ -17,16 +18,19 @@ import at.petrak.hexcasting.client.ShiftScrollListener import at.petrak.hexcasting.client.ktxt.accumulatedScroll import at.petrak.hexcasting.client.render.* import at.petrak.hexcasting.client.sound.GridSoundInstance +import at.petrak.hexcasting.common.items.armor.ItemRobes import at.petrak.hexcasting.common.lib.HexAttributes import at.petrak.hexcasting.common.lib.HexSounds import at.petrak.hexcasting.common.lib.hex.HexActions import at.petrak.hexcasting.common.msgs.MsgNewSpellPatternC2S +import at.petrak.hexcasting.common.msgs.MsgPannedGridC2S import at.petrak.hexcasting.xplat.IClientXplatAbstractions import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.client.Minecraft import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.screens.Screen +import net.minecraft.client.player.LocalPlayer import net.minecraft.client.renderer.GameRenderer import net.minecraft.client.resources.sounds.SimpleSoundInstance import net.minecraft.client.resources.sounds.SoundInstance @@ -44,6 +48,7 @@ class GuiSpellcasting constructor( private var cachedStack: List, private var cachedRavenmind: Iota?, private var parenCount: Int, + private var panOffset: Vec2, ) : Screen("gui.hexcasting.spellcasting".asTranslatedComponent) { private var stackDescs: List = listOf() private var parenDescs: List = listOf() @@ -52,6 +57,10 @@ class GuiSpellcasting constructor( private var drawState: PatternDrawState = PatternDrawState.BetweenPatterns private val usedSpots: MutableSet = HashSet() + private var panningAllowed = false + private var prevPanOffset = panOffset + private val bgLocation = HexAPI.modLoc("textures/gui/casting_bg.png") + private var ambianceSoundInstance: GridSoundInstance? = null private val randSrc = SoundInstance.createUnseededRandom() @@ -63,6 +72,25 @@ class GuiSpellcasting constructor( this.calculateIotaDisplays() } + fun getPanDistance(): Float { + return panOffset.length() / 20 + } + + fun syncPanOffset() { + if (panOffset != prevPanOffset || ClientTickCounter.ticksInGame % 10 == 0L) { + IClientXplatAbstractions.INSTANCE.sendPacketToServer(MsgPannedGridC2S(panOffset)) + prevPanOffset = panOffset + } + } + + fun validatePanAbility(player: LocalPlayer) { + panningAllowed = ItemRobes.isWearingFullSet(player) + if (!panningAllowed && panOffset != Vec2.ZERO) { + panOffset = Vec2.ZERO + syncPanOffset() + } + } + fun recvServerUpdate(info: ExecutionClientView, index: Int) { if (info.isStackClear) { this.minecraft?.setScreen(null) @@ -128,6 +156,7 @@ class GuiSpellcasting constructor( if (player != null) { this.ambianceSoundInstance = GridSoundInstance(player) soundManager.play(this.ambianceSoundInstance!!) + this.validatePanAbility(player) } this.calculateIotaDisplays() @@ -140,6 +169,10 @@ class GuiSpellcasting constructor( val heldItem = player.getItemInHand(handOpenedWith) if (heldItem.isEmpty || !heldItem.`is`(HexTags.Items.STAVES) || player.getAttributeValue(HexAttributes.FEEBLE_MIND) > 0) closeForReal() + validatePanAbility(player) + if (this.panningAllowed) { + syncPanOffset() + } } } @@ -147,6 +180,8 @@ class GuiSpellcasting constructor( if (super.mouseClicked(mxOut, myOut, pButton)) { return true } + if (pButton == HexConfig.client().gridPanMouseButton() && this.panningAllowed) + return false if (HexConfig.client().clickingTogglesDrawing()) { return if (this.drawState is PatternDrawState.BetweenPatterns) drawStart(mxOut, myOut) @@ -189,14 +224,29 @@ class GuiSpellcasting constructor( } override fun mouseDragged(mxOut: Double, myOut: Double, pButton: Int, pDragX: Double, pDragY: Double): Boolean { - if (super.mouseDragged(mxOut, myOut, pButton, pDragX, pDragY)) { + if (super.mouseDragged(mxOut, myOut, pButton, pDragX, pDragY)) return true + if (pButton == HexConfig.client().gridPanMouseButton() + && this.drawState is PatternDrawState.BetweenPatterns + && this.panningAllowed + ) { + return panGrid(pDragX, pDragY) } if (HexConfig.client().clickingTogglesDrawing()) return false return drawMove(mxOut, myOut) } + private fun panGrid(pDragX: Double, pDragY: Double): Boolean { + val shift = Vec2(pDragX.toFloat(), pDragY.toFloat()) + val newOffset = this.panOffset.add(shift) + if (newOffset.lengthSquared() < 900*900) + this.panOffset = newOffset + else + this.panOffset = newOffset.normalized().scale(900f); + return false; + } + private fun drawMove(mxOut: Double, myOut: Double): Boolean { val mx = Mth.clamp(mxOut, 0.0, this.width.toDouble()) val my = Mth.clamp(myOut, 0.0, this.height.toDouble()) @@ -276,6 +326,8 @@ class GuiSpellcasting constructor( } if (HexConfig.client().clickingTogglesDrawing()) return false + if (pButton == HexConfig.client().gridPanMouseButton() && this.panningAllowed) + return false return drawEnd() } @@ -358,6 +410,12 @@ class GuiSpellcasting constructor( super.onClose() } + override fun renderBackground(guiGraphics: GuiGraphics, i: Int, j: Int, f: Float) { + guiGraphics.setColor(1f,1f,1f, (getPanDistance() / 15).coerceAtMost(1f)) + renderMenuBackgroundTexture(guiGraphics, bgLocation, 0, 0, 0f, 0f, this.width, this.height) + guiGraphics.setColor(1f, 1f, 1f, 1f) + this.renderBlurredBackground(f) + } override fun render(graphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { super.render(graphics, pMouseX, pMouseY, pPartialTick) @@ -405,12 +463,13 @@ class GuiSpellcasting constructor( for ((idx, elts) in this.patterns.withIndex()) { val (pat, origin, valid) = elts + val points = pat.toLines(this.hexSize(), this.coordToPx(origin)) + val center = Vec2(graphics.guiWidth() / 2f, graphics.guiHeight() / 2f) + if (points.all{ point -> point.distanceToSqr(center) > center.lengthSquared()+2500 }) + continue // don't render the pattern if it's completely offscreen drawPatternFromPoints( mat, - pat.toLines( - this.hexSize(), - this.coordToPx(origin) - ), + points, findDupIndices(pat.positions()), true, valid.color or (0xC8 shl 24), @@ -532,7 +591,7 @@ class GuiSpellcasting constructor( return (baseScale / scaleModifier).toFloat() } - fun coordsOffset(): Vec2 = Vec2(this.width.toFloat() * 0.5f, this.height.toFloat() * 0.5f) + fun coordsOffset(): Vec2 = Vec2(this.width.toFloat() * 0.5f, this.height.toFloat() * 0.5f).add(this.panOffset) fun coordToPx(coord: HexCoord) = at.petrak.hexcasting.api.utils.coordToPx(coord, this.hexSize(), this.coordsOffset()) @@ -541,7 +600,7 @@ class GuiSpellcasting constructor( private sealed class PatternDrawState { - /** We're waiting on the player to right-click again */ + /** We're waiting on the player to left-click again */ object BetweenPatterns : PatternDrawState() /** We just started drawing and haven't drawn the first line yet. */ diff --git a/Common/src/main/java/at/petrak/hexcasting/client/model/HexModelLayers.java b/Common/src/main/java/at/petrak/hexcasting/client/model/HexModelLayers.java index 11dc412327..eeeee86310 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/model/HexModelLayers.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/model/HexModelLayers.java @@ -13,7 +13,9 @@ public class HexModelLayers { public static final ModelLayerLocation ALTIORA = make("altiora"); - public static final ModelLayerLocation ROBES = make("robes"); + public static final ModelLayerLocation ROBES_0 = make("robes_0"); + public static final ModelLayerLocation ROBES_1 = make("robes_1"); + public static final ModelLayerLocation ROBES_2 = make("robes_2"); private static ModelLayerLocation make(String name) { return make(name, "main"); @@ -29,6 +31,8 @@ private static ModelLayerLocation make(String name, String layer) { // https://github.com/VazkiiMods/Botania/blob/1.19.x/Xplat/src/main/java/vazkii/botania/client/model/BotaniaLayerDefinitions.java public static void init(BiConsumer> consumer) { consumer.accept(ALTIORA, ElytraModel::createLayer); - consumer.accept(ROBES, HexRobesModels::variant1); + consumer.accept(ROBES_0, HexRobesModel::variant0); + consumer.accept(ROBES_1, HexRobesModel::variant1); + consumer.accept(ROBES_2, HexRobesModel::variant2); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModel.java b/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModel.java new file mode 100644 index 0000000000..c9c24a28dc --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModel.java @@ -0,0 +1,315 @@ +package at.petrak.hexcasting.client.model; + +// Made with Blockbench 4.6.1 +// Exported for Minecraft version 1.17 or later with Mojang mappings +// Paste this class into your mod and generate all required imports + +import at.petrak.hexcasting.api.HexAPI; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.model.HumanoidArmorModel; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; + +public class HexRobesModel extends HumanoidArmorModel { + // This layer location should be baked with EntityRendererProvider.Context in the entity renderer and passed into + // this model's constructor + // public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(modLoc("robes"), "main"); + + final EquipmentSlot slot; + + public final ModelPart head; + public final ModelPart body; + public final ModelPart rightArm; + public final ModelPart leftArm; + public final ModelPart rightLeg; + public final ModelPart leftLeg; + + public HexRobesModel(ModelPart root, EquipmentSlot slot) { + super(root); + this.slot = slot; + + this.head = root.getChild("head"); + this.body = root.getChild("body"); + this.rightArm = root.getChild("right_arm"); + this.leftArm = root.getChild("left_arm"); + this.rightLeg = root.getChild("right_leg"); + this.leftLeg = root.getChild("left_leg"); + } + + public static LayerDefinition variant0() { + MeshDefinition meshdef = new MeshDefinition(); + PartDefinition root = meshdef.getRoot(); + + root.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO); + + var head = root.addOrReplaceChild("head", CubeListBuilder.create(), PartPose.ZERO); + + head.addOrReplaceChild("hood", + CubeListBuilder.create() + .texOffs(0, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.3F)) + .texOffs(0, 16).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.4F)), + PartPose.offset(4.0F, -8.0F, -4.0F)); + + head.addOrReplaceChild("horns", + CubeListBuilder.create() + .texOffs(24, 0).addBox(8.5F, 0.0F, 0.0F, 8.0F, 4.0F, 0.0F, new CubeDeformation(0.3F)) + .texOffs(24, 0).mirror().addBox(-7F, 0.0F, 0.0F, 8.0F, 4.0F, 0.0F, new CubeDeformation(0.3F)) + .mirror(false), + PartPose.offset(-4.8F, -8.2F, 0.0F)); + + var body = root.addOrReplaceChild("body", CubeListBuilder.create(), PartPose.ZERO); + + body.addOrReplaceChild("tunic", + CubeListBuilder.create() + .texOffs(40, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)) + .texOffs(40, 16).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)), + PartPose.offset(4.0F, 0.0F, -2.0F)); + + var rightArm = root.addOrReplaceChild("right_arm", CubeListBuilder.create(), PartPose.ZERO); + + rightArm.addOrReplaceChild("right_sleeve", + CubeListBuilder.create() + .texOffs(0, 32).addBox(0.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(-3.0F, -2.0F, -2.0F)); + + var leftArm = root.addOrReplaceChild("left_arm", CubeListBuilder.create(), PartPose.ZERO); + + leftArm.addOrReplaceChild("left_sleeve", + CubeListBuilder.create() + .texOffs(0, 32).mirror().addBox(0, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)) + .mirror(false), + PartPose.offset(-1.0F, -2.0F, -2.0F)); + + var rightLeg = root.addOrReplaceChild("right_leg", CubeListBuilder.create(), PartPose.ZERO); + + PartDefinition Right_r1 = rightLeg.addOrReplaceChild("right_skirt", + CubeListBuilder.create() + .texOffs(48, 32).mirror().addBox(-2.2F, -0.5F, -6.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)) + .mirror(false), + PartPose.offsetAndRotation(0.0F, 0.0F, 4.0F, 0.0F, 0.0F, 0.1309F)); + + rightLeg.addOrReplaceChild("right_boot", + CubeListBuilder.create() + .texOffs(16, 41).addBox(-4.0F, 0.0F, 0.0F, 4.0F, 3.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(2.0F, 9.0F, -2.0F)); + + var leftLeg = root.addOrReplaceChild("left_leg", CubeListBuilder.create(), PartPose.ZERO); + + PartDefinition Left_r1 = leftLeg.addOrReplaceChild("left_skirt", + CubeListBuilder.create() + .texOffs(48, 32).addBox(-1.8F, -0.5F, -6.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)), + PartPose.offsetAndRotation(0.0F, 0.0F, 4.0F, 0.0F, 0.0F, -0.1309F)); + + leftLeg.addOrReplaceChild("left_boot", + CubeListBuilder.create() + .texOffs(16, 41).addBox(0.0F, 0.0F, 0.0F, 4.0F, 3.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(-2.0F, 9.0F, -2.0F)); + + return LayerDefinition.create(meshdef, 64, 64); + } + + public static LayerDefinition variant1() { + MeshDefinition meshdef = new MeshDefinition(); + PartDefinition root = meshdef.getRoot(); + + root.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO); + + var head = root.addOrReplaceChild("head", CubeListBuilder.create(), PartPose.ZERO); + + head.addOrReplaceChild("hood", + CubeListBuilder.create() + .texOffs(0, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.3F)) + .texOffs(0, 16).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.4F)), + PartPose.offset(4.0F, -8.0F, -4.0F)); + + head.addOrReplaceChild("right_horn", + CubeListBuilder.create() + .texOffs(24, 0).addBox(-4.0F, -2.0F, 0.0F, 8.0F, 4.0F, 0.0F, new CubeDeformation(0.0F)), + PartPose.offsetAndRotation(4.25F, -12.25F, 0.0F, 0.0F, 0.0F, -1.5708F)); + + head.addOrReplaceChild("left_horn", + CubeListBuilder.create() + .texOffs(24, 0).mirror().addBox(-4.0F, -2.0F, 0.0F, 8.0F, 4.0F, 0.0F, new CubeDeformation(0.0F)) + .mirror(false), + PartPose.offsetAndRotation(-4.25F, -12.25F, 0.0F, 0.0F, 0.0F, 1.5708F)); + + var body = root.addOrReplaceChild("body", CubeListBuilder.create(), PartPose.ZERO); + + body.addOrReplaceChild("tunic", + CubeListBuilder.create() + .texOffs(40, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)) + .texOffs(40, 16).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)), + PartPose.offset(4.0F, 0.0F, -2.0F)); + + var rightArm = root.addOrReplaceChild("right_arm", CubeListBuilder.create(), PartPose.ZERO); + + rightArm.addOrReplaceChild("right_sleeve", + CubeListBuilder.create() + .texOffs(0, 32).addBox(0.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(-3.0F, -2.0F, -2.0F)); + + var leftArm = root.addOrReplaceChild("left_arm", CubeListBuilder.create(), PartPose.ZERO); + + leftArm.addOrReplaceChild("left_sleeve", + CubeListBuilder.create() + .texOffs(0, 32).mirror().addBox(0, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)) + .mirror(false), + PartPose.offset(-1.0F, -2.0F, -2.0F)); + + var rightLeg = root.addOrReplaceChild("right_leg", CubeListBuilder.create(), PartPose.ZERO); + + rightLeg.addOrReplaceChild("right_skirt", + CubeListBuilder.create() + .texOffs(48, 32).mirror().addBox(-4.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)) + .mirror(false), + PartPose.offset(2.0F, 0.0F, -2.0F)); + + rightLeg.addOrReplaceChild("right_boot", + CubeListBuilder.create() + .texOffs(16, 40).addBox(-4.0F, 8.0F, 0.0F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(2.0F, 0.0F, -2.0F)); + + var leftLeg = root.addOrReplaceChild("left_leg", CubeListBuilder.create(), PartPose.ZERO); + + leftLeg.addOrReplaceChild("left_skirt", + CubeListBuilder.create() + .texOffs(48, 32).addBox(-4.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)), + PartPose.offset(2.0F, 0.0F, -2.0F)); + + leftLeg.addOrReplaceChild("left_boot", + CubeListBuilder.create() + .texOffs(16, 40).addBox(-4.0F, 8.0F, 0.0F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(2.0F, 0.0F, -2.0F)); + + return LayerDefinition.create(meshdef, 64, 64); + } + + public static LayerDefinition variant2() { + MeshDefinition meshdef = new MeshDefinition(); + PartDefinition root = meshdef.getRoot(); + + root.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO); + + var head = root.addOrReplaceChild("head", CubeListBuilder.create(), PartPose.ZERO); + + head.addOrReplaceChild("hood", + CubeListBuilder.create() + .texOffs(0, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.3F)) + .texOffs(0, 16).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.4F)), + PartPose.offset(4.0F, -8.0F, -4.0F)); + + head.addOrReplaceChild("right_horn", + CubeListBuilder.create() + .texOffs(24, 0).mirror().addBox(-7.0F, -4.0F, 0.0F, 8.0F, 8.0F, 0.0F, new CubeDeformation(0.3F, 0.3F, 0.0F)) + .mirror(false), + PartPose.offsetAndRotation(-5.0F, -8.7F, 0.0F, 0.0F, 0.0F, 1.309F)); + + head.addOrReplaceChild("left_horn", + CubeListBuilder.create() + .texOffs(24, 0).addBox(-1.0F, -4.0F, 0.0F, 8.0F, 8.0F, 0.0F, new CubeDeformation(0.3F, 0.3F, 0.0F)), + PartPose.offsetAndRotation(5.0F, -8.7F, 0.0F, 0.0F, 0.0F, -1.309F)); + + var body = root.addOrReplaceChild("body", CubeListBuilder.create(), PartPose.ZERO); + + body.addOrReplaceChild("tunic", + CubeListBuilder.create() + .texOffs(40, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)) + .texOffs(40, 16).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)), + PartPose.offset(4.0F, 0.0F, -2.0F)); + + var sash = body.addOrReplaceChild("sash", + CubeListBuilder.create() + .texOffs(32, 48).mirror().addBox(7.4F, -3.9F, 0.0F, 3.0F, 3.0F, 6.0F, new CubeDeformation(0.1F)) + .mirror(false), + PartPose.offset(-5.45F, 10.8F, -3.0F)); + + sash.addOrReplaceChild("strap", + CubeListBuilder.create() + .texOffs(0, 48).mirror().addBox(-0.95F, -13.2F, -3.0F, 10.0F, 3.0F, 6.0F, new CubeDeformation(0.0F)) + .mirror(false), + PartPose.offsetAndRotation(6.2F, 11.45F, 3.0F, 0.0F, 0.0F, -0.3927F)); + + var rightArm = root.addOrReplaceChild("right_arm", CubeListBuilder.create(), PartPose.ZERO); + + rightArm.addOrReplaceChild("right_sleeve", + CubeListBuilder.create() + .texOffs(0, 32).addBox(0.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(-3.0F, -2.0F, -2.0F)); + + var leftArm = root.addOrReplaceChild("left_arm", CubeListBuilder.create(), PartPose.ZERO); + + leftArm.addOrReplaceChild("left_sleeve", + CubeListBuilder.create() + .texOffs(0, 32).mirror().addBox(0, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.3F)) + .mirror(false), + PartPose.offset(-1.0F, -2.0F, -2.0F)); + + var rightLeg = root.addOrReplaceChild("right_leg", CubeListBuilder.create(), PartPose.ZERO); + + rightLeg.addOrReplaceChild("right_skirt", + CubeListBuilder.create() + .texOffs(48, 32).addBox(-4.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.35F)), + PartPose.offset(2.0F, 0.0F, -2.0F)); + + rightLeg.addOrReplaceChild("right_boot", + CubeListBuilder.create() + .texOffs(16, 40).addBox(-4.0F, 8.0F, 0.0F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(2.0F, 0.0F, -2.0F)); + + var leftLeg = root.addOrReplaceChild("left_leg", CubeListBuilder.create(), PartPose.ZERO); + + leftLeg.addOrReplaceChild("left_skirt", + CubeListBuilder.create() + .texOffs(48, 32).mirror().addBox(-4.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.35F)) + .mirror(false), + PartPose.offset(2.0F, 0.0F, -2.0F)); + + leftLeg.addOrReplaceChild("left_boot", + CubeListBuilder.create() + .texOffs(16, 40).addBox(-4.0F, 8.0F, 0.0F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.3F)), + PartPose.offset(2.0F, 0.0F, -2.0F)); + + return LayerDefinition.create(meshdef, 64, 64); + } + + @Override + public void renderToBuffer(PoseStack ms, VertexConsumer buffer, int light, int overlay, int color) { + renderArmorPart(slot); + super.renderToBuffer(ms, buffer, light, overlay, color); + } + + private void renderArmorPart(EquipmentSlot slot) { + setAllVisible(false); + rightLeg.getChild("right_skirt").visible = false; + leftLeg.getChild("left_skirt").visible = false; + rightLeg.getChild("right_boot").visible = false; + leftLeg.getChild("left_boot").visible = false; + + switch (slot) { + case HEAD -> head.visible = true; + case CHEST -> { + body.visible = true; + rightArm.visible = true; + leftArm.visible = true; + } + case LEGS -> { + rightLeg.visible = true; + leftLeg.visible = true; + rightLeg.getChild("right_skirt").visible = true; + leftLeg.getChild("left_skirt").visible = true; + } + case FEET -> { + rightLeg.visible = true; + leftLeg.visible = true; + rightLeg.getChild("right_boot").visible = true; + leftLeg.getChild("left_boot").visible = true; + } + case MAINHAND, OFFHAND -> { + } + } + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModels.java b/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModels.java deleted file mode 100644 index 7f35494cab..0000000000 --- a/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModels.java +++ /dev/null @@ -1,70 +0,0 @@ -package at.petrak.hexcasting.client.model; - -// Made with Blockbench 4.6.1 -// Exported for Minecraft version 1.17 or later with Mojang mappings -// Paste this class into your mod and generate all required imports - -import net.minecraft.client.model.geom.ModelLayerLocation; -import net.minecraft.client.model.geom.PartPose; -import net.minecraft.client.model.geom.builders.*; - -import static at.petrak.hexcasting.api.HexAPI.modLoc; - -public class HexRobesModels { - // This layer location should be baked with EntityRendererProvider.Context in the entity renderer and passed into - // this model's constructor - public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(modLoc("robes"), "main"); - - public static LayerDefinition variant1() { - MeshDefinition meshdefinition = new MeshDefinition(); - PartDefinition partdefinition = meshdefinition.getRoot(); - - PartDefinition Hood = partdefinition.addOrReplaceChild("Hood", - CubeListBuilder.create() - .texOffs(0, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.0F)) - .texOffs(0, 16).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.0F)), - PartPose.offset(4.0F, -8.0F, -4.0F)); - - PartDefinition Horns = partdefinition.addOrReplaceChild("Horns", - CubeListBuilder.create() - .texOffs(24, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 4.0F, 0.0F, new CubeDeformation(0.0F)) - .texOffs(24, 0).mirror().addBox(9.5F, 0.0F, 0.0F, 8.0F, 4.0F, 0.0F, new CubeDeformation(0.0F)) - .mirror(false), - PartPose.offset(-4.8F, -8.2F, 0.0F)); - - PartDefinition Torso = partdefinition.addOrReplaceChild("Torso", - CubeListBuilder.create() - .texOffs(40, 0).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)) - .texOffs(40, 16).addBox(-8.0F, 0.0F, 0.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)), - PartPose.offset(4.0F, 0.0F, -2.0F)); - - PartDefinition Arms = partdefinition.addOrReplaceChild("Arms", - CubeListBuilder.create() - .texOffs(0, 32).addBox(-4.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)) - .texOffs(0, 32).mirror().addBox(8.0F, 0.0F, 0.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)) - .mirror(false), - PartPose.offset(-4.0F, 0.0F, -2.0F)); - - PartDefinition Skirt = partdefinition.addOrReplaceChild("Skirt", CubeListBuilder.create(), - PartPose.offset(0.0F, 12.0F, -2.0F)); - - PartDefinition Left_r1 = Skirt.addOrReplaceChild("Left_r1", - CubeListBuilder.create() - .texOffs(48, 32).mirror().addBox(0.1F, 0.0F, -4.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)) - .mirror(false), - PartPose.offsetAndRotation(0.0F, 0.0F, 4.0F, 0.0F, 0.0F, -0.1309F)); - - PartDefinition Right_r1 = Skirt.addOrReplaceChild("Right_r1", - CubeListBuilder.create() - .texOffs(48, 32).addBox(-4.0F, 0.0F, -4.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)), - PartPose.offsetAndRotation(0.0F, 0.0F, 4.0F, 0.0F, 0.0F, 0.1309F)); - - PartDefinition Legs = partdefinition.addOrReplaceChild("Legs", - CubeListBuilder.create().texOffs(16, 41) - .addBox(-4.0F, 0.0F, 0.0F, 4.0F, 3.0F, 4.0F, new CubeDeformation(0.0F)) - .texOffs(16, 41).addBox(0.0F, 0.0F, 0.0F, 4.0F, 3.0F, 4.0F, new CubeDeformation(0.0F)), - PartPose.offset(0.0F, 21.0F, -2.0F)); - - return LayerDefinition.create(meshdefinition, 64, 64); - } -} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/particles/ConjureParticle.java b/Common/src/main/java/at/petrak/hexcasting/client/particles/ConjureParticle.java index 9f0ae031a3..cea627e759 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/particles/ConjureParticle.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/particles/ConjureParticle.java @@ -88,6 +88,25 @@ public Particle createParticle(ConjureParticleOptions type, ClientLevel level, } } + // the code in LivingEntity that creates status effect particles hardcodes their velocity to (1,1,1) for some reason + // all the vanilla particles *used* for status effects have custom providers which completely ignore that velocity + // so we need to do that too, otherwise the particles just shoot off in a diagonal line + public static class StatusEffectProvider implements ParticleProvider { + private final SpriteSet sprite; + + public StatusEffectProvider(SpriteSet pSprites) { + this.sprite = pSprites; + } + + @Nullable + @Override + public Particle createParticle(ConjureParticleOptions type, ClientLevel level, + double pX, double pY, double pZ, + double pXSpeed, double pYSpeed, double pZSpeed) { + return new ConjureParticle(level, pX, pY, pZ, 0, 0, 0, this.sprite, type.color()); + } + } + // https://github.com/VazkiiMods/Botania/blob/db85d778ab23f44c11181209319066d1f04a9e3d/Xplat/src/main/java/vazkii/botania/client/fx/FXWisp.java private record ConjureRenderType() implements ParticleRenderType { @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/BlockNeuralMesh.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/BlockNeuralMesh.java new file mode 100644 index 0000000000..76e97d16ee --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/BlockNeuralMesh.java @@ -0,0 +1,72 @@ +package at.petrak.hexcasting.common.blocks; + +import at.petrak.hexcasting.common.lib.HexBlocks; +import at.petrak.hexcasting.common.lib.HexItems; +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; + +public class BlockNeuralMesh extends MultifaceBlock { + public static final MapCodec CODEC = simpleCodec(BlockNeuralMesh::new); + + public MapCodec codec() { + return CODEC; + } + + public BlockNeuralMesh(BlockBehaviour.Properties arg) { + super(arg); + } + + @Override + public MultifaceSpreader getSpreader() { + throw new UnsupportedOperationException("Neural mesh is not capable of spreading"); + } + + @Override + protected boolean canBeReplaced(BlockState blockState, BlockPlaceContext blockPlaceContext) { + return blockPlaceContext.getItemInHand().is(HexItems.NEURAL_MESH.get()); + } + + @Override + protected void randomTick(BlockState blockState, ServerLevel serverLevel, BlockPos blockPos, RandomSource randomSource) { + for (var dir : availableFaces(blockState)) { + BlockPos targetPos = blockPos.relative(dir); + BlockState targetState = serverLevel.getBlockState(targetPos); + if (targetState.is(Blocks.BUDDING_AMETHYST)) { + targetState.randomTick(serverLevel, targetPos, randomSource); + } + } + } + + @Override + protected BlockState updateShape(BlockState blockState, Direction direction, BlockState blockState2, LevelAccessor levelAccessor, BlockPos blockPos, BlockPos blockPos2) { + if (!hasAnyFace(blockState)) { + return Blocks.AIR.defaultBlockState(); + } else { + if (hasFace(blockState, direction) && !canAttachTo(levelAccessor, direction, blockPos2, blockState2)) { + var resultState = removeFace(blockState, getFaceProperty(direction)); + if (resultState.is(HexBlocks.NEURAL_MESH.get()) && levelAccessor instanceof Level level) { + popResource(level, blockPos, new ItemStack(HexItems.NEURAL_MESH.get())); + } + return resultState; + } + return blockState; + } + } + + // this is private in MultifaceBlock so here's a reimpl + private static BlockState removeFace(BlockState blockState, BooleanProperty booleanProperty) { + BlockState blockState2 = blockState.setValue(booleanProperty, false); + return hasAnyFace(blockState2) ? blockState2 : Blocks.AIR.defaultBlockState(); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt index e4ff09fdc2..9f54c6cca1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt @@ -8,11 +8,15 @@ import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.getMob import at.petrak.hexcasting.api.casting.getVec3 import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.casting.mishaps.Mishap import at.petrak.hexcasting.api.casting.mishaps.MishapAlreadyBrainswept import at.petrak.hexcasting.api.casting.mishaps.MishapBadBrainsweep import at.petrak.hexcasting.api.casting.mishaps.MishapBadLocation +import at.petrak.hexcasting.api.misc.MediaConstants import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexTags +import at.petrak.hexcasting.common.lib.HexDamageTypes +import at.petrak.hexcasting.common.lib.HexMobEffects import at.petrak.hexcasting.common.recipe.BrainsweepRecipe import at.petrak.hexcasting.common.recipe.HexRecipeStuffRegistry import at.petrak.hexcasting.ktxt.tellWitnessesThatIWasMurdered @@ -21,8 +25,12 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions import net.minecraft.core.BlockPos import net.minecraft.sounds.SoundEvents import net.minecraft.sounds.SoundSource +import net.minecraft.world.effect.MobEffectInstance import net.minecraft.world.entity.Mob +import net.minecraft.world.entity.npc.AbstractVillager import net.minecraft.world.entity.npc.Villager +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.Blocks import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.phys.Vec3 @@ -52,6 +60,17 @@ object OpBrainsweep : SpellAction { if (IXplatAbstractions.INSTANCE.isBrainswept(sacrifice)) throw MishapAlreadyBrainswept(sacrifice) + // special behavior for crystallization + if (vecPos.closerThan(sacrifice.eyePosition, 0.1) + && sacrifice.hasEffect(HexMobEffects.ENLARGE_GRID) + && sacrifice is AbstractVillager) { + return SpellAction.Result( + AltSpell(sacrifice, pos), + MediaConstants.CRYSTAL_UNIT * 10, + listOf(ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0)) + ) + } + val state = env.world.getBlockState(pos) val recman = env.world.recipeManager @@ -89,4 +108,26 @@ object OpBrainsweep : SpellAction { env.world.playSound(null, sacrifice, SoundEvents.PLAYER_LEVELUP, SoundSource.AMBIENT, 0.5f, 0.8f) } } + + private data class AltSpell(val sacrifice: Mob, val pos: BlockPos) : RenderedSpell { + override fun cast(env: CastingEnvironment) { + val amount = sacrifice.health * 0.1F + Mishap.trulyHurt(sacrifice, sacrifice.damageSources().source(HexDamageTypes.OVERCAST), amount) + + val blockStateId = Block.getId(Blocks.AMETHYST_BLOCK.defaultBlockState()) + env.world.levelEvent(2001, pos, blockStateId) + env.world.levelEvent(2001, pos.below(), blockStateId) + + sacrifice.removeEffect(HexMobEffects.ENLARGE_GRID) + sacrifice.addEffect(MobEffectInstance(HexMobEffects.CRYSTALLIZED, -1)) + + HexAPI.instance().brainsweep(sacrifice) + + if (sacrifice is Villager && HexConfig.server().doVillagersTakeOffenseAtMindMurder()) { + env.castingEntity?.let { sacrifice.tellWitnessesThatIWasMurdered(it) } + } + + env.world.playSound(null, sacrifice, SoundEvents.ZOMBIE_VILLAGER_CURE, SoundSource.AMBIENT, 0.8f, 1f) + } + } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/effects/DissociationEffect.java b/Common/src/main/java/at/petrak/hexcasting/common/effects/DissociationEffect.java new file mode 100644 index 0000000000..c426e97936 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/effects/DissociationEffect.java @@ -0,0 +1,59 @@ +package at.petrak.hexcasting.common.effects; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.common.lib.HexDamageTypes; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectCategory; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; + +/** + * Applied when the casting grid is panned too far. During the first second of duration (ie continuously, so long as + * the effect is constantly being topped up) the player slowly loses oxygen. Once the grid is closed or panned back + * to center, the effect can start to tick down, and the oxygen drain stops. + *

+ * Make sure to use the provided constants for effect duration, or the oxygen drain system may behave oddly. + */ +public class DissociationEffect extends MobEffect { + public static final int AMP_0_DURATION = 300; + public static final int AMP_1_DURATION = 600; + + public DissociationEffect() { + super(MobEffectCategory.HARMFUL, 0x8932b8); + this.addAttributeModifier(Attributes.MOVEMENT_SPEED, HexAPI.modLoc("dissociation.slow"), -0.2, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + this.addAttributeModifier(Attributes.BLOCK_BREAK_SPEED, HexAPI.modLoc("dissociation.fatigue.a"), -0.45, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + this.addAttributeModifier(Attributes.ATTACK_SPEED, HexAPI.modLoc("dissociation.fatigue.b"), -0.1, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + this.addAttributeModifier(Attributes.ATTACK_DAMAGE, HexAPI.modLoc("dissociation.weak"), -4.0, AttributeModifier.Operation.ADD_VALUE); + } + + public static boolean shouldPreventBreathing(int duration, int amplifier) { + return switch (amplifier) { + case 0 -> duration > AMP_0_DURATION - 20; + case 1 -> duration > AMP_1_DURATION - 20; + default -> false; + }; + } + + @Override + public boolean applyEffectTick(LivingEntity entity, int amplifier) { + if (((Player)entity).getAbilities().invulnerable) return true; + entity.setAirSupply(entity.getAirSupply() - 1); + if (entity.getAirSupply() == -4) { + entity.setAirSupply(0); + entity.hurt(entity.damageSources().source(HexDamageTypes.FORGOT_TO_BREATHE), 2.0F); + } + return true; + } + + @Override + public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) { + if (!shouldPreventBreathing(duration, amplifier)) return false; + return switch (amplifier) { + case 0 -> duration % 10 == 0; + case 1 -> duration % 5 == 0; + default -> false; + }; + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java b/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java index 471e5861bd..0e461a6df1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collections; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Consumer; @@ -111,19 +112,4 @@ public Consumer defaultBrainsweepingBehavior() { public FrozenPigment getColorizer(Player player) { return IXplatAbstractions.INSTANCE.getPigment(player); } - - ArmorMaterial ARMOR_MATERIAL = new ArmorMaterial( - Collections.emptyMap(), - 0, - SoundEvents.ARMOR_EQUIP_LEATHER, - () -> Ingredient.EMPTY, - Collections.emptyList(), // TODO check textures. If not - use robes here from original code - 0, - 0 - ); - - @Override - public ArmorMaterial robesMaterial() { - return ARMOR_MATERIAL; - } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemStaff.java b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemStaff.java index 7ad1f4b5af..ee79020e44 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemStaff.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemStaff.java @@ -46,13 +46,14 @@ public InteractionResultHolder use(Level world, Player player, Intera if (!world.isClientSide() && player instanceof ServerPlayer serverPlayer) { var vm = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, hand); var patterns = IXplatAbstractions.INSTANCE.getPatternsSavedInUi(serverPlayer); + var panOffset = IXplatAbstractions.INSTANCE.getPanOffset(serverPlayer); @Nullable Iota ravenmind = vm.getImage().ravenmind().orElse(null); IXplatAbstractions.INSTANCE.sendPacketToPlayer(serverPlayer, new MsgOpenSpellGuiS2C(hand, patterns, vm.getImage().getStack(), ravenmind, - 0)); // TODO: Fix! + 0, panOffset)); // TODO: Fix! } player.awardStat(Stats.ITEM_USED.get(this)); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/armor/ItemRobes.java b/Common/src/main/java/at/petrak/hexcasting/common/items/armor/ItemRobes.java index fbe194e85f..a39c9086dd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/armor/ItemRobes.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/armor/ItemRobes.java @@ -1,19 +1,121 @@ package at.petrak.hexcasting.common.items.armor; +import at.petrak.hexcasting.annotations.SoftImplement; import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.api.item.VariantItem; +import at.petrak.hexcasting.client.model.HexModelLayers; +import at.petrak.hexcasting.client.model.HexRobesModel; +import at.petrak.hexcasting.common.items.ItemLens; +import at.petrak.hexcasting.common.lib.HexArmorMaterials; +import at.petrak.hexcasting.common.lib.HexAttributes; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.core.Holder; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.EquipmentSlotGroup; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.ItemAttributeModifiers; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +import static at.petrak.hexcasting.api.HexAPI.modLoc; /** * To get the armor model in; - * On forge: cursed self-mixin - * On fabric: hook in ClientInit + * On forge: client item extension in ForgeHexClientInitializer (line 161) + * On fabric: custom HexRobesRenderer set up from FabricHexClientInitializer (line 60) */ -public class ItemRobes extends ArmorItem { - public final ArmorItem.Type type; +public class ItemRobes extends ArmorItem implements VariantItem { + public final Type type; + private @Nullable HexRobesModel[] models; + + public static ItemAttributeModifiers HOOD_MODIFIERS = ItemAttributeModifiers.builder() + .add(HexAttributes.SCRY_SIGHT, ItemLens.SCRY_SIGHT, EquipmentSlotGroup.HEAD) + .add(HexAttributes.GRID_ZOOM, ItemLens.GRID_ZOOM, EquipmentSlotGroup.HEAD) + .add(Attributes.ARMOR, new AttributeModifier( + modLoc("robes_hood_armor"), 3.0, AttributeModifier.Operation.ADD_VALUE + ), EquipmentSlotGroup.HEAD) + .build(); + + public static ItemAttributeModifiers TUNIC_MODIFIERS = ItemAttributeModifiers.builder() + .add(HexAttributes.MEDIA_CONSUMPTION_MODIFIER, new AttributeModifier( + modLoc("robes_tunic_discount"), -0.1, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL + ), EquipmentSlotGroup.CHEST) + .add(Attributes.ARMOR, new AttributeModifier( + modLoc("robes_tunic_armor"), 7.0, AttributeModifier.Operation.ADD_VALUE + ), EquipmentSlotGroup.CHEST) + .build(); + + public static ItemAttributeModifiers LEGS_MODIFIERS = ItemAttributeModifiers.builder() + .add(HexAttributes.AMBIT_RADIUS, new AttributeModifier( + modLoc("robes_legs_ambit"), 4.0, AttributeModifier.Operation.ADD_VALUE + ), EquipmentSlotGroup.LEGS) + .add(Attributes.ARMOR, new AttributeModifier( + modLoc("robes_legs_armor"), 6.0, AttributeModifier.Operation.ADD_VALUE + ), EquipmentSlotGroup.LEGS) + .build(); - public ItemRobes(ArmorItem.Type type, Properties properties) { - super(Holder.direct(HexAPI.instance().robesMaterial()), type, properties); + public static ItemAttributeModifiers BOOTS_MODIFIERS = ItemAttributeModifiers.builder() + .add(HexAttributes.SENTINEL_RADIUS, new AttributeModifier( + modLoc("robes_boots_sentinel_ambit"), 2.0, AttributeModifier.Operation.ADD_VALUE + ), EquipmentSlotGroup.FEET) + .add(Attributes.ARMOR, new AttributeModifier( + modLoc("robes_boots_armor"), 2.0, AttributeModifier.Operation.ADD_VALUE + ), EquipmentSlotGroup.FEET) + .build(); + + public ItemRobes(Type type, Properties properties) { + super(HexArmorMaterials.ROBES, type, properties); this.type = type; } + + public static boolean isWearingFullSet(LivingEntity entity) { + for (var slot : List.of(EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET)) { + if (!(entity.getItemBySlot(slot).getItem() instanceof ItemRobes)) + return false; + } + return true; + } + + public static HexRobesModel[] provideArmorModelsForSlot(EquipmentSlot slot) { + EntityModelSet models = Minecraft.getInstance().getEntityModels(); + return new HexRobesModel[] { + new HexRobesModel(models.bakeLayer(HexModelLayers.ROBES_0), slot), + new HexRobesModel(models.bakeLayer(HexModelLayers.ROBES_1), slot), + new HexRobesModel(models.bakeLayer(HexModelLayers.ROBES_2), slot) + }; + } + + public HexRobesModel[] getArmorModels() { + if (models == null) models = provideArmorModelsForSlot(getEquipmentSlot()); + return models; + } + + @SoftImplement("IItemExtension") + public ResourceLocation getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, ArmorMaterial.Layer layer, boolean innerModel) { + return HexAPI.modLoc("textures/armor/robes"+getVariant(stack)+".png"); + } + + @Override + public Component getName(ItemStack pStack) { + var descID = this.getDescriptionId(pStack); + var robesItem = (ItemRobes) pStack.getItem(); + if (robesItem.type == Type.LEGGINGS) { + return Component.translatable(descID + "." + robesItem.getVariant(pStack)); + } else { + return Component.translatable(descID); + } + } + + @Override + public int numVariants() { return 3; } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexArmorMaterials.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexArmorMaterials.java new file mode 100644 index 0000000000..7222f83e9d --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexArmorMaterials.java @@ -0,0 +1,36 @@ +package at.petrak.hexcasting.common.lib; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.xplat.IXplatAbstractions; +import at.petrak.hexcasting.xplat.IXplatRegister; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.item.ArmorItem.Type; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.ArmorMaterials; +import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.crafting.Ingredient; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class HexArmorMaterials { + private static final IXplatRegister REGISTER = IXplatAbstractions.INSTANCE.createRegistar(Registries.ARMOR_MATERIAL); + + public static void register() { + REGISTER.registerAll(); + } + + public static final Holder ROBES = REGISTER.registerHolder("robes", () -> + new ArmorMaterial( + Map.of(), // no defense here since it's specified with the other attributes in ItemRobes + ArmorMaterials.GOLD.value().enchantmentValue(), + SoundEvents.ARMOR_EQUIP_LEATHER, + () -> Ingredient.of(HexItems.NEURAL_FIBER.get()), + List.of(new ArmorMaterial.Layer(HexAPI.modLoc("robes"))), + 0, 0 // no toughness or knockback resistance + )); +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexAttributes.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexAttributes.java index 707ec6544c..e5469995b6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexAttributes.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexAttributes.java @@ -33,7 +33,7 @@ public static void register() { //a multiplier to adjust media consumption across the board public static final Holder MEDIA_CONSUMPTION_MODIFIER = REGISTER.registerHolder("media_consumption", () -> new RangedAttribute( - MOD_ID + ".attributes.media_consumption", 1.0, 0.0, Double.MAX_VALUE).setSyncable(true)); + MOD_ID + ".attributes.media_consumption", 1.0, 0.0, Double.MAX_VALUE).setSyncable(true).setSentiment(Attribute.Sentiment.NEGATIVE)); public static final Holder AMBIT_RADIUS = REGISTER.registerHolder("ambit_radius", () -> new RangedAttribute( MOD_ID + ".attributes.ambit_radius", PlayerBasedCastEnv.DEFAULT_AMBIT_RADIUS, 0.0, Double.MAX_VALUE).setSyncable(true)); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlocks.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlocks.java index 4f9fd2f54e..447a8ab55f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlocks.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlocks.java @@ -1,10 +1,7 @@ package at.petrak.hexcasting.common.lib; import at.petrak.hexcasting.api.block.circle.BlockAbstractImpetus; -import at.petrak.hexcasting.common.blocks.BlockConjured; -import at.petrak.hexcasting.common.blocks.BlockConjuredLight; -import at.petrak.hexcasting.common.blocks.BlockFlammable; -import at.petrak.hexcasting.common.blocks.BlockQuenchedAllay; +import at.petrak.hexcasting.common.blocks.*; import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf; import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicLigature; import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicRecord; @@ -145,10 +142,20 @@ private static BlockBehaviour.Properties quenched() { .isViewBlocking(HexBlocks::never)), new Item.Properties()); - // "no" item because we add it manually + // "no" item because we add them manually in HexItems + // these must be registered before anything that references HexItems to avoid initializer errors public static final Supplier SLATE = blockNoItem("slate", () -> new BlockSlate(slateish() .pushReaction(PushReaction.DESTROY))); + public static final Supplier NEURAL_MESH = blockNoItem("neural_mesh", () -> + new BlockNeuralMesh(BlockBehaviour.Properties.of() + .noCollission() + .randomTicks() + .strength(0.2F) + .sound(SoundType.CANDLE) + .pushReaction(PushReaction.DESTROY) + ) + ); public static final Supplier IMPETUS_EMPTY = blockItem("impetus/empty", () -> new BlockEmptyImpetus(slateish() @@ -197,6 +204,7 @@ private static BlockBehaviour.Properties quenched() { HexItems.props().rarity(Rarity.UNCOMMON) ); + // Decoration?! public static final Supplier QUENCHED_ALLAY_TILES = blockItem("quenched_allay_tiles", () -> new BlockQuenchedAllay(quenched())); public static final Supplier QUENCHED_ALLAY_BRICKS = blockItem("quenched_allay_bricks", () -> new BlockQuenchedAllay(quenched())); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDamageTypes.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDamageTypes.java index 6bd0f900fc..cdb9c5bb9a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDamageTypes.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDamageTypes.java @@ -3,6 +3,7 @@ import net.minecraft.core.registries.Registries; import net.minecraft.data.worldgen.BootstrapContext; import net.minecraft.resources.ResourceKey; +import net.minecraft.world.damagesource.DamageEffects; import net.minecraft.world.damagesource.DamageScaling; import net.minecraft.world.damagesource.DamageType; @@ -10,6 +11,7 @@ public class HexDamageTypes { public static final ResourceKey OVERCAST = ResourceKey.create(Registries.DAMAGE_TYPE, modLoc("overcast")); + public static final ResourceKey FORGOT_TO_BREATHE = ResourceKey.create(Registries.DAMAGE_TYPE, modLoc("forgot_to_breathe")); public static void bootstrap(BootstrapContext ctx) { ctx.register(OVERCAST, new DamageType( @@ -17,5 +19,10 @@ public static void bootstrap(BootstrapContext ctx) { DamageScaling.WHEN_CAUSED_BY_LIVING_NON_PLAYER, 0f )); + ctx.register(FORGOT_TO_BREATHE, new DamageType( + "hexcasting.forgot_to_breathe", + DamageScaling.WHEN_CAUSED_BY_LIVING_NON_PLAYER, + 0f + )); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexItems.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexItems.java index e54537b9c7..37045eb505 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexItems.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexItems.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.common.lib; +import at.petrak.hexcasting.api.HexAPI; import at.petrak.hexcasting.api.casting.ActionRegistryEntry; import at.petrak.hexcasting.api.misc.MediaConstants; import at.petrak.hexcasting.api.mod.HexTags; @@ -8,6 +9,7 @@ import at.petrak.hexcasting.common.items.ItemLens; import at.petrak.hexcasting.common.items.ItemLoreFragment; import at.petrak.hexcasting.common.items.ItemStaff; +import at.petrak.hexcasting.common.items.armor.ItemRobes; import at.petrak.hexcasting.common.items.magic.*; import at.petrak.hexcasting.common.items.pigment.*; import at.petrak.hexcasting.common.items.storage.*; @@ -70,6 +72,7 @@ public static void registerItemsForCreativeTab(ResourceKey tabK public static final Supplier STAFF_QUENCHED = make("staff/quenched", () -> new ItemStaff(unstackable().rarity(Rarity.UNCOMMON))); // mindsplice staffaratus public static final Supplier STAFF_MINDSPLICE = make("staff/mindsplice", () -> new ItemStaff(unstackable().rarity(Rarity.UNCOMMON))); + public static final Supplier STAFF_NEURAL = make("staff/neural", () -> new ItemStaff(unstackable().rarity(Rarity.UNCOMMON))); public static final Supplier SCRYING_LENS = make("lens", () -> new ItemLens( IXplatAbstractions.INSTANCE.addEquipSlotFabric(EquipmentSlot.HEAD) @@ -100,6 +103,43 @@ public static void registerItemsForCreativeTab(ResourceKey tabK ) ); + public static final Supplier NEURAL_FIBER = make("neural_fiber", () -> new Item(props().rarity(Rarity.UNCOMMON))); + + public static final Supplier NEURAL_MESH = make("neural_mesh", () -> + new BlockItem(HexBlocks.NEURAL_MESH.get(), props() + .rarity(Rarity.UNCOMMON) + ) + ); + + public static final Supplier ROBES_HOOD = make("robes/hood", () -> + new ItemRobes(ArmorItem.Type.HELMET, unstackable() + .rarity(Rarity.UNCOMMON) + .durability(270) + .attributes(ItemRobes.HOOD_MODIFIERS) + ) + ); + public static final Supplier ROBES_TUNIC = make("robes/tunic", () -> + new ItemRobes(ArmorItem.Type.CHESTPLATE, unstackable() + .rarity(Rarity.UNCOMMON) + .durability(400) + .attributes(ItemRobes.TUNIC_MODIFIERS) + ) + ); + public static final Supplier ROBES_LEGS = make("robes/legs", () -> + new ItemRobes(ArmorItem.Type.LEGGINGS, unstackable() + .rarity(Rarity.UNCOMMON) + .durability(350) + .attributes(ItemRobes.LEGS_MODIFIERS) + ) + ); + public static final Supplier ROBES_BOOTS = make("robes/boots", () -> + new ItemRobes(ArmorItem.Type.BOOTS, unstackable() + .rarity(Rarity.UNCOMMON) + .durability(315) + .attributes(ItemRobes.BOOTS_MODIFIERS) + ) + ); + public static final Supplier SCROLL_SMOL = make("scroll_small", () -> new ItemScroll(props(), 1)); public static final Supplier SCROLL_MEDIUM = make("scroll_medium", () -> new ItemScroll(props(), 2)); public static final Supplier SCROLL_LARGE = make("scroll", () -> new ItemScroll(props(), 3)); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexMobEffects.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexMobEffects.java index 9f03197eaf..1e77e217f0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexMobEffects.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexMobEffects.java @@ -1,14 +1,20 @@ package at.petrak.hexcasting.common.lib; import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.common.effects.DissociationEffect; import at.petrak.hexcasting.common.misc.HexMobEffect; +import at.petrak.hexcasting.common.particles.ConjureParticleOptions; import at.petrak.hexcasting.xplat.IXplatAbstractions; import at.petrak.hexcasting.xplat.IXplatRegister; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; public class HexMobEffects { @@ -21,8 +27,11 @@ public static void register() { public static final Holder ENLARGE_GRID = REGISTER.registerHolder("enlarge_grid", () -> new HexMobEffect(MobEffectCategory.BENEFICIAL, 0xc875ff).addAttributeModifier(HexAttributes.GRID_ZOOM, HexAPI.modLoc("enlarge_grid"), - 0.25, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)); + 0.25, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)); public static final Holder SHRINK_GRID = REGISTER.registerHolder("shrink_grid", () -> new HexMobEffect(MobEffectCategory.HARMFUL, 0xc0e660).addAttributeModifier(HexAttributes.GRID_ZOOM, HexAPI.modLoc("shrink_grid"), -0.2, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)); + public static final Holder CRYSTALLIZED = REGISTER.registerHolder("crystallized", + () -> new HexMobEffect(MobEffectCategory.HARMFUL, 0x8932b8, new ConjureParticleOptions(0x8932b8, true))); + public static final Holder DISSOCIATION = REGISTER.registerHolder("dissociation", DissociationEffect::new); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexParticles.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexParticles.java index d5428d8b91..989eea3297 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexParticles.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexParticles.java @@ -21,7 +21,9 @@ public static void register() { } public static final Supplier CONJURE_PARTICLE = REGISTER.register( - "conjure_particle", () -> new ConjureParticleOptions.Type(false)); + "conjure_particle", () -> new ConjureParticleOptions.Type(false, false)); + public static final Supplier STATUS_PARTICLE = REGISTER.register( + "status_particle", () -> new ConjureParticleOptions.Type(false, true)); public static class FactoryHandler { public interface Consumer { @@ -31,6 +33,7 @@ void register(ParticleType type, public static void registerFactories(Consumer consumer) { consumer.register(CONJURE_PARTICLE.get(), ConjureParticle.Provider::new); + consumer.register(STATUS_PARTICLE.get(), ConjureParticle.StatusEffectProvider::new); } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/misc/HexMobEffect.java b/Common/src/main/java/at/petrak/hexcasting/common/misc/HexMobEffect.java index 4af9029f0b..0c9e7c54d6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/misc/HexMobEffect.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/misc/HexMobEffect.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.common.misc; +import net.minecraft.core.particles.ParticleOptions; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; @@ -10,4 +11,8 @@ public class HexMobEffect extends MobEffect { public HexMobEffect(MobEffectCategory category, int color) { super(category, color); } + + public HexMobEffect(MobEffectCategory category, int color, ParticleOptions particleOptions) { + super(category, color, particleOptions); + } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgOpenSpellGuiS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgOpenSpellGuiS2C.java index db261af133..11f988d77b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgOpenSpellGuiS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgOpenSpellGuiS2C.java @@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.casting.eval.ResolvedPattern; import at.petrak.hexcasting.api.casting.iota.Iota; import at.petrak.hexcasting.api.casting.iota.IotaType; +import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.client.gui.GuiSpellcasting; import net.minecraft.client.Minecraft; import net.minecraft.network.RegistryFriendlyByteBuf; @@ -11,6 +12,7 @@ import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.InteractionHand; +import net.minecraft.world.phys.Vec2; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -23,7 +25,8 @@ public record MsgOpenSpellGuiS2C(InteractionHand hand, List pat List stack, @Nullable Iota ravenmind, - int parenCount + int parenCount, + Vec2 panOffset ) implements CustomPacketPayload { public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(HexAPI.modLoc("cgui")); @@ -40,6 +43,7 @@ public record MsgOpenSpellGuiS2C(InteractionHand hand, List pat Optional::ofNullable ), MsgOpenSpellGuiS2C::ravenmind, ByteBufCodecs.VAR_INT, MsgOpenSpellGuiS2C::parenCount, + HexUtils.VEC2_STREAM_CODEC, MsgOpenSpellGuiS2C::panOffset, MsgOpenSpellGuiS2C::new ); @@ -59,7 +63,7 @@ public static void handle(MsgOpenSpellGuiS2C msg) { var mc = Minecraft.getInstance(); mc.setScreen( new GuiSpellcasting(msg.hand(), msg.patterns(), msg.stack, msg.ravenmind, - msg.parenCount)); + msg.parenCount, msg.panOffset)); }); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgPannedGridC2S.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgPannedGridC2S.java new file mode 100644 index 0000000000..b9efb19b7f --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgPannedGridC2S.java @@ -0,0 +1,53 @@ +package at.petrak.hexcasting.common.msgs; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.api.casting.eval.env.StaffCastEnv; +import at.petrak.hexcasting.api.utils.HexUtils; +import at.petrak.hexcasting.client.gui.GuiSpellcasting; +import at.petrak.hexcasting.common.effects.DissociationEffect; +import at.petrak.hexcasting.common.lib.HexMobEffects; +import at.petrak.hexcasting.common.misc.HexMobEffect; +import at.petrak.hexcasting.xplat.IXplatAbstractions; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.phys.Vec2; +import org.joml.Vector3f; + +/** + * Sent client->server to sync the player's casting grid pan offset and potentially apply the Dissociation debuff + * if they've panned too far. Sent whenever the pan offset is upated, and also every 10 ticks while the GUI is + * open so that the debuff can be kept active. + */ +public record MsgPannedGridC2S(Vec2 panOffset) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(HexAPI.modLoc("pan_cs")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + HexUtils.VEC2_STREAM_CODEC, MsgPannedGridC2S::panOffset, + MsgPannedGridC2S::new + ); + + @Override + public Type type() { + return TYPE; + } + + public void handle(MinecraftServer server, ServerPlayer sender) { + server.execute(() -> { + IXplatAbstractions.INSTANCE.setPanOffset(sender, panOffset); + var inst = sender.getEffect(HexMobEffects.DISSOCIATION); + int currentDur = (inst != null) ? inst.getDuration() : 0; + if (panOffset.lengthSquared() > 600*600) { + int newDur = Math.min(currentDur + 80, DissociationEffect.AMP_1_DURATION); + sender.addEffect(new MobEffectInstance(HexMobEffects.DISSOCIATION, newDur, 1, false, false, true)); + } else if (panOffset.lengthSquared() > 300*300) { + int newDur = Math.min(currentDur + 40, DissociationEffect.AMP_0_DURATION); + sender.addEffect(new MobEffectInstance(HexMobEffects.DISSOCIATION, newDur, 0, false, false, true)); + } + }); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/particles/ConjureParticleOptions.java b/Common/src/main/java/at/petrak/hexcasting/common/particles/ConjureParticleOptions.java index 869e0f5ab3..6990e8b743 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/particles/ConjureParticleOptions.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/particles/ConjureParticleOptions.java @@ -10,27 +10,38 @@ import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; -public record ConjureParticleOptions(int color) implements ParticleOptions { +public record ConjureParticleOptions(int color, boolean isStatus) implements ParticleOptions { @Override public ParticleType getType() { + if (isStatus) return HexParticles.STATUS_PARTICLE.get(); return HexParticles.CONJURE_PARTICLE.get(); } + public ConjureParticleOptions(int color) { + this(color, false); + } + public static class Type extends ParticleType { - public Type(boolean pOverrideLimiter) { + public boolean isStatus; + + public Type(boolean pOverrideLimiter, boolean isStatus) { super(pOverrideLimiter); + this.isStatus = isStatus; } public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( Codec.INT.fieldOf("color") - .forGetter((ConjureParticleOptions o) -> o.color) + .forGetter((ConjureParticleOptions o) -> o.color), + Codec.BOOL.fieldOf("status") + .forGetter((ConjureParticleOptions o) -> o.isStatus) ) .apply(instance, ConjureParticleOptions::new) ); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( ByteBufCodecs.VAR_INT, ConjureParticleOptions::color, + ByteBufCodecs.BOOL, ConjureParticleOptions::isStatus, ConjureParticleOptions::new ); diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/HexLootTables.java b/Common/src/main/java/at/petrak/hexcasting/datagen/HexLootTables.java index 713b16d052..5df6d75005 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/HexLootTables.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/HexLootTables.java @@ -8,6 +8,7 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions; import at.petrak.paucal.api.datagen.PaucalLootTableSubProvider; import net.minecraft.advancements.critereon.*; +import net.minecraft.core.Direction; import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; @@ -16,7 +17,9 @@ import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.MultifaceBlock; import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.storage.loot.LootPool; @@ -85,6 +88,18 @@ protected void makeLootTables(Map blockTables, )); blockTables.put(HexBlocks.EDIFIED_DOOR.get(), LootTable.lootTable().withPool(doorPool)); + var meshEntry = LootItem.lootTableItem(HexBlocks.NEURAL_MESH.get()) + .apply(SetItemCountFunction.setCount(ConstantValue.exactly(-1), true)); + for (var dir : Direction.values()) { + meshEntry.apply(SetItemCountFunction.setCount(ConstantValue.exactly(1), true) + .when(new LootItemBlockStatePropertyCondition.Builder(HexBlocks.NEURAL_MESH.get()).setProperties( + StatePropertiesPredicate.Builder.properties().hasProperty(MultifaceBlock.getFaceProperty(dir), true) + )) + ); + } + var meshPool = LootPool.lootPool().setRolls(ConstantValue.exactly(1)).add(meshEntry); + blockTables.put(HexBlocks.NEURAL_MESH.get(), LootTable.lootTable().withPool(meshPool)); + var silkTouchCond = MatchTool.toolMatches( ItemPredicate.Builder.item().withSubPredicate( ItemSubPredicates.ENCHANTMENTS, diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java index 4f817a0293..ac7a5a5857 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java @@ -102,6 +102,7 @@ public void buildRecipes(RecipeOutput recipes) { staffRecipe(recipes, HexItems.STAFF_EDIFIED.get(), HexBlocks.EDIFIED_PLANKS.get().asItem()); staffRecipe(recipes, HexItems.STAFF_QUENCHED.get(), HexItems.QUENCHED_SHARD.get()); staffRecipe(recipes, HexItems.STAFF_MINDSPLICE.get(), Ingredient.of(HexTags.Items.MINDFLAYED_CIRCLE_COMPONENTS)); + staffRecipe(recipes, HexItems.STAFF_NEURAL.get(), HexItems.NEURAL_MESH.get()); ShapelessRecipeBuilder.shapeless(RecipeCategory.TOOLS, HexItems.THOUGHT_KNOT.get()) .requires(HexItems.AMETHYST_DUST.get()) @@ -261,6 +262,38 @@ public void buildRecipes(RecipeOutput recipes) { .pattern(" S ") .unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes); + ring(RecipeCategory.REDSTONE, HexItems.NEURAL_MESH.get(), 1, HexItems.NEURAL_FIBER.get(), Blocks.BONE_BLOCK) + .unlockedBy("has_item", hasItem(HexItems.NEURAL_FIBER.get())).save(recipes); + + ShapedRecipeBuilder.shaped(RecipeCategory.COMBAT, HexItems.ROBES_HOOD.get()) + .define('F', HexItems.NEURAL_FIBER.get()) + .define('B', Items.BONE) + .pattern("BFB") + .pattern("F F") + .unlockedBy("has_item", hasItem(HexItems.NEURAL_FIBER.get())).save(recipes); + + ShapedRecipeBuilder.shaped(RecipeCategory.COMBAT, HexItems.ROBES_TUNIC.get()) + .define('F', HexItems.NEURAL_FIBER.get()) + .pattern("F F") + .pattern("FFF") + .pattern("FFF") + .unlockedBy("has_item", hasItem(HexItems.NEURAL_FIBER.get())).save(recipes); + + ShapedRecipeBuilder.shaped(RecipeCategory.COMBAT, HexItems.ROBES_LEGS.get()) + .define('F', HexItems.NEURAL_FIBER.get()) + .pattern("FFF") + .pattern("F F") + .pattern("F F") + .unlockedBy("has_item", hasItem(HexItems.NEURAL_FIBER.get())).save(recipes); + + ShapedRecipeBuilder.shaped(RecipeCategory.COMBAT, HexItems.ROBES_BOOTS.get()) + .define('F', HexItems.NEURAL_FIBER.get()) + .define('B', Items.BONE) + .pattern(" ") + .pattern("B B") + .pattern("F F") + .unlockedBy("has_item", hasItem(HexItems.NEURAL_FIBER.get())).save(recipes); + ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, HexItems.AMETHYST_DUST.get(), (int) (MediaConstants.QUENCHED_SHARD_UNIT / MediaConstants.DUST_UNIT) + 1) .requires(HexItems.QUENCHED_SHARD.get()) diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexDamageTypeTagProvider.java b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexDamageTypeTagProvider.java index 220598df0c..77be411044 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexDamageTypeTagProvider.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexDamageTypeTagProvider.java @@ -25,6 +25,11 @@ protected void addTags(@NotNull HolderLookup.Provider provider) { DamageTypeTags.BYPASSES_SHIELD, DamageTypeTags.NO_KNOCKBACK ); + add(HexDamageTypes.FORGOT_TO_BREATHE, + DamageTypeTags.BYPASSES_ARMOR, + DamageTypeTags.BYPASSES_EFFECTS, + DamageTypeTags.NO_KNOCKBACK + ); } @SafeVarargs diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexItemTagProvider.java b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexItemTagProvider.java index 2f97a1209e..48f06f52d4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexItemTagProvider.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexItemTagProvider.java @@ -40,7 +40,7 @@ protected void addTags(HolderLookup.Provider provider) { HexItems.STAFF_JUNGLE.get(), HexItems.STAFF_ACACIA.get(), HexItems.STAFF_DARK_OAK.get(), HexItems.STAFF_CRIMSON.get(), HexItems.STAFF_WARPED.get(), HexItems.STAFF_MANGROVE.get(), HexItems.STAFF_CHERRY.get(),HexItems.STAFF_BAMBOO.get(), - HexItems.STAFF_QUENCHED.get(), HexItems.STAFF_MINDSPLICE.get()); + HexItems.STAFF_QUENCHED.get(), HexItems.STAFF_MINDSPLICE.get(), HexItems.STAFF_NEURAL.get()); add(tag(HexTags.Items.PHIAL_BASE), Items.GLASS_BOTTLE); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinBuddingAmethystBlock.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinBuddingAmethystBlock.java new file mode 100644 index 0000000000..2e01fc5656 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinBuddingAmethystBlock.java @@ -0,0 +1,48 @@ +package at.petrak.hexcasting.mixin; + +import at.petrak.hexcasting.common.lib.HexBlocks; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.BuddingAmethystBlock; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(BuddingAmethystBlock.class) +public class MixinBuddingAmethystBlock { + // When combined with the extra random ticks provided by the neural mesh blocks themselves, this results + // in an overall speed boost equivalent to each mesh block providing 5 extra random ticks whenever it + // receives a single random tick. We do it this way (rather than actually ticking the budding block five + // times per mesh tick) to avoid sudden jumps in growth progress. + @WrapOperation( + method = "randomTick", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/RandomSource;nextInt(I)I", ordinal = 0) + ) + private int increaseSuccessChanceWithMesh( + RandomSource instance, int originalArg, Operation original, + BlockState selfState, ServerLevel serverLevel, BlockPos selfPos, RandomSource randomSource + ) { + int meshCount = 0; + for (Direction dir : Direction.values()) { + BlockPos checkPos = selfPos.relative(dir); + if (serverLevel.getBlockState(checkPos).is(HexBlocks.NEURAL_MESH.get())) { + meshCount++; + } + } + if (meshCount == 0) + return original.call(instance, originalArg); + boolean success = switch (meshCount) { + case 1 -> (randomSource.nextDouble() < 0.6); + case 2 -> (randomSource.nextDouble() < 11.0/15.0); + case 3 -> (randomSource.nextDouble() < 0.8); + case 4 -> (randomSource.nextDouble() < 0.84); + case 5 -> (randomSource.nextDouble() < 13.0/15.0); + default -> false; + }; + return success ? 0 : -1; + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinLivingEntity.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinLivingEntity.java index c3dbc47b81..e10238f190 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinLivingEntity.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinLivingEntity.java @@ -1,24 +1,45 @@ package at.petrak.hexcasting.mixin; -import at.petrak.hexcasting.xplat.IXplatAbstractions; +import at.petrak.hexcasting.common.lib.HexItems; +import at.petrak.hexcasting.common.lib.HexMobEffects; +import at.petrak.hexcasting.common.effects.DissociationEffect; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -// Nuke the brain at the source + @Mixin(LivingEntity.class) public abstract class MixinLivingEntity { - @Inject(method = "getBrain", at = @At("RETURN")) - private void removeBrain(CallbackInfoReturnable> cir) { + @Inject(method = "dropAllDeathLoot", require = 1, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;dropFromLootTable(Lnet/minecraft/world/damagesource/DamageSource;Z)V")) + private void dropCrystallizedLoot(CallbackInfo ci) { + var self = (LivingEntity) (Object) this; + var rand = self.getRandom(); + if (self.hasEffect(HexMobEffects.CRYSTALLIZED)) { + int fibers = rand.nextIntBetweenInclusive(1,3); + int dust = rand.nextIntBetweenInclusive(4,7); + int extra = 0; + if (self instanceof Villager vill) { + // lv2 = 50% +1 drop; lv3 = +1 drop; lv4 = +2 drops; lv5 = +3 drops + int lvl = vill.getVillagerData().getLevel(); + if (rand.nextIntBetweenInclusive(2, 3) <= lvl) extra++; + extra += Math.max(lvl-3, 0); + } + self.spawnAtLocation(new ItemStack(HexItems.NEURAL_FIBER.get(), fibers + extra)); + self.spawnAtLocation(new ItemStack(HexItems.AMETHYST_DUST.get(), dust + extra)); + } + } + + @Inject(method = "increaseAirSupply", at = @At("HEAD"), cancellable = true) + private void forgetToBreathe(int currentAir, CallbackInfoReturnable cir) { var self = (LivingEntity) (Object) this; - if (self instanceof Mob mob && IXplatAbstractions.INSTANCE.isBrainswept(mob)) { - var brain = cir.getReturnValue(); - brain.removeAllBehaviors(); - cir.setReturnValue(brain); + var inst = self.getEffect(HexMobEffects.DISSOCIATION); + if (inst != null && DissociationEffect.shouldPreventBreathing(inst.getDuration(), inst.getAmplifier())) { + cir.setReturnValue(currentAir); } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinGameRenderer.java b/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinGameRenderer.java new file mode 100644 index 0000000000..9f1e1e2c34 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinGameRenderer.java @@ -0,0 +1,28 @@ +package at.petrak.hexcasting.mixin.client; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.client.gui.GuiSpellcasting; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.PostChain; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(GameRenderer.class) +public abstract class MixinGameRenderer { + @WrapOperation( + method = "processBlurEffect", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/PostChain;setUniform(Ljava/lang/String;F)V") + ) + private void scaleBlurWhenPanningGrid(PostChain instance, String string, float f, Operation original) { + GameRenderer renderer = (GameRenderer)(Object)this; + Screen screen = renderer.getMinecraft().screen; + if (screen instanceof GuiSpellcasting grid) { + original.call(instance, string, Math.min(grid.getPanDistance(), 12f)); + } else { + original.call(instance, string, f); + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/xplat/DummyXplatAbstractions.kt b/Common/src/main/java/at/petrak/hexcasting/xplat/DummyXplatAbstractions.kt index f21675d6dc..4d36722bff 100644 --- a/Common/src/main/java/at/petrak/hexcasting/xplat/DummyXplatAbstractions.kt +++ b/Common/src/main/java/at/petrak/hexcasting/xplat/DummyXplatAbstractions.kt @@ -56,6 +56,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.material.Fluid import net.minecraft.world.level.storage.loot.predicates.LootItemCondition +import net.minecraft.world.phys.Vec2 import net.minecraft.world.phys.Vec3 import java.util.function.BiFunction import java.util.function.Supplier @@ -88,12 +89,14 @@ internal class DummyXplatAbstractions: IXplatAbstractions { override fun setAltiora(target: Player, altiora: AltioraAbility?) = error("Found use of DummyXplatAbstractions.") override fun setStaffcastImage(target: ServerPlayer, image: CastingImage?) = error("Found use of DummyXplatAbstractions.") override fun setPatterns(target: ServerPlayer, patterns: List) = error("Found use of DummyXplatAbstractions.") + override fun setPanOffset(target: ServerPlayer, panOffset: Vec2) = error("Found use of DummyXplatAbstractions.") override fun getFlight(player: ServerPlayer): FlightAbility? = error("Found use of DummyXplatAbstractions.") override fun getAltiora(player: Player): AltioraAbility? = error("Found use of DummyXplatAbstractions.") override fun getPigment(player: Player): FrozenPigment = error("Found use of DummyXplatAbstractions.") override fun getSentinel(player: Player): Sentinel? = error("Found use of DummyXplatAbstractions.") override fun getStaffcastVM(player: ServerPlayer, hand: InteractionHand): CastingVM = error("Found use of DummyXplatAbstractions.") override fun getPatternsSavedInUi(player: ServerPlayer): List = error("Found use of DummyXplatAbstractions.") + override fun getPanOffset(player: ServerPlayer): Vec2? = error("Found use of DummyXplatAbstractions.") override fun clearCastingData(player: ServerPlayer) = error("Found use of DummyXplatAbstractions.") override fun findMediaHolder(stack: ItemStack): ADMediaHolder? = error("Found use of DummyXplatAbstractions.") override fun findDataHolder(stack: ItemStack): ADIotaHolder? = error("Found use of DummyXplatAbstractions.") diff --git a/Common/src/main/java/at/petrak/hexcasting/xplat/IXplatAbstractions.java b/Common/src/main/java/at/petrak/hexcasting/xplat/IXplatAbstractions.java index c2cc4ec351..d64a582211 100644 --- a/Common/src/main/java/at/petrak/hexcasting/xplat/IXplatAbstractions.java +++ b/Common/src/main/java/at/petrak/hexcasting/xplat/IXplatAbstractions.java @@ -38,7 +38,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Tier; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -47,6 +46,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; @@ -103,6 +103,8 @@ public interface IXplatAbstractions { void setPatterns(ServerPlayer target, List patterns); + void setPanOffset(ServerPlayer target, Vec2 panOffset); + @Nullable FlightAbility getFlight(ServerPlayer player); @Nullable AltioraAbility getAltiora(Player player); @@ -115,6 +117,8 @@ public interface IXplatAbstractions { List getPatternsSavedInUi(ServerPlayer player); + Vec2 getPanOffset(ServerPlayer player); + void clearCastingData(ServerPlayer player); @Nullable diff --git a/Common/src/main/resources/assets/hexcasting/blockstates/neural_mesh.json b/Common/src/main/resources/assets/hexcasting/blockstates/neural_mesh.json new file mode 100644 index 0000000000..f5b66df718 --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/blockstates/neural_mesh.json @@ -0,0 +1,140 @@ +{ + "multipart": [ + { + "apply": { + "model": "hexcasting:block/neural_mesh" + }, + "when": { + "north": "true" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh" + }, + "when": { + "down": "false", + "east": "false", + "north": "false", + "south": "false", + "up": "false", + "west": "false" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "y": 90 + }, + "when": { + "east": "true" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "y": 90 + }, + "when": { + "down": "false", + "east": "false", + "north": "false", + "south": "false", + "up": "false", + "west": "false" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "y": 180 + }, + "when": { + "south": "true" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "y": 180 + }, + "when": { + "down": "false", + "east": "false", + "north": "false", + "south": "false", + "up": "false", + "west": "false" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "y": 270 + }, + "when": { + "west": "true" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "y": 270 + }, + "when": { + "down": "false", + "east": "false", + "north": "false", + "south": "false", + "up": "false", + "west": "false" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "x": 270 + }, + "when": { + "up": "true" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "x": 270 + }, + "when": { + "down": "false", + "east": "false", + "north": "false", + "south": "false", + "up": "false", + "west": "false" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "x": 90 + }, + "when": { + "down": "true" + } + }, + { + "apply": { + "model": "hexcasting:block/neural_mesh", + "x": 90 + }, + "when": { + "down": "false", + "east": "false", + "north": "false", + "south": "false", + "up": "false", + "west": "false" + } + } + ] +} \ No newline at end of file diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index cb5bca2269..fc39a37c16 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -18,6 +18,7 @@ edified: "Edified Staff", quenched: "Quenched Shard Staff", mindsplice: "Mindsplice Staff", + neural: "Neural Staff", }, amethyst_dust: "Amethyst Dust", @@ -62,7 +63,18 @@ abacus: "Abacus", jeweler_hammer: "Jeweler's Hammer", sub_sandwich: "Submarine Sandwich", - + neural_fiber: "Neural Fiber", + neural_mesh: "Neural Mesh", + + robes: { + hood: "Grand Caster Hood", + tunic: "Grand Caster Tunic", + "legs.0": "Grand Caster Robe", + "legs.1": "Grand Caster Pants", + "legs.2": "Grand Caster Leggings", + boots: "Grand Caster Boots", + }, + dye_colorizer_: { white: "White Pigment", orange: "Orange Pigment", @@ -125,7 +137,9 @@ "block.hexcasting": { conjured_light: "Conjured Light", conjured_block: "Conjured Block", - + + neural_mesh: "Neural Mesh", + directrix: { empty: "Empty Directrix", redstone: "Mason Directrix", @@ -219,6 +233,8 @@ "effect.hexcasting": { enlarge_grid: "Clarity", shrink_grid: "Clouding", + crystallized: "Crystallized", + dissociation: "Dissociation", }, "item.minecraft.potion.effect": { @@ -364,6 +380,10 @@ "": "Clicking Toggles Drawing", "@Tooltip": "Whether you click to start and stop drawing instead of clicking and dragging to draw", }, + gridPanMouseButton: { + "": "Grid Pan Mouse Button", + "@Tooltip": "Which mouse button is used to pan the hex grid (once that ability is unlocked)", + }, advancedTooltipsShowsIotaNBT: { "": "Advanced Tooltips Shows Iota NBT", "@Tooltip": "Whether enabling advanced tooltips (F3+H) should display the full NBT of iotas stored in items like foci and spellbooks", @@ -523,6 +543,10 @@ "": "%s's mind was subsumed into energy", player: "%s's mind was subsumed into energy while fighting %s", }, + forgot_to_breathe: { + "": "%s forgot to breathe", + player: "%s forgot to breathe while fighting %s", + } }, "command.hexcasting": { @@ -1317,6 +1341,8 @@ directrix: "Directrices", akashiclib: "Akashic Libraries", quenching_allays: "Quenching Allays", + neural_fiber: "Neural Inversion", + caster_robes: "Caster's Garments", fanciful_staves: "Fanciful Staves", // and the actions @@ -1776,7 +1802,18 @@ "4": "The product is fragile. Breaking it shatters it into pieces, with $(thing)Fortune/$ increasing the yield... if I wish the block itself I need a silken touch.$(br2)The produced shards are worth thrice an $(l:items/amethyst)$(item)Charged Amethyst Crystal/$ apiece. The block itself is worth four of the shards.", "5": "They are mercurial, they seem to twist and wink under my fingers, and by giving them a mentor in another form of _media they may be coerced into its shape, in an equivalent exchange of _media.", }, - + + neural_fiber: { + "1": "Mind and body-- I can bridge the gap! $(l:greatwork/brainsweeping)$(action)Flay Mind/$ was built to sever but I understand it now, I can TWIST it, force the mind not $(o)out/$ but $(o)in/$, so long as the flesh is made ready to accept it -- $(l:items/potions)Clarity/$ should do the job. The mind can be folded into itself, crystallized in flesh and bone and nerve, until there is only ONE, mind-and-body superimposed in a single hybrid substrate.", + "2": "Viscera suffused with micro-fractal splinters of cognition, living and thinking and-- USELESS! Nothing but a mass of meat and _media, in the end.$(br2)But the nerves... the nerves become conduits, skeins of thought reified in shimmering fiber. These I can USE. Free them from the flesh and they are $(o)mine/$.$(br2)I could weave them into myself -- more $(o)space/$ to think in -- no. I am not being rational.", + "3": "The process itself is simple: apply $(l:items/potions)Clarity/$ to render the body receptive, cast $(l:greatwork/brainsweeping)$(action)Flay Mind/$ with the $(l:patterns/basics#hexcasting:entity_pos/eye)$(action)subject’s own head/$ as the destination, then dissect to harvest the fiber. Any villager will do, though a more developed mind will provide a higher yield.$(br2)I wonder... does it understand, even excised? Does it feel?", + mesh: "The fibers have a natural affinity for bone. Woven into such a frame, I can affix them to $(thing)Budding Amethyst/$ to provide additional paths for the flow of media, accelerating growth. However, covering too many faces seems to reduce overall production efficiency.", + }, + + caster_robes: { + "1": "With $(l:greatwork/neural_fiber)Neural Fiber/$, I finally have the key to augmenting my own skill! Robes woven from the fibers streamline the _media around me -- I can cast further, cheaper, $(o)greater/$.$(br2)But I would not settle for that alone. With these robes I can think $(o)outside/$ myself, mind shared between thinking flesh and thinking fabric, threads woven as thoughts are woven as Nature is-- ENOUGH.", + "2": "So long as I wear the full set of robes, I gain the ability to $(o)pan/$ the hex grid with right-click. This vastly expands the number of patterns I can draw at once, though not without risks. Drifting further into this mental space pulls my awareness away from my body -- go too far, and I might even forget to breathe.$(br2)The nature of the robes also renders them receptive to $(l:patterns/spells/cyclevariant)$(action)Caster's Glamour/$, should I wish to style myself differently.",//499 + }, "fanciful_staves.1": "It is only right as I shed the husk of ignorance I replace my tools, my palm-polished staves. These new constructions of mine have no additional properties -- but they are so glorious, oh so Glorious... They match the radiance winking at the corners of my sight.", diff --git a/Common/src/main/resources/assets/hexcasting/models/block/neural_mesh.json b/Common/src/main/resources/assets/hexcasting/models/block/neural_mesh.json new file mode 100644 index 0000000000..0d4d773748 --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/models/block/neural_mesh.json @@ -0,0 +1,38 @@ +{ + "ambientocclusion": false, + "textures": { + "particle": "hexcasting:item/neural_mesh", + "neural_mesh": "hexcasting:block/neural_mesh" + }, + "render_type": "cutout", + "elements": [ + { + "from": [ 0, 0, 0.1 ], + "to": [ 16, 16, 0.1 ], + "faces": { + "north": { "uv": [ 8, 0, 0, 8 ], "texture": "#neural_mesh" }, + "south": { "uv": [ 0, 0, 8, 8 ], "texture": "#neural_mesh" } + } + }, + { + "from": [ 0, 0, 0.3 ], + "to": [ 16, 16, 0.3 ], + "faces": { + "north": { "uv": [ 16, 0, 8, 8 ], "texture": "#neural_mesh" }, + "south": { "uv": [ 8, 0, 16, 8 ], "texture": "#neural_mesh" } + } + }, + { + "from": [3, 3, 0], + "to": [13, 13, 1], + "faces": { + "north": {"uv": [1.5, 9.5, 6.5, 14.5], "texture": "#neural_mesh"}, + "south": {"uv": [1.5, 9.5, 6.5, 14.5], "texture": "#neural_mesh"}, + "east": {"uv": [6, 9.5, 6.5, 14.5], "texture": "#neural_mesh"}, + "west": {"uv": [1.5, 9.5, 2, 14.5], "texture": "#neural_mesh"}, + "up": {"uv": [1.5, 9.5, 6.5, 10], "texture": "#neural_mesh"}, + "down": {"uv": [1.5, 14, 6.5, 14.5], "texture": "#neural_mesh"} + } + } + ] +} \ No newline at end of file diff --git a/Common/src/main/resources/assets/hexcasting/particles/status_particle.json b/Common/src/main/resources/assets/hexcasting/particles/status_particle.json new file mode 100644 index 0000000000..ec744902a2 --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/particles/status_particle.json @@ -0,0 +1,5 @@ +{ + "textures": [ + "hexcasting:cloud" + ] +} \ No newline at end of file diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/caster_robes.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/caster_robes.json new file mode 100644 index 0000000000..7556b6bb9c --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/caster_robes.json @@ -0,0 +1,28 @@ +{ + "name": "hexcasting.entry.caster_robes", + "category": "hexcasting:greatwork", + "icon": "hexcasting:robes/hood", + "advancement": "hexcasting:enlightenment", + "entry_color": "54398a", + "sortnum": 7, + "pages": [ + { + "type": "patchouli:text", + "text": "hexcasting.page.caster_robes.1" + }, + { + "type": "patchouli:text", + "text": "hexcasting.page.caster_robes.2" + }, + { + "type": "patchouli:crafting", + "recipe": "hexcasting:robes/hood", + "recipe2": "hexcasting:robes/tunic" + }, + { + "type": "patchouli:crafting", + "recipe": "hexcasting:robes/legs", + "recipe2": "hexcasting:robes/boots" + } + ] +} \ No newline at end of file diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/fanciful_staves.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/fanciful_staves.json index f62fbc0013..25d3b0073c 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/fanciful_staves.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/fanciful_staves.json @@ -2,7 +2,7 @@ "name": "hexcasting.entry.fanciful_staves", "category": "hexcasting:greatwork", "icon": "hexcasting:staff/mindsplice", - "sortnum": 6, + "sortnum": 8, "advancement": "hexcasting:enlightenment", "entry_color": "54398a", "pages": [ @@ -14,6 +14,10 @@ "type": "patchouli:crafting", "recipe": "hexcasting:staff/quenched", "recipe2": "hexcasting:staff/mindsplice" + }, + { + "type": "patchouli:crafting", + "recipe": "hexcasting:staff/neural" } ] } diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/neural_fiber.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/neural_fiber.json new file mode 100644 index 0000000000..2ea6b1c99d --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/neural_fiber.json @@ -0,0 +1,29 @@ +{ + "name": "hexcasting.entry.neural_fiber", + "category": "hexcasting:greatwork", + "icon": "hexcasting:charged_amethyst", + "advancement": "hexcasting:enlightenment", + "entry_color": "54398a", + "sortnum": 6, + "pages": [ + { + "type": "patchouli:text", + "text": "hexcasting.page.neural_fiber.1" + }, + { + "type": "patchouli:text", + "text": "hexcasting.page.neural_fiber.2" + }, + { + "type": "patchouli:spotlight", + "item": "hexcasting:neural_fiber", + "text": "hexcasting.page.neural_fiber.3", + "link_recipe": true + }, + { + "type": "patchouli:crafting", + "recipe": "hexcasting:neural_mesh", + "text": "hexcasting.page.neural_fiber.mesh" + } + ] +} \ No newline at end of file diff --git a/Common/src/main/resources/assets/hexcasting/textures/armor/robes0.png b/Common/src/main/resources/assets/hexcasting/textures/armor/robes0.png new file mode 100644 index 0000000000..2218a6e628 Binary files /dev/null and b/Common/src/main/resources/assets/hexcasting/textures/armor/robes0.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/armor/robes1.png b/Common/src/main/resources/assets/hexcasting/textures/armor/robes1.png index 2218a6e628..cb621b6072 100644 Binary files a/Common/src/main/resources/assets/hexcasting/textures/armor/robes1.png and b/Common/src/main/resources/assets/hexcasting/textures/armor/robes1.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/armor/robes2.png b/Common/src/main/resources/assets/hexcasting/textures/armor/robes2.png index cb621b6072..cde5477699 100644 Binary files a/Common/src/main/resources/assets/hexcasting/textures/armor/robes2.png and b/Common/src/main/resources/assets/hexcasting/textures/armor/robes2.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/armor/robes3.png b/Common/src/main/resources/assets/hexcasting/textures/armor/robes3.png deleted file mode 100644 index cde5477699..0000000000 Binary files a/Common/src/main/resources/assets/hexcasting/textures/armor/robes3.png and /dev/null differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/block/neural_mesh.png b/Common/src/main/resources/assets/hexcasting/textures/block/neural_mesh.png new file mode 100644 index 0000000000..253dac0c12 Binary files /dev/null and b/Common/src/main/resources/assets/hexcasting/textures/block/neural_mesh.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/gui/casting_bg.png b/Common/src/main/resources/assets/hexcasting/textures/gui/casting_bg.png new file mode 100644 index 0000000000..7f94529482 Binary files /dev/null and b/Common/src/main/resources/assets/hexcasting/textures/gui/casting_bg.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/neural_fiber.png b/Common/src/main/resources/assets/hexcasting/textures/item/neural_fiber.png new file mode 100644 index 0000000000..9494392dd6 Binary files /dev/null and b/Common/src/main/resources/assets/hexcasting/textures/item/neural_fiber.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/neural_mesh.png b/Common/src/main/resources/assets/hexcasting/textures/item/neural_mesh.png new file mode 100644 index 0000000000..1a3069b70e Binary files /dev/null and b/Common/src/main/resources/assets/hexcasting/textures/item/neural_mesh.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/1-boots.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/0_boots.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/1-boots.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/0_boots.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/1-helmet.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/0_hood.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/1-helmet.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/0_hood.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/1-leggings.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/0_legs.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/1-leggings.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/0_legs.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/1-chestplate.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/0_tunic.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/1-chestplate.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/0_tunic.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/2-boots.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/1_boots.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/2-boots.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/1_boots.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/2-helmet.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/1_hood.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/2-helmet.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/1_hood.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/2-leggings.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/1_legs.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/2-leggings.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/1_legs.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/2-chestplate.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/1_tunic.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/2-chestplate.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/1_tunic.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/3-boots.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/2_boots.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/3-boots.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/2_boots.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/3-helmet.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/2_hood.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/3-helmet.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/2_hood.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/3-leggings.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/2_legs.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/3-leggings.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/2_legs.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/robes/3-chestplate.png b/Common/src/main/resources/assets/hexcasting/textures/item/robes/2_tunic.png similarity index 100% rename from Common/src/main/resources/assets/hexcasting/textures/item/robes/3-chestplate.png rename to Common/src/main/resources/assets/hexcasting/textures/item/robes/2_tunic.png diff --git a/Common/src/main/resources/assets/hexcasting/textures/item/staff/neural.png b/Common/src/main/resources/assets/hexcasting/textures/item/staff/neural.png new file mode 100644 index 0000000000..6592f9e493 Binary files /dev/null and b/Common/src/main/resources/assets/hexcasting/textures/item/staff/neural.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/mob_effect/crystallized.png b/Common/src/main/resources/assets/hexcasting/textures/mob_effect/crystallized.png new file mode 100644 index 0000000000..b4e4f6d2bf Binary files /dev/null and b/Common/src/main/resources/assets/hexcasting/textures/mob_effect/crystallized.png differ diff --git a/Common/src/main/resources/assets/hexcasting/textures/mob_effect/dissociation.png b/Common/src/main/resources/assets/hexcasting/textures/mob_effect/dissociation.png new file mode 100644 index 0000000000..2d90323597 Binary files /dev/null and b/Common/src/main/resources/assets/hexcasting/textures/mob_effect/dissociation.png differ diff --git a/Common/src/main/resources/hexplat.mixins.json b/Common/src/main/resources/hexplat.mixins.json index 9c6121aa10..ca9b69e663 100644 --- a/Common/src/main/resources/hexplat.mixins.json +++ b/Common/src/main/resources/hexplat.mixins.json @@ -6,6 +6,8 @@ "package": "at.petrak.hexcasting.mixin", "mixins": [ "MixinAbstractVillager", + "MixinBuddingAmethystBlock", + "MixinLivingEntity", "MixinMob", "MixinRaider", "MixinVillager", @@ -26,6 +28,7 @@ "accessor.client.AccessorRenderStateShard", "accessor.client.AccessorRenderType", "client.MixinClientLevel", - "client.MixinPlayerRenderer" + "client.MixinPlayerRenderer", + "client.MixinGameRenderer" ] } diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json new file mode 100644 index 0000000000..e2c37e3408 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/boots" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/boots" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json new file mode 100644 index 0000000000..0b7770cf3f --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/hood" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/hood" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json new file mode 100644 index 0000000000..7076892ac0 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/legs" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/legs" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json new file mode 100644 index 0000000000..9e5bac0e88 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/tunic" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/tunic" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json new file mode 100644 index 0000000000..5a76172263 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:neural_mesh" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:neural_mesh" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json new file mode 100644 index 0000000000..c3502060e1 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:charged_amethyst" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:staff/neural" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:staff/neural" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json b/Fabric/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json new file mode 100644 index 0000000000..49ecc8425a --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json @@ -0,0 +1,106 @@ +{ + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "add": true, + "count": -1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "down": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "up": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "north": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "south": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "west": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "east": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + } + ], + "name": "hexcasting:neural_mesh" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "hexcasting:blocks/neural_mesh" +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/neural_mesh.json b/Fabric/src/generated/resources/data/hexcasting/recipe/neural_mesh.json new file mode 100644 index 0000000000..b1ae10c52c --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/neural_mesh.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "redstone", + "key": { + "C": { + "item": "hexcasting:neural_fiber" + }, + "D": { + "item": "hexcasting:neural_fiber" + }, + "I": { + "item": "minecraft:bone_block" + } + }, + "pattern": [ + "DCD", + "CIC", + "DCD" + ], + "result": { + "count": 1, + "id": "hexcasting:neural_mesh" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/robes/boots.json b/Fabric/src/generated/resources/data/hexcasting/recipe/robes/boots.json new file mode 100644 index 0000000000..3c2411b6fc --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/robes/boots.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "B": { + "item": "minecraft:bone" + }, + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + " ", + "B B", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/boots" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/robes/hood.json b/Fabric/src/generated/resources/data/hexcasting/recipe/robes/hood.json new file mode 100644 index 0000000000..1f2cd42944 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/robes/hood.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "B": { + "item": "minecraft:bone" + }, + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "BFB", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/hood" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/robes/legs.json b/Fabric/src/generated/resources/data/hexcasting/recipe/robes/legs.json new file mode 100644 index 0000000000..3715882308 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/robes/legs.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "FFF", + "F F", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/legs" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/robes/tunic.json b/Fabric/src/generated/resources/data/hexcasting/recipe/robes/tunic.json new file mode 100644 index 0000000000..c162bb6405 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/robes/tunic.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "F F", + "FFF", + "FFF" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/tunic" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/staff/neural.json b/Fabric/src/generated/resources/data/hexcasting/recipe/staff/neural.json new file mode 100644 index 0000000000..a4288d0288 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/staff/neural.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "A": { + "item": "hexcasting:charged_amethyst" + }, + "S": { + "item": "minecraft:stick" + }, + "W": { + "item": "hexcasting:neural_mesh" + } + }, + "pattern": [ + " SA", + " WS", + "S " + ], + "result": { + "count": 1, + "id": "hexcasting:staff/neural" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/tags/item/staves.json b/Fabric/src/generated/resources/data/hexcasting/tags/item/staves.json index 29f4595c62..c3b2e7c4f8 100644 --- a/Fabric/src/generated/resources/data/hexcasting/tags/item/staves.json +++ b/Fabric/src/generated/resources/data/hexcasting/tags/item/staves.json @@ -13,6 +13,7 @@ "hexcasting:staff/cherry", "hexcasting:staff/bamboo", "hexcasting:staff/quenched", - "hexcasting:staff/mindsplice" + "hexcasting:staff/mindsplice", + "hexcasting:staff/neural" ] } \ No newline at end of file diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexClientInitializer.kt b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexClientInitializer.kt index 76130ce49a..a42dc2ebbe 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexClientInitializer.kt +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexClientInitializer.kt @@ -4,11 +4,13 @@ import at.petrak.hexcasting.client.ClientTickCounter import at.petrak.hexcasting.client.Keybinds import at.petrak.hexcasting.client.RegisterClientStuff import at.petrak.hexcasting.client.ShiftScrollListener +import at.petrak.hexcasting.client.gui.GuiSpellcasting import at.petrak.hexcasting.client.gui.PatternTooltipComponent import at.petrak.hexcasting.client.model.HexModelLayers import at.petrak.hexcasting.client.render.HexAdditionalRenderers import at.petrak.hexcasting.common.casting.PatternRegistryManifest import at.petrak.hexcasting.common.lib.HexParticles +import at.petrak.hexcasting.fabric.client.HexRobesRenderer import at.petrak.hexcasting.fabric.event.MouseScrollCallback import at.petrak.hexcasting.fabric.network.FabricPacketHandler import at.petrak.hexcasting.interop.HexInterop @@ -37,7 +39,7 @@ object FabricHexClientInitializer : ClientModInitializer { } HudRenderCallback.EVENT.register(HexAdditionalRenderers::overlayGui) WorldRenderEvents.START.register { ClientTickCounter.renderTickStart(it.tickCounter().gameTimeDeltaTicks) } - ClientTickEvents.END_CLIENT_TICK.register { + ClientTickEvents.END_CLIENT_TICK.register { ctx -> ClientTickCounter.clientTickEnd() Keybinds.clientTickEnd() ShiftScrollListener.clientTickEnd() @@ -56,7 +58,7 @@ object FabricHexClientInitializer : ClientModInitializer { RegisterClientStuff.init() HexModelLayers.init { loc, defn -> EntityModelLayerRegistry.registerModelLayer(loc, defn::get) } - + HexRobesRenderer.init() HexParticles.FactoryHandler.registerFactories(object : HexParticles.FactoryHandler.Consumer { override fun register(type: ParticleType, constructor: Function>) { diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java index 09dd3727e7..aaf82542ff 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java @@ -140,6 +140,8 @@ public static final class Client implements HexConfig.ClientConfigAccess, Config @ConfigEntry.Gui.Tooltip private boolean clickingTogglesDrawing = DEFAULT_CLICKING_TOGGLES_DRAWING; @ConfigEntry.Gui.Tooltip + private int gridPanMouseButton = DEFAULT_GRID_PAN_MOUSE_BUTTON; + @ConfigEntry.Gui.Tooltip private boolean advancedTooltipsShowsIotaNBT = DEFAULT_ADVANCED_TOOLTIPS_SHOWS_IOTA_NBT; @ConfigEntry.Gui.Tooltip private boolean staticActiveSlates = DEFAULT_STATIC_ACTIVE_SLATES; @@ -147,6 +149,7 @@ public static final class Client implements HexConfig.ClientConfigAccess, Config @Override public void validatePostLoad() throws ValidationException { this.gridSnapThreshold = Mth.clamp(this.gridSnapThreshold, 0.5, 1.0); + this.gridPanMouseButton = Math.max(this.gridPanMouseButton, 1); } @Override @@ -179,6 +182,9 @@ public boolean clickingTogglesDrawing() { return clickingTogglesDrawing; } + @Override + public int gridPanMouseButton() { return gridPanMouseButton; } + @Override public boolean advancedTooltipsShowsIotaNBT() { return advancedTooltipsShowsIotaNBT; diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexInitializer.kt b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexInitializer.kt index 878e371aeb..505cb68926 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexInitializer.kt +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexInitializer.kt @@ -5,11 +5,7 @@ import at.petrak.hexcasting.api.addldata.ADMediaHolder import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers import at.petrak.hexcasting.api.casting.ActionRegistryEntry import at.petrak.hexcasting.api.casting.iota.DoubleIota -import at.petrak.hexcasting.api.item.HexHolderItem -import at.petrak.hexcasting.api.item.IotaHolderItem -import at.petrak.hexcasting.api.item.MediaHolderItem -import at.petrak.hexcasting.api.item.PigmentItem -import at.petrak.hexcasting.api.item.VariantItem +import at.petrak.hexcasting.api.item.* import at.petrak.hexcasting.api.misc.MediaConstants import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexStatistics @@ -23,7 +19,6 @@ import at.petrak.hexcasting.common.casting.actions.spells.great.OpAltiora import at.petrak.hexcasting.common.command.PatternResKeyArgument import at.petrak.hexcasting.common.entities.HexEntities import at.petrak.hexcasting.common.items.ItemJewelerHammer -import at.petrak.hexcasting.common.items.magic.ItemMediaBattery import at.petrak.hexcasting.common.items.storage.ItemScroll import at.petrak.hexcasting.common.lib.* import at.petrak.hexcasting.common.lib.hex.* @@ -32,8 +27,6 @@ import at.petrak.hexcasting.common.misc.BrainsweepingEvents import at.petrak.hexcasting.common.misc.PlayerPositionRecorder import at.petrak.hexcasting.common.misc.RegisterMisc import at.petrak.hexcasting.common.recipe.HexRecipeStuffRegistry -import at.petrak.hexcasting.common.lib.HexBrainsweepeeIngredients -import at.petrak.hexcasting.common.lib.HexStateIngredients import at.petrak.hexcasting.fabric.cc.HexCardinalComponents import at.petrak.hexcasting.fabric.cc.adimpl.* import at.petrak.hexcasting.fabric.event.VillagerConversionCallback @@ -215,6 +208,7 @@ object FabricHexInitializer : ModInitializer { HexRecipeStuffRegistry.register() HexParticles.register() + HexArmorMaterials.register() HexLootFunctions.register() diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/CCPanOffset.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/CCPanOffset.java new file mode 100644 index 0000000000..6af7bed9b0 --- /dev/null +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/CCPanOffset.java @@ -0,0 +1,33 @@ +package at.petrak.hexcasting.fabric.cc; + +import at.petrak.hexcasting.api.utils.HexUtils; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec2; +import org.ladysnake.cca.api.v3.component.Component; +import org.ladysnake.cca.api.v3.component.sync.AutoSyncedComponent; + +public class CCPanOffset implements Component, AutoSyncedComponent { + public static final String TAG_PAN_OFFSET = "pan_offset"; + + private final Player owner; + private Vec2 panOffset = Vec2.ZERO; + + public CCPanOffset(ServerPlayer owner) { + this.owner = owner; + } + + public Vec2 getPanOffset() { return panOffset; } + public void setPanOffset(Vec2 newOffset) { this.panOffset = newOffset; } + + @Override + public void readFromNbt(CompoundTag tag, HolderLookup.Provider registryLookup) { + this.panOffset = HexUtils.vec2FromNBT(tag.getCompound(TAG_PAN_OFFSET)); + } + + public void writeToNbt(CompoundTag tag, HolderLookup.Provider registryLookup) { + tag.put(TAG_PAN_OFFSET, HexUtils.serializeToNBT(this.panOffset)); + } +} diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/HexCardinalComponents.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/HexCardinalComponents.java index b60bc9a1c6..9dd5c9e10e 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/HexCardinalComponents.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/HexCardinalComponents.java @@ -41,6 +41,8 @@ public class HexCardinalComponents implements EntityComponentInitializer, ItemCo CCStaffcastImage.class); public static final ComponentKey PATTERNS = ComponentRegistry.getOrCreate(modLoc("patterns"), CCPatterns.class); + public static final ComponentKey PAN_OFFSET = ComponentRegistry.getOrCreate(modLoc("pan_offset"), + CCPanOffset.class); public static final ComponentKey CLIENT_CASTING_STACK = ComponentRegistry.getOrCreate(modLoc("client_casting_stack"), CCClientCastingStack.class); @@ -78,6 +80,7 @@ public void registerEntityComponentFactories(EntityComponentFactoryRegistry regi registry.registerFor(ServerPlayer.class, FLIGHT, CCFlight::new); registry.registerFor(ServerPlayer.class, STAFFCAST_IMAGE, CCStaffcastImage::new); registry.registerFor(ServerPlayer.class, PATTERNS, CCPatterns::new); + registry.registerFor(ServerPlayer.class, PAN_OFFSET, CCPanOffset::new); registry.registerFor(ItemEntity.class, IOTA_HOLDER, wrapItemEntityDelegate( diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/client/HexRobesRenderer.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/client/HexRobesRenderer.java new file mode 100644 index 0000000000..48607da62c --- /dev/null +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/client/HexRobesRenderer.java @@ -0,0 +1,34 @@ +package at.petrak.hexcasting.fabric.client; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.common.items.armor.ItemRobes; +import at.petrak.hexcasting.common.lib.HexArmorMaterials; +import at.petrak.hexcasting.common.lib.HexItems; +import net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderer; +import net.minecraft.world.item.Item; + +import java.util.List; + +public class HexRobesRenderer { + public static final List ROBE_ITEMS = + List.of( + HexItems.ROBES_HOOD.get(), + HexItems.ROBES_TUNIC.get(), + HexItems.ROBES_LEGS.get(), + HexItems.ROBES_BOOTS.get() + ); + + public static void init() { + ArmorRenderer renderer = (matrices, vertexConsumers, stack, entity, slot, light, contextModel) -> { + + ItemRobes armor = (ItemRobes) stack.getItem(); + var model = armor.getArmorModels()[armor.getVariant(stack)]; + var texture = armor.getArmorTexture(stack, entity, slot, HexArmorMaterials.ROBES.value().layers().getFirst(), false); + contextModel.copyPropertiesTo(model); + + ArmorRenderer.renderPart(matrices, vertexConsumers, light, stack, model, texture); + + }; + ArmorRenderer.register(renderer, ROBE_ITEMS.toArray(new Item[0])); + } +} diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/network/FabricPacketHandler.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/network/FabricPacketHandler.java index c7e2346e9b..8ee9e166a5 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/network/FabricPacketHandler.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/network/FabricPacketHandler.java @@ -16,6 +16,7 @@ public static void initPackets() { PayloadTypeRegistry.playC2S().register(MsgShiftScrollC2S.TYPE, MsgShiftScrollC2S.STREAM_CODEC); PayloadTypeRegistry.playC2S().register(MsgNewSpellPatternC2S.TYPE, MsgNewSpellPatternC2S.STREAM_CODEC); PayloadTypeRegistry.playS2C().register(MsgNewSpellPatternS2C.TYPE, MsgNewSpellPatternS2C.STREAM_CODEC); + PayloadTypeRegistry.playC2S().register(MsgPannedGridC2S.TYPE, MsgPannedGridC2S.STREAM_CODEC); PayloadTypeRegistry.playS2C().register(MsgOpenSpellGuiS2C.TYPE, MsgOpenSpellGuiS2C.STREAM_CODEC); PayloadTypeRegistry.playS2C().register(MsgBeepS2C.TYPE, MsgBeepS2C.STREAM_CODEC); PayloadTypeRegistry.playS2C().register(MsgShiftScrollC2S.TYPE, MsgShiftScrollC2S.STREAM_CODEC); @@ -31,6 +32,8 @@ public static void init() { makeServerBoundHandler(MsgShiftScrollC2S::handle)); ServerPlayNetworking.registerGlobalReceiver(MsgNewSpellPatternC2S.TYPE, makeServerBoundHandler(MsgNewSpellPatternC2S::handle)); + ServerPlayNetworking.registerGlobalReceiver(MsgPannedGridC2S.TYPE, + makeServerBoundHandler(MsgPannedGridC2S::handle)); } private static ServerPlayNetworking.PlayPayloadHandler makeServerBoundHandler( diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/xplat/FabricXplatImpl.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/xplat/FabricXplatImpl.java index fbad939683..eda1e88482 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/xplat/FabricXplatImpl.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/xplat/FabricXplatImpl.java @@ -80,6 +80,7 @@ import net.minecraft.world.level.storage.loot.predicates.AnyOfCondition; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.level.storage.loot.predicates.MatchTool; +import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; import virtuoel.pehkui.api.ScaleTypes; @@ -189,6 +190,12 @@ public void setPatterns(ServerPlayer target, List patterns) { cc.setPatterns(patterns); } + @Override + public void setPanOffset(ServerPlayer target, Vec2 panOffset) { + var cc = HexCardinalComponents.PAN_OFFSET.get(target); + cc.setPanOffset(panOffset); + } + @Override public boolean isBrainswept(Mob mob) { var cc = HexCardinalComponents.BRAINSWEPT.get(mob); @@ -231,10 +238,17 @@ public List getPatternsSavedInUi(ServerPlayer player) { return cc.getPatterns(); } + @Override + public Vec2 getPanOffset(ServerPlayer player) { + var cc = HexCardinalComponents.PAN_OFFSET.get(player); + return cc.getPanOffset(); + } + @Override public void clearCastingData(ServerPlayer player) { this.setStaffcastImage(player, null); this.setPatterns(player, List.of()); + this.setPanOffset(player, Vec2.ZERO); } @Override diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json index 053571f52b..798dec41db 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/Fabric/src/main/resources/fabric.mod.json @@ -77,6 +77,7 @@ "hexcasting:altiora", "hexcasting:harness", "hexcasting:patterns", + "hexcasting:pan_offset", "hexcasting:client_casting_stack", "hexcasting:pigment", "hexcasting:iota_holder", diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/neural_fiber.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/neural_fiber.json new file mode 100644 index 0000000000..0d52422152 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/neural_fiber.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/neural_fiber" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/neural_mesh.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/neural_mesh.json new file mode 100644 index 0000000000..4f9fe9bf8a --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/neural_mesh.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/neural_mesh" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots.json new file mode 100644 index 0000000000..264198cc15 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "hexcasting:item/robes/boots", + "predicate": { + "hexcasting:variant": 0.0 + } + }, + { + "model": "hexcasting:item/robes/boots_1", + "predicate": { + "hexcasting:variant": 1.0 + } + }, + { + "model": "hexcasting:item/robes/boots_2", + "predicate": { + "hexcasting:variant": 2.0 + } + } + ], + "textures": { + "layer0": "hexcasting:item/robes/0_boots" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots_1.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots_1.json new file mode 100644 index 0000000000..fe6a221473 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/1_boots" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots_2.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots_2.json new file mode 100644 index 0000000000..27a0c192a7 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/boots_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/2_boots" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood.json new file mode 100644 index 0000000000..d2218f4994 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "hexcasting:item/robes/hood", + "predicate": { + "hexcasting:variant": 0.0 + } + }, + { + "model": "hexcasting:item/robes/hood_1", + "predicate": { + "hexcasting:variant": 1.0 + } + }, + { + "model": "hexcasting:item/robes/hood_2", + "predicate": { + "hexcasting:variant": 2.0 + } + } + ], + "textures": { + "layer0": "hexcasting:item/robes/0_hood" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood_1.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood_1.json new file mode 100644 index 0000000000..4631bfe281 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/1_hood" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood_2.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood_2.json new file mode 100644 index 0000000000..0761f55547 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/hood_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/2_hood" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs.json new file mode 100644 index 0000000000..03d57e0536 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "hexcasting:item/robes/legs", + "predicate": { + "hexcasting:variant": 0.0 + } + }, + { + "model": "hexcasting:item/robes/legs_1", + "predicate": { + "hexcasting:variant": 1.0 + } + }, + { + "model": "hexcasting:item/robes/legs_2", + "predicate": { + "hexcasting:variant": 2.0 + } + } + ], + "textures": { + "layer0": "hexcasting:item/robes/0_legs" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs_1.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs_1.json new file mode 100644 index 0000000000..93054eafd4 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/1_legs" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs_2.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs_2.json new file mode 100644 index 0000000000..b5667a0aec --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/legs_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/2_legs" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic.json new file mode 100644 index 0000000000..da671641b8 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "hexcasting:item/robes/tunic", + "predicate": { + "hexcasting:variant": 0.0 + } + }, + { + "model": "hexcasting:item/robes/tunic_1", + "predicate": { + "hexcasting:variant": 1.0 + } + }, + { + "model": "hexcasting:item/robes/tunic_2", + "predicate": { + "hexcasting:variant": 2.0 + } + } + ], + "textures": { + "layer0": "hexcasting:item/robes/0_tunic" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic_1.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic_1.json new file mode 100644 index 0000000000..797dbbc608 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/1_tunic" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic_2.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic_2.json new file mode 100644 index 0000000000..a665bce0cb --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/robes/tunic_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "hexcasting:item/robes/2_tunic" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/item/staff/neural.json b/Neoforge/src/generated/resources/assets/hexcasting/models/item/staff/neural.json new file mode 100644 index 0000000000..9d11027240 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/item/staff/neural.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld_rod", + "textures": { + "layer0": "hexcasting:item/staff/neural" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/assets/hexcasting/models/staff/neural.json b/Neoforge/src/generated/resources/assets/hexcasting/models/staff/neural.json new file mode 100644 index 0000000000..4890c91a60 --- /dev/null +++ b/Neoforge/src/generated/resources/assets/hexcasting/models/staff/neural.json @@ -0,0 +1,16 @@ +{ + "overrides": [ + { + "model": "hexcasting:item/neural_staff", + "predicate": { + "hexcasting:funny_level": 0.0 + } + }, + { + "model": "hexcasting:item/cherry_staff", + "predicate": { + "hexcasting:funny_level": 2.0 + } + } + ] +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json new file mode 100644 index 0000000000..e2c37e3408 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/boots.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/boots" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/boots" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json new file mode 100644 index 0000000000..0b7770cf3f --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/hood.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/hood" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/hood" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json new file mode 100644 index 0000000000..7076892ac0 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/legs.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/legs" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/legs" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json new file mode 100644 index 0000000000..9e5bac0e88 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/combat/robes/tunic.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:robes/tunic" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:robes/tunic" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json new file mode 100644 index 0000000000..5a76172263 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/redstone/neural_mesh.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:neural_fiber" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:neural_mesh" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:neural_mesh" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json new file mode 100644 index 0000000000..c3502060e1 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/tools/staff/neural.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "hexcasting:charged_amethyst" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:staff/neural" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:staff/neural" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/damage_type/forgot_to_breathe.json b/Neoforge/src/generated/resources/data/hexcasting/damage_type/forgot_to_breathe.json new file mode 100644 index 0000000000..d3a0ca991f --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/damage_type/forgot_to_breathe.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "hexcasting.forgot_to_breathe", + "scaling": "when_caused_by_living_non_player" +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json b/Neoforge/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json new file mode 100644 index 0000000000..49ecc8425a --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/loot_table/blocks/neural_mesh.json @@ -0,0 +1,106 @@ +{ + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "add": true, + "count": -1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "down": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "up": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "north": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "south": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "west": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + }, + { + "add": true, + "conditions": [ + { + "block": "hexcasting:neural_mesh", + "condition": "minecraft:block_state_property", + "properties": { + "east": "true" + } + } + ], + "count": 1.0, + "function": "minecraft:set_count" + } + ], + "name": "hexcasting:neural_mesh" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "hexcasting:blocks/neural_mesh" +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/neural_mesh.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/neural_mesh.json new file mode 100644 index 0000000000..b1ae10c52c --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/neural_mesh.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "redstone", + "key": { + "C": { + "item": "hexcasting:neural_fiber" + }, + "D": { + "item": "hexcasting:neural_fiber" + }, + "I": { + "item": "minecraft:bone_block" + } + }, + "pattern": [ + "DCD", + "CIC", + "DCD" + ], + "result": { + "count": 1, + "id": "hexcasting:neural_mesh" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/boots.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/boots.json new file mode 100644 index 0000000000..3c2411b6fc --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/boots.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "B": { + "item": "minecraft:bone" + }, + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + " ", + "B B", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/boots" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/hood.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/hood.json new file mode 100644 index 0000000000..1f2cd42944 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/hood.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "B": { + "item": "minecraft:bone" + }, + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "BFB", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/hood" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/legs.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/legs.json new file mode 100644 index 0000000000..3715882308 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/legs.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "FFF", + "F F", + "F F" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/legs" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/tunic.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/tunic.json new file mode 100644 index 0000000000..c162bb6405 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/robes/tunic.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "F": { + "item": "hexcasting:neural_fiber" + } + }, + "pattern": [ + "F F", + "FFF", + "FFF" + ], + "result": { + "count": 1, + "id": "hexcasting:robes/tunic" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/staff/neural.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/staff/neural.json new file mode 100644 index 0000000000..a4288d0288 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/staff/neural.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "A": { + "item": "hexcasting:charged_amethyst" + }, + "S": { + "item": "minecraft:stick" + }, + "W": { + "item": "hexcasting:neural_mesh" + } + }, + "pattern": [ + " SA", + " WS", + "S " + ], + "result": { + "count": 1, + "id": "hexcasting:staff/neural" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/tags/item/staves.json b/Neoforge/src/generated/resources/data/hexcasting/tags/item/staves.json index 29f4595c62..c3b2e7c4f8 100644 --- a/Neoforge/src/generated/resources/data/hexcasting/tags/item/staves.json +++ b/Neoforge/src/generated/resources/data/hexcasting/tags/item/staves.json @@ -13,6 +13,7 @@ "hexcasting:staff/cherry", "hexcasting:staff/bamboo", "hexcasting:staff/quenched", - "hexcasting:staff/mindsplice" + "hexcasting:staff/mindsplice", + "hexcasting:staff/neural" ] } \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json b/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json index 4209c89aa3..319bb24df4 100644 --- a/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json +++ b/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json @@ -1,5 +1,6 @@ { "values": [ - "hexcasting:overcast" + "hexcasting:overcast", + "hexcasting:forgot_to_breathe" ] } \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/bypasses_effects.json b/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/bypasses_effects.json index 4209c89aa3..319bb24df4 100644 --- a/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/bypasses_effects.json +++ b/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/bypasses_effects.json @@ -1,5 +1,6 @@ { "values": [ - "hexcasting:overcast" + "hexcasting:overcast", + "hexcasting:forgot_to_breathe" ] } \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/no_knockback.json b/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/no_knockback.json index 4209c89aa3..319bb24df4 100644 --- a/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/no_knockback.json +++ b/Neoforge/src/generated/resources/data/minecraft/tags/damage_type/no_knockback.json @@ -1,5 +1,6 @@ { "values": [ - "hexcasting:overcast" + "hexcasting:overcast", + "hexcasting:forgot_to_breathe" ] } \ No newline at end of file diff --git a/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexClientInitializer.java b/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexClientInitializer.java index 3e30a6c875..1662f29e61 100644 --- a/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexClientInitializer.java +++ b/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexClientInitializer.java @@ -4,12 +4,15 @@ import at.petrak.hexcasting.client.Keybinds; import at.petrak.hexcasting.client.RegisterClientStuff; import at.petrak.hexcasting.client.ShiftScrollListener; +import at.petrak.hexcasting.client.gui.GuiSpellcasting; import at.petrak.hexcasting.client.gui.PatternTooltipComponent; import at.petrak.hexcasting.client.model.AltioraLayer; import at.petrak.hexcasting.client.model.HexModelLayers; import at.petrak.hexcasting.client.render.HexAdditionalRenderers; import at.petrak.hexcasting.client.render.shader.HexShaders; import at.petrak.hexcasting.common.casting.PatternRegistryManifest; +import at.petrak.hexcasting.common.items.armor.ItemRobes; +import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexParticles; import at.petrak.hexcasting.common.misc.PatternTooltip; import at.petrak.hexcasting.forge.lib.ForgeHexAttachments; @@ -17,6 +20,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.color.block.BlockColors; import net.minecraft.client.color.item.ItemColors; +import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.PlayerModel; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.particle.ParticleProvider; @@ -25,10 +29,15 @@ import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleType; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.*; +import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions; +import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent; import net.neoforged.neoforge.common.NeoForge; import java.io.IOException; @@ -147,6 +156,23 @@ public static void addPlayerLayers(EntityRenderersEvent.AddLayers evt) { }); } + @SubscribeEvent + public static void registerArmorRenderer(RegisterClientExtensionsEvent evt) { + evt.registerItem(new IClientItemExtensions() { + //private final Map[]> MODEL_SETS = new Object2ObjectArrayMap<>(); + + @Override + public HumanoidModel getHumanoidArmorModel(LivingEntity livingEntity, ItemStack itemStack, EquipmentSlot equipmentSlot, HumanoidModel original) { + ItemRobes armor = (ItemRobes) itemStack.getItem(); + return armor.getArmorModels()[armor.getVariant(itemStack)]; + +// var variant = itemStack.get(HexDataComponents.ITEM_VARIANT.get()); +// var modelSet = MODEL_SETS.computeIfAbsent(equipmentSlot, ItemRobes::provideArmorModelsForSlot); +// return variant != null ? modelSet[variant] : modelSet[0]; + } + }, HexItems.ROBES_HOOD.get(), HexItems.ROBES_TUNIC.get(), HexItems.ROBES_LEGS.get(), HexItems.ROBES_BOOTS.get()); + } + @SubscribeEvent public static void registerBinds(RegisterKeyMappingsEvent event) { Keybinds.ALL_BINDS.forEach(event::register); diff --git a/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java b/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java index a9a48d4201..c582804ecb 100644 --- a/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java +++ b/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java @@ -86,6 +86,7 @@ public static class Client implements HexConfig.ClientConfigAccess { private static ModConfigSpec.BooleanValue invertAbacusScrollDirection; private static ModConfigSpec.DoubleValue gridSnapThreshold; private static ModConfigSpec.BooleanValue clickingTogglesDrawing; + private static ModConfigSpec.IntValue gridPanMouseButton; private static ModConfigSpec.BooleanValue disableInworldScrolling; private static ModConfigSpec.BooleanValue advancedTooltipsShowsIotaNBT; private static ModConfigSpec.BooleanValue staticActiveSlates; @@ -111,6 +112,9 @@ public Client(ModConfigSpec.Builder builder) { clickingTogglesDrawing = builder.comment( "Whether you click to start and stop drawing instead of clicking and dragging") .define("clickingTogglesDrawing", DEFAULT_CLICKING_TOGGLES_DRAWING); + gridPanMouseButton = builder.comment( + "Which mouse button is used to pan the hex grid (once that ability is unlocked)") + .defineInRange("gridPanMouseButton", DEFAULT_GRID_PAN_MOUSE_BUTTON, 1, Integer.MAX_VALUE); advancedTooltipsShowsIotaNBT = builder.comment( "Whether enabling advanced tooltips (F3+H) should display the full NBT of iotas stored in items " + "like foci and spellbooks") @@ -150,6 +154,9 @@ public boolean clickingTogglesDrawing() { return clickingTogglesDrawing.get(); } + @Override + public int gridPanMouseButton() { return gridPanMouseButton.get(); } + @Override public boolean advancedTooltipsShowsIotaNBT() { return advancedTooltipsShowsIotaNBT.get(); diff --git a/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java b/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java index 73c5f84471..d07bdeaef5 100644 --- a/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java +++ b/Neoforge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java @@ -131,6 +131,7 @@ private static void initRegistry() { HexMobEffects.register(); HexPotions.register(); HexParticles.register(); + HexArmorMaterials.register(); HexAdvancementTriggers.register(); diff --git a/Neoforge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexItemModels.java b/Neoforge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexItemModels.java index 864fb611ca..607ad63a59 100644 --- a/Neoforge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexItemModels.java +++ b/Neoforge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexItemModels.java @@ -55,6 +55,7 @@ protected void registerModels() { brandishedItem(HexItems.JEWELER_HAMMER.get()); simpleItem(HexItems.CREATIVE_UNLOCKER.get()); simpleItem(HexItems.LORE_FRAGMENT.get()); + simpleItem(HexItems.NEURAL_FIBER.get()); singleTexture(getPath(HexBlocks.CONJURED_BLOCK.get()), ResourceLocation.withDefaultNamespace("item/generated"), @@ -80,6 +81,13 @@ protected void registerModels() { .translation(-2.5f, 0f, -8f) .scale(0.4f); + simpleItem(HexItems.NEURAL_MESH.get()); + + buildRobes(HexItems.ROBES_HOOD.get(), "hood", HexItems.ROBES_HOOD.get().numVariants()); + buildRobes(HexItems.ROBES_TUNIC.get(), "tunic", HexItems.ROBES_HOOD.get().numVariants()); + buildRobes(HexItems.ROBES_LEGS.get(), "legs", HexItems.ROBES_HOOD.get().numVariants()); + buildRobes(HexItems.ROBES_BOOTS.get(), "boots", HexItems.ROBES_HOOD.get().numVariants()); + singleTexture("old_staff", ResourceLocation.withDefaultNamespace("item/handheld_rod"), "layer0", modLoc("item/staff/old")); singleTexture("cherry_staff", ResourceLocation.withDefaultNamespace("item/handheld_rod"), @@ -98,6 +106,7 @@ protected void registerModels() { buildStaff(HexItems.STAFF_BAMBOO.get(), "bamboo"); buildStaff(HexItems.STAFF_EDIFIED.get(), "edified"); buildStaff(HexItems.STAFF_MINDSPLICE.get(), "mindsplice"); + buildStaff(HexItems.STAFF_NEURAL.get(), "neural"); // again, doesn't like paths with slashes in them, so we do it manually buildFourVariantGaslight("item/staff/quenched", "item/staff/quenched", (name, path) -> @@ -276,6 +285,19 @@ private void buildStaff(Item item, String name) { .end(); } + private void buildRobes(Item item, String type, int numVariants) { + var name = "item/" + getPath(item); + var builder = getBuilder(name); + for (int i = 0; i < numVariants; i++) { + var parent_tag = "item/generated"; + var model = i == 0 ? singleTexture(name, ResourceLocation.withDefaultNamespace(parent_tag), + "layer0", modLoc("item/robes/" + i + "_" + type)) + : withExistingParent(name + "_" + i, ResourceLocation.withDefaultNamespace(parent_tag)) + .texture("layer0", modLoc("item/robes/" + i + "_" + type)); + builder.override().predicate(ItemFocus.VARIANT_PRED, i).model(model).end(); + } + } + private void buildPackagedSpell(Item item, String stub, int numVariants) { var name = getPath(item); var builder = getBuilder(name); diff --git a/Neoforge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java b/Neoforge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java index c53a796a4e..5c95098709 100644 --- a/Neoforge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java +++ b/Neoforge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java @@ -21,6 +21,8 @@ public static void init(IEventBus modBus) { // Client -> server registar.playToServer(MsgNewSpellPatternC2S.TYPE, MsgNewSpellPatternC2S.STREAM_CODEC, makeServerBoundHandler(MsgNewSpellPatternC2S::handle)); + registar.playToServer(MsgPannedGridC2S.TYPE, MsgPannedGridC2S.STREAM_CODEC, + makeServerBoundHandler(MsgPannedGridC2S::handle)); registar.playToServer(MsgShiftScrollC2S.TYPE, MsgShiftScrollC2S.STREAM_CODEC, makeServerBoundHandler(MsgShiftScrollC2S::handle)); diff --git a/Neoforge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java b/Neoforge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java index 19d0b90813..33112f9120 100644 --- a/Neoforge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java +++ b/Neoforge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java @@ -60,7 +60,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Tier; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -70,6 +69,7 @@ import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import net.neoforged.api.distmarker.Dist; import net.neoforged.fml.ModContainer; @@ -232,6 +232,11 @@ public void setPatterns(ServerPlayer player, List patterns) { player.getPersistentData().put(TAG_PATTERNS, ResolvedPattern.CODEC.listOf().encodeStart(NbtOps.INSTANCE, patterns).getOrThrow()); } + @Override + public void setPanOffset(ServerPlayer player, Vec2 panOffset) { + player.getPersistentData().put(TAG_PAN_OFFSET, HexUtils.VEC2_CODEC.encodeStart(NbtOps.INSTANCE, panOffset).getOrThrow()); + } + @Override public boolean isBrainswept(Mob e) { return e.getPersistentData().getBoolean(TAG_BRAINSWEPT); @@ -295,10 +300,16 @@ public List getPatternsSavedInUi(ServerPlayer player) { return ResolvedPattern.CODEC.listOf().parse(NbtOps.INSTANCE, player.getPersistentData().getList(TAG_PATTERNS, Tag.TAG_COMPOUND)).getOrThrow(); } + @Override + public Vec2 getPanOffset(ServerPlayer player) { + return HexUtils.VEC2_CODEC.parse(NbtOps.INSTANCE, player.getPersistentData().getCompound(TAG_PAN_OFFSET)).getOrThrow(); + } + @Override public void clearCastingData(ServerPlayer player) { player.getPersistentData().remove(TAG_VM); player.getPersistentData().remove(TAG_PATTERNS); + player.getPersistentData().remove(TAG_PAN_OFFSET); } @Override @@ -572,4 +583,5 @@ public void setScale(Entity e, float scale) { public static final String TAG_VM = "hexcasting:spell_harness"; public static final String TAG_PATTERNS = "hexcasting:spell_patterns"; + public static final String TAG_PAN_OFFSET = "hexcasting:pan_offset"; } diff --git a/art/robes/Robes0.bbmodel b/art/robes/Robes0.bbmodel new file mode 100644 index 0000000000..61a422e741 --- /dev/null +++ b/art/robes/Robes0.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"5.0","model_format":"modded_entity","box_uv":true},"name":"Robes1","model_identifier":"","modded_entity_entity_class":"","modded_entity_version":"1.17","modded_entity_flip_y":true,"visible_box":[1,1,0],"variable_placeholders":"","multi_file_ruleset":"","variable_placeholder_buttons":[],"timeline_setups":[],"unhandled_root_fields":{},"resolution":{"width":64,"height":64},"elements":[{"name":"hood_outer","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,24,-4],"to":[4,32,4],"autouv":0,"color":7,"inflate":0.4,"origin":[0,0,0],"uv_offset":[0,16],"faces":{"north":{"uv":[8,24,16,32],"texture":0},"east":{"uv":[0,24,8,32],"texture":0},"south":{"uv":[24,24,32,32],"texture":0},"west":{"uv":[16,24,24,32],"texture":0},"up":{"uv":[16,24,8,16],"texture":0},"down":{"uv":[24,16,16,24],"texture":0}},"type":"cube","uuid":"1581b57e-00c2-c3a2-d822-b969220a28d4"},{"name":"hood_inner","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,24,-4],"to":[4,32,4],"autouv":0,"color":3,"inflate":0.3,"origin":[0,0,0],"faces":{"north":{"uv":[8,8,16,16],"texture":0},"east":{"uv":[0,8,8,16],"texture":0},"south":{"uv":[24,8,32,16],"texture":0},"west":{"uv":[16,8,24,16],"texture":0},"up":{"uv":[16,8,8,0],"texture":0},"down":{"uv":[24,0,16,8],"texture":0}},"type":"cube","uuid":"c5b38b99-6a56-d9ff-e64c-7b6f865f9a78"},{"name":"left_horn","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-11.7,28.2,0],"to":[-3.7,32.2,0],"autouv":0,"color":2,"inflate":0.3,"origin":[0,0,0],"uv_offset":[24,0],"faces":{"north":{"uv":[24,0,32,4],"texture":0},"east":{"uv":[24,0,24,4],"texture":0},"south":{"uv":[32,0,40,4],"texture":0},"west":{"uv":[32,0,32,4],"texture":0},"up":{"uv":[32,0,24,0],"texture":0},"down":{"uv":[40,0,32,0],"texture":0}},"type":"cube","uuid":"6964045e-8723-0987-f243-5ea5477fe7de"},{"name":"right_horn","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[3.8,28.2,0],"to":[11.8,32.2,0],"autouv":0,"color":0,"mirror_uv":true,"inflate":0.3,"origin":[0,0,0],"uv_offset":[24,0],"faces":{"north":{"uv":[32,0,24,4],"texture":0},"east":{"uv":[32,0,32,4],"texture":0},"south":{"uv":[40,0,32,4],"texture":0},"west":{"uv":[24,0,24,4],"texture":0},"up":{"uv":[24,0,32,0],"texture":0},"down":{"uv":[32,0,40,0],"texture":0}},"type":"cube","uuid":"f33f09f2-5156-ad5f-6a83-b6ec43dd94ba"},{"name":"tunic_outer","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,12,-2],"to":[4,24,2],"autouv":0,"color":4,"inflate":0.4,"origin":[0,0,0],"uv_offset":[40,16],"faces":{"north":{"uv":[44,20,52,32],"texture":0},"east":{"uv":[40,20,44,32],"texture":0},"south":{"uv":[56,20,64,32],"texture":0},"west":{"uv":[52,20,56,32],"texture":0},"up":{"uv":[52,20,44,16],"texture":0},"down":{"uv":[60,16,52,20],"texture":0}},"type":"cube","uuid":"e8531e9d-18f6-891f-90e4-7521fdc4d333"},{"name":"tunic_inner","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,12,-2],"to":[4,24,2],"autouv":0,"color":7,"inflate":0.3,"origin":[0,0,0],"uv_offset":[40,0],"faces":{"north":{"uv":[44,4,52,16],"texture":0},"east":{"uv":[40,4,44,16],"texture":0},"south":{"uv":[56,4,64,16],"texture":0},"west":{"uv":[52,4,56,16],"texture":0},"up":{"uv":[52,4,44,0],"texture":0},"down":{"uv":[60,0,52,4],"texture":0}},"type":"cube","uuid":"39cd0047-8c4e-0c56-9ba0-6821e5288d85"},{"name":"right_sleeve","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[4,12,-2],"to":[8,24,2],"autouv":0,"color":3,"inflate":0.3,"origin":[0,0,0],"uv_offset":[0,32],"faces":{"north":{"uv":[4,36,8,48],"texture":0},"east":{"uv":[0,36,4,48],"texture":0},"south":{"uv":[12,36,16,48],"texture":0},"west":{"uv":[8,36,12,48],"texture":0},"up":{"uv":[8,36,4,32],"texture":0},"down":{"uv":[12,32,8,36],"texture":0}},"type":"cube","uuid":"980d2769-4452-dfb8-65e0-279fe928b4dc"},{"name":"left_sleeve","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-8,12,-2],"to":[-4,24,2],"autouv":0,"color":0,"mirror_uv":true,"inflate":0.3,"origin":[0,0,0],"uv_offset":[0,32],"faces":{"north":{"uv":[8,36,4,48],"texture":0},"east":{"uv":[12,36,8,48],"texture":0},"south":{"uv":[16,36,12,48],"texture":0},"west":{"uv":[4,36,0,48],"texture":0},"up":{"uv":[4,36,8,32],"texture":0},"down":{"uv":[8,32,12,36],"texture":0}},"type":"cube","uuid":"a67ab72a-fddc-6238-2450-0efdf132c8f1"},{"name":"right_skirt","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[1.75,0.25,-2],"to":[5.75,12.25,2],"autouv":0,"color":1,"mirror_uv":true,"inflate":0.4,"rotation":[0,0,7.5],"origin":[1.75,0.25,0],"uv_offset":[48,32],"faces":{"north":{"uv":[56,36,52,48],"texture":0},"east":{"uv":[60,36,56,48],"texture":0},"south":{"uv":[64,36,60,48],"texture":0},"west":{"uv":[52,36,48,48],"texture":0},"up":{"uv":[52,36,56,32],"texture":0},"down":{"uv":[56,32,60,36],"texture":0}},"type":"cube","uuid":"9f17843d-d8f7-54ed-8955-46c9f9b16c58"},{"name":"left_skirt","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-5.85,0.25,-2],"to":[-1.85,12.25,2],"autouv":0,"color":6,"inflate":0.4,"rotation":[0,0,-7.5],"origin":[-1.75,-0.25,0],"uv_offset":[48,32],"faces":{"north":{"uv":[52,36,56,48],"texture":0},"east":{"uv":[48,36,52,48],"texture":0},"south":{"uv":[60,36,64,48],"texture":0},"west":{"uv":[56,36,60,48],"texture":0},"up":{"uv":[56,36,52,32],"texture":0},"down":{"uv":[60,32,56,36],"texture":0}},"type":"cube","uuid":"948db43e-cb45-4d54-b8c9-2fff5114297d"},{"name":"left_boot","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,0,-2],"to":[0,3,2],"autouv":0,"color":9,"inflate":0.3,"origin":[0,0,0],"uv_offset":[16,41],"faces":{"north":{"uv":[20,45,24,48],"texture":0},"east":{"uv":[16,45,20,48],"texture":0},"south":{"uv":[28,45,32,48],"texture":0},"west":{"uv":[24,45,28,48],"texture":0},"up":{"uv":[24,45,20,41],"texture":0},"down":{"uv":[28,41,24,45],"texture":0}},"type":"cube","uuid":"79498393-90f7-57dc-503c-6574ada461b9"},{"name":"right_boot","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[0,0,-2],"to":[4,3,2],"autouv":0,"color":2,"inflate":0.3,"origin":[0,0,0],"uv_offset":[16,41],"faces":{"north":{"uv":[20,45,24,48],"texture":0},"east":{"uv":[16,45,20,48],"texture":0},"south":{"uv":[28,45,32,48],"texture":0},"west":{"uv":[24,45,28,48],"texture":0},"up":{"uv":[24,45,20,41],"texture":0},"down":{"uv":[28,41,24,45],"texture":0}},"type":"cube","uuid":"ef919b63-e2e6-f0f2-daa2-f3617e632db6"}],"groups":[{"name":"head","uuid":"fd15bc83-0616-6b91-4dc0-205078c28696","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4,32,-4],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"horns","uuid":"392fe1f0-1ca6-16cb-3fdf-f4df1acbea50","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[4.8,32.2,0],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":false,"primary_selected":false},{"name":"body","uuid":"3ce8c80e-9c6b-c2c7-d890-65103951659b","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"leftArm","uuid":"8b7e8f66-6842-18bf-5ec6-ed8186b30dcc","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[4,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"rightArm","uuid":"3f6f3a5d-40f0-79e0-f4c7-8260f3f17f66","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-8,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"rightLeg","uuid":"ad7f6d7b-a515-346a-234d-92719a8f6f03","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[2,12.25,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"leftLeg","uuid":"89bec69e-bfd8-c0e8-d1df-5948a74a5ae4","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4.1,12.5,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false}],"outliner":[{"uuid":"fd15bc83-0616-6b91-4dc0-205078c28696","isOpen":true,"children":["c5b38b99-6a56-d9ff-e64c-7b6f865f9a78","1581b57e-00c2-c3a2-d822-b969220a28d4",{"uuid":"392fe1f0-1ca6-16cb-3fdf-f4df1acbea50","isOpen":false,"children":["6964045e-8723-0987-f243-5ea5477fe7de","f33f09f2-5156-ad5f-6a83-b6ec43dd94ba"]}]},{"uuid":"3ce8c80e-9c6b-c2c7-d890-65103951659b","isOpen":true,"children":["39cd0047-8c4e-0c56-9ba0-6821e5288d85","e8531e9d-18f6-891f-90e4-7521fdc4d333"]},{"uuid":"3f6f3a5d-40f0-79e0-f4c7-8260f3f17f66","isOpen":true,"children":["980d2769-4452-dfb8-65e0-279fe928b4dc"]},{"uuid":"8b7e8f66-6842-18bf-5ec6-ed8186b30dcc","isOpen":true,"children":["a67ab72a-fddc-6238-2450-0efdf132c8f1"]},{"uuid":"ad7f6d7b-a515-346a-234d-92719a8f6f03","isOpen":true,"children":["9f17843d-d8f7-54ed-8955-46c9f9b16c58","ef919b63-e2e6-f0f2-daa2-f3617e632db6"]},{"uuid":"89bec69e-bfd8-c0e8-d1df-5948a74a5ae4","isOpen":true,"children":["948db43e-cb45-4d54-b8c9-2fff5114297d","79498393-90f7-57dc-503c-6574ada461b9"]}],"textures":[{"name":"","path":"","folder":"","namespace":"","id":"0","group":"","scope":0,"width":64,"height":64,"uv_width":64,"uv_height":64,"particle":false,"use_as_default":false,"layers_enabled":false,"sync_to_project":"","file_format":"png","render_mode":"default","render_sides":"auto","wrap_mode":"limited","pbr_channel":"color","fps":7,"frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"internal":true,"saved":false,"uuid":"76798d81-bebb-9cf7-cb53-4b3c6019c51a","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAFt0lEQVR4XmNcE7ny/9NP7xjeffvG8Ozja4YXH94wbL43h5EBCuode/8zUABSZ9sziEjJMbx59ohBRsWEkYFCIMypQZF73n6/geIGluBlYQwP379n+PjpM4O+gjzFDkT33/s3r+BCP769+o8cECA+B5cYyXbyc4gwCLALws398PM9mP3xxxswTUge2Y1MP7+/ZmB5d4+B6cVVhmNbF/9noDLQtfBiBMU8KCBAngcZD/L4kztn/sP45FgJ8zRIL3JgwMwiJA9Tx/j/74P//37UM/x9+Jrh/e3TDJ+f/mO4du4fw+EjHxm6b/xjJJTkQKGNzwP33h9BieHLJ7b9FxQRYwAFCChwSPU8tbMAo5GE739QaIGSD3r+ADmO2gFAbw8Tso/l3IvNVM/31M5GsFSGnMdBbGRxEBtZHuQGYtQzMYxwQHEAwEIZWzjikyMl3EGFHHJBh63QQ5cnVj0LqJ6fcmI2RekAl0dzLFJB5uKtWRr3F5OdBWGeJDagsalnIdbnFy8vATdoQOpB1Ze+bsyAZh55flW4/chsXI7CpZ6oLHBgfx/Do5vXwa05kOdBbJDYcCg+wAEAKkFxYZgnfUNaGbCxidFLi4B6+PE23FhkNi67cKlnWnxhPV73gTz4+e1bBlCMgxovIAxig8QINYIImU1pwIDaL8gtPkLmYVNPVBZAjn1sqYDWWQHd4dg8jSxGinqiAgCWCmAeJSb2GYYIwBsAoOoFVsXExMxkAHkchEFskP+Q5WnpX3R7YG5CFkeuCklRT7AOJmY8ADSOgC0ApPhFGSip57GZics9uhIyDKBxjfytmSS1K0hqCQpxcTGAMLLDcHkepAaf3GDJIUQ1hNA9DeODRpEYhjggmALQPY/sX3xyAxEu5EQIy2CPQGLKIFj+B2W5VKMKrH0PHUl5sFel+YQYLr94Avf2kO8Ok5IdYSkEOeUO+QAAxSio9CemwAXVSCC1ID2wJEAwAPDlK5AcqKrDlY3wyVEj6xEb+8jugFWTML0s6HmMlIINplaISx7uH/QAw5aHke0gtd6GWQQyg9jYB6lFdhdyKmAhplQHaUZv0IA8hi2w0C1Dj2lC8sSoR/Y8SD0ohvE1xkBqkN0PCvSJ3tP/gwKQCTlEYWyQh5FDDFtrDl8LD1vAgBwIwleeP2SAsYnJBiBHgkp5mJkgNizmQR4BuRNfqsUV4CC9oJRAl0IQW+wQWz6ELA9nhCVZWHUHEoNlHVhEYDMPJoYrskBmgLMAJEYYGGB1JXJKIKZMQK9eYPOMsORJaWFIqJyApYJnH1HTFDHZDWsKQPY0PstxyWGLcViyJyX5MxAJsKUCQrEPM5oFuRAB5U/0VEDIDdhiH6YHX+FE7Y4SoiwQBVtPbGHLBHMILMRAgUCoYEEPFJhlsAIOZBY+zzPQAIBSAczdMPcQ0xXH6DuDqgdCNQDDIAbofYHZ5zrwjg9glAHInmcYAWB0bhBbfmYYQQAjfyCvGcIXDrDmKKhRMpjCC1SGkeIejCyA3l3EZRisOToYEwuhcgxZHiMASOmdkduTG0yBhrMQJNTBGMzFBLZGFnKsI8tjDQBC2WAwJ39QxIDqfpiHkT0OYyO3DbAOioKSNqgwxNachKUMYpM/qQ0TWqUsUKyDWqfIAQPyC84sgCsVDPbYhwUgLJnDaPQWIUwcZwCgj52BDCY19geinADFMGi0CpYNkLMDzNOgVAkLELwtQVgqEIJOiQ3V2Ad5HOZp5AIQFFh4J0aQx85AsYlt8hG28hMW26CF0bD1v7C1wTA50OKKPAa7/6AZZpAYr7AwAzmrRfGlLJAH0ZM7Lj5ILVEzqbDWFbaCD7mQAxUyoNQSPNEU7Ma1+afhq9BxOZpQb43W2YioqTFiS3xQiIKGpd6lfgO7G1t9zDAKRkNgNARGQ2A0BEZDYDQERkNgNARGQ2A0BEZDYDQERkNgNARGQ2CAQwAAcEROeP7rqXUAAAAASUVORK5CYII="}]} \ No newline at end of file diff --git a/art/robes/Robes1.bbmodel b/art/robes/Robes1.bbmodel new file mode 100644 index 0000000000..690b827aa2 --- /dev/null +++ b/art/robes/Robes1.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"5.0","model_format":"modded_entity","box_uv":true},"name":"Robes2","model_identifier":"","modded_entity_entity_class":"","modded_entity_version":"1.17","modded_entity_flip_y":true,"visible_box":[1,1,0],"variable_placeholders":"","multi_file_ruleset":"","variable_placeholder_buttons":[],"timeline_setups":[],"unhandled_root_fields":{},"resolution":{"width":64,"height":64},"elements":[{"name":"hood_outer","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,24,-4],"to":[4,32,4],"autouv":0,"color":3,"inflate":0.4,"origin":[0,0,0],"uv_offset":[0,16],"faces":{"north":{"uv":[8,24,16,32],"texture":0},"east":{"uv":[0,24,8,32],"texture":0},"south":{"uv":[24,24,32,32],"texture":0},"west":{"uv":[16,24,24,32],"texture":0},"up":{"uv":[16,24,8,16],"texture":0},"down":{"uv":[24,16,16,24],"texture":0}},"type":"cube","uuid":"b2301383-7b8a-8d9f-c284-318663224705"},{"name":"hood_inner","box_uv":true,"render_order":"behind","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,24,-4],"to":[4,32,4],"autouv":0,"color":0,"inflate":0.3,"origin":[0,0,0],"faces":{"north":{"uv":[8,8,16,16],"texture":0},"east":{"uv":[0,8,8,16],"texture":0},"south":{"uv":[24,8,32,16],"texture":0},"west":{"uv":[16,8,24,16],"texture":0},"up":{"uv":[16,8,8,0],"texture":0},"down":{"uv":[24,0,16,8],"texture":0}},"type":"cube","uuid":"cec6b116-5e7e-77d1-1f1a-e56dfe32702c"},{"name":"right_horn","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-8.25,34.25,0],"to":[-0.25,38.25,0],"autouv":0,"color":6,"rotation":[0,0,-90],"origin":[-4.25,36.25,0],"uv_offset":[24,0],"faces":{"north":{"uv":[24,0,32,4],"texture":0},"east":{"uv":[24,0,24,4],"texture":0},"south":{"uv":[32,0,40,4],"texture":0},"west":{"uv":[32,0,32,4],"texture":0},"up":{"uv":[32,0,24,0],"texture":0},"down":{"uv":[40,0,32,0],"texture":0}},"type":"cube","uuid":"cae1f41b-7569-26aa-acc4-3ed8d8815444"},{"name":"tunic_outer","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,12,-2],"to":[4,24,2],"autouv":0,"color":7,"inflate":0.4,"origin":[0,0,0],"uv_offset":[40,16],"faces":{"north":{"uv":[44,20,52,32],"texture":0},"east":{"uv":[40,20,44,32],"texture":0},"south":{"uv":[56,20,64,32],"texture":0},"west":{"uv":[52,20,56,32],"texture":0},"up":{"uv":[52,20,44,16],"texture":0},"down":{"uv":[60,16,52,20],"texture":0}},"type":"cube","uuid":"a19f6d42-3fe9-bb4c-480e-d6574977d99f"},{"name":"tunic_inner","box_uv":true,"render_order":"behind","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,12,-2],"to":[4,24,2],"autouv":0,"color":3,"inflate":0.3,"origin":[0,0,0],"uv_offset":[40,0],"faces":{"north":{"uv":[44,4,52,16],"texture":0},"east":{"uv":[40,4,44,16],"texture":0},"south":{"uv":[56,4,64,16],"texture":0},"west":{"uv":[52,4,56,16],"texture":0},"up":{"uv":[52,4,44,0],"texture":0},"down":{"uv":[60,0,52,4],"texture":0}},"type":"cube","uuid":"d6c0c5b1-527b-cf1f-061a-36c7e9bb98db"},{"name":"left_sleeve","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-8,12,-2],"to":[-4,24,2],"autouv":0,"color":3,"mirror_uv":true,"inflate":0.3,"origin":[0,0,0],"uv_offset":[0,32],"faces":{"north":{"uv":[8,36,4,48],"texture":0},"east":{"uv":[12,36,8,48],"texture":0},"south":{"uv":[16,36,12,48],"texture":0},"west":{"uv":[4,36,0,48],"texture":0},"up":{"uv":[4,36,8,32],"texture":0},"down":{"uv":[8,32,12,36],"texture":0}},"type":"cube","uuid":"818aa72b-cef1-58e9-725c-5eaa37f7b9dc"},{"name":"right_sleeve","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[4,12,-2],"to":[8,24,2],"autouv":0,"color":7,"inflate":0.3,"origin":[0,0,0],"uv_offset":[0,32],"faces":{"north":{"uv":[4,36,8,48],"texture":0},"east":{"uv":[0,36,4,48],"texture":0},"south":{"uv":[12,36,16,48],"texture":0},"west":{"uv":[8,36,12,48],"texture":0},"up":{"uv":[8,36,4,32],"texture":0},"down":{"uv":[12,32,8,36],"texture":0}},"type":"cube","uuid":"dbf8c827-9338-7729-bb47-4f346cdf3592"},{"name":"left_skirt","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,0,-2],"to":[0,12,2],"autouv":0,"color":8,"inflate":0.4,"origin":[-4,0,0],"uv_offset":[48,32],"faces":{"north":{"uv":[52,36,56,48],"texture":0},"east":{"uv":[48,36,52,48],"texture":0},"south":{"uv":[60,36,64,48],"texture":0},"west":{"uv":[56,36,60,48],"texture":0},"up":{"uv":[56,36,52,32],"texture":0},"down":{"uv":[60,32,56,36],"texture":0}},"type":"cube","uuid":"22bfadf3-71a3-962a-553b-5d9aff88ddc3"},{"name":"right_skirt","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[0,0,-2],"to":[4,12,2],"autouv":0,"color":8,"mirror_uv":true,"inflate":0.4,"origin":[4,0,0],"uv_offset":[48,32],"faces":{"north":{"uv":[56,36,52,48],"texture":0},"east":{"uv":[60,36,56,48],"texture":0},"south":{"uv":[64,36,60,48],"texture":0},"west":{"uv":[52,36,48,48],"texture":0},"up":{"uv":[52,36,56,32],"texture":0},"down":{"uv":[56,32,60,36],"texture":0}},"type":"cube","uuid":"1f6091bd-5faa-e333-da79-c6c57a92952a"},{"name":"left_boot","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,0,-2],"to":[0,4,2],"autouv":0,"color":8,"inflate":0.3,"origin":[0,0,0],"uv_offset":[16,40],"faces":{"north":{"uv":[20,44,24,48],"texture":0},"east":{"uv":[16,44,20,48],"texture":0},"south":{"uv":[28,44,32,48],"texture":0},"west":{"uv":[24,44,28,48],"texture":0},"up":{"uv":[24,44,20,40],"texture":0},"down":{"uv":[28,40,24,44],"texture":0}},"type":"cube","uuid":"5a38ae46-c69d-e663-6bf0-db99aa735735"},{"name":"right_boot","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[0,0,-2],"to":[4,4,2],"autouv":0,"color":4,"inflate":0.3,"origin":[0,0,0],"uv_offset":[16,40],"faces":{"north":{"uv":[20,44,24,48],"texture":0},"east":{"uv":[16,44,20,48],"texture":0},"south":{"uv":[28,44,32,48],"texture":0},"west":{"uv":[24,44,28,48],"texture":0},"up":{"uv":[24,44,20,40],"texture":0},"down":{"uv":[28,40,24,44],"texture":0}},"type":"cube","uuid":"60e41237-317f-4c78-8b20-dab88a2ba123"},{"name":"left_horn","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[0.25,34.25,0],"to":[8.25,38.25,0],"autouv":0,"color":7,"mirror_uv":true,"rotation":[0,0,90],"origin":[4.25,36.25,0],"uv_offset":[24,0],"faces":{"north":{"uv":[32,0,24,4],"texture":0},"east":{"uv":[32,0,32,4],"texture":0},"south":{"uv":[40,0,32,4],"texture":0},"west":{"uv":[24,0,24,4],"texture":0},"up":{"uv":[24,0,32,0],"texture":0},"down":{"uv":[32,0,40,0],"texture":0}},"type":"cube","uuid":"c3b4c436-d99b-e573-ef06-7f6c2bd3370f"}],"groups":[{"name":"head","uuid":"a98bbf19-0b66-952c-1616-51351bc4fde0","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4,32,-4],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"body","uuid":"a946c104-4b18-70b2-14d4-8c06829849be","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"rightArm","uuid":"26a798c8-f71d-51b0-0be9-e11439c93c86","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[4,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"leftArm","uuid":"759c4eae-7953-1987-4504-74b1555e5c39","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-8,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"leftLeg","uuid":"46e6c36b-8782-ecc4-f6be-415512f92d4a","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4,12,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"rightLeg","uuid":"e5bb982a-468b-c3e8-d99f-7b7a594eefed","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[0,12,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"horns","uuid":"5e0675dc-8bb1-c564-3970-d9333592e0b3","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4.25,36.25,0],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false}],"outliner":[{"uuid":"a98bbf19-0b66-952c-1616-51351bc4fde0","isOpen":true,"children":["cec6b116-5e7e-77d1-1f1a-e56dfe32702c","b2301383-7b8a-8d9f-c284-318663224705",{"uuid":"5e0675dc-8bb1-c564-3970-d9333592e0b3","isOpen":true,"children":["cae1f41b-7569-26aa-acc4-3ed8d8815444","c3b4c436-d99b-e573-ef06-7f6c2bd3370f"]}]},{"uuid":"a946c104-4b18-70b2-14d4-8c06829849be","isOpen":true,"children":["d6c0c5b1-527b-cf1f-061a-36c7e9bb98db","a19f6d42-3fe9-bb4c-480e-d6574977d99f"]},{"uuid":"26a798c8-f71d-51b0-0be9-e11439c93c86","isOpen":true,"children":["dbf8c827-9338-7729-bb47-4f346cdf3592"]},{"uuid":"759c4eae-7953-1987-4504-74b1555e5c39","isOpen":true,"children":["818aa72b-cef1-58e9-725c-5eaa37f7b9dc"]},{"uuid":"e5bb982a-468b-c3e8-d99f-7b7a594eefed","isOpen":true,"children":["1f6091bd-5faa-e333-da79-c6c57a92952a","60e41237-317f-4c78-8b20-dab88a2ba123"]},{"uuid":"46e6c36b-8782-ecc4-f6be-415512f92d4a","isOpen":true,"children":["22bfadf3-71a3-962a-553b-5d9aff88ddc3","5a38ae46-c69d-e663-6bf0-db99aa735735"]}],"textures":[{"name":"","path":"","folder":"","namespace":"","id":"0","group":"","scope":0,"width":64,"height":64,"uv_width":64,"uv_height":64,"particle":false,"use_as_default":false,"layers_enabled":false,"sync_to_project":"","file_format":"png","render_mode":"default","render_sides":"auto","wrap_mode":"limited","pbr_channel":"color","fps":7,"frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"internal":true,"saved":false,"uuid":"ae10bf54-61f3-91d7-642d-574fba3483bc","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAGA0lEQVR4XmNcE7ny/9NP7xjeffvG8Ozja4YXH94wbL43h5EBCuode/8zUABSZ9sziEjJMbx59ohBRsWEkYFCIMypQZF73n6/geIGluBlYQwP379n+PjpM4O+gjzFDkT33/s3r+BCP769+o8cECA+B5cYyXbyc4gwCLALws398PM9mP3xxxswTUge2Y1MP7+/ZmB5d4+B6cVVhmNbF/9noDLQtfBiBMU8KCBAngcZD/L4kztn/sP45FgJ8zRIL3JgwMwiJA9Tx/j/74P//37UM/x9+Jrh/e3TDJ+f/mO4du4fw+EjHxm6b/xjJJTkQKGNzwP33h9BieHLJ7b9FxQRYwAFCChwSPU8tbMAo5GE739QaIGSD3r+ADmO2gFAbw8Tso/l3IvNVM/31M5GsFSGnMdBbGRxEBtZHuQGYtQzMYxwQHEAwEIZWzjikyMl3EGFHHJBh63QQ5cnVj0LqJ6fcmI2RekAl0dzLFJB5uKtWRr3F5OdBWGeJDagsalnIdbnFy8vATdoQOpB1Ze+bsyAZh55flW4/chsXI7CpZ6oLHBgfx/Do5vXwa05kOdBbJDYcCg+wAEAKkFxYZgnfUNaGbCxidFLi4B6+PE23FhkNi67cKlnWnxhPV73gTz4+e1bBlCMgxovIAxig8QINYIImU1pwIDaL8gtPkLmYVNPVBZAjn1sqYDWWQHd4dg8jSxGinqiAgCWCmAeJSb2GYYIwBsAoOoFVsXExMxkAHkchEFskP+Q5WnpX3R7YG5CFkeuCklRT7AOJmY8ADSOgC0ApPhFGSip57GZieyeyq2xYCXt3ovhSkm1j4WUmBPi4gIrBw2ewPTh8jxIHp8cNVIMJd1pmP1EBQDM4zBN2AKCYQCAnWkB2NZYg0CybSdYCKJ7HtkmfHIMQwSwDHZ3TvSejtKXAGU/WMA7K9ow7L1/hAE5RaKrJ+S/Qd8dRi5vkD0P8ljeNDsGFcX3DMhZE109oQBgYRjCYFLWIYY794GDo5KEPYEcMMhZl2AKQNaIbg1IDlTV4bIenxw1wr1+VQhKCsBnJrKnkf3EiF7PU1qw4Qsw5KQKY+dvzcTbFsHWDoG58crzh+AyIN8qGmwczG5SaimULIDL8yCD0RsYIIdhUw8SwxcIhORJSRmgMuBh1mYGbCmTWHOYsMUKyAPInsDWusLX4sIWMKBGEQiDYg3GpiQbgNwHKwOISXUgu2D2IttPl1oAW4uQGuUDKWUAuhtg9rMgQoaBQUdSHiVSQCFLTJmALe/BLARZRIlnzz28jjOhNIa9BtcC7ILXCSYmI3lNFDUwc7FWg8j5FF8hBZLD1vDAFuO4YoCQy100jRmk+YTAykCTuCAGjG/RrMzwMGwzQ7y6K1Z5mHqQ5J7rZ1GsApkLEgAHACiGYPkTPRUQciC+khdmLjYziO0ooTsc2awQlXBwDcL+YTfekWcJAREG9IAElUWgmXAWkENgyRQWCCA+KaU1TC1ysgc5lFhP4gtk5Kl6XOoIqfFVSvkP8iy6fpA+jDoYlKQJ1QAMgxigtxsIjQ9g1ALEVikMwwSMzg2iRySlTeGhljAwygDkNUP4PAMKKFB1FLI8fFBNryNXy7hqKORIxsgCoLoTVs/iCwCQGuR6drDEPCllGEgtRgAQ6p0he5QUtfQKIOSqFxTTyLGNzgepxVkI4isLBnM5ga2+xxX44IYQNklYNsCVnEhJ/gGaqSittA3XZ9O8zCCmDwPzG9YUAEva2GIaJjYYkz8sMolpgcLU4MwCuArDwVr4wTwPat6Ckja+whAkB1sRizMAsKWCoRD7yKkA5FHkgIDxkVMI3lFh9FRAbOyDVoKCHAJaBkuPPI9ejoFSAa4OEHJKAbEJFkighgVyfxw978NWfsIMBi2Mhq3/ha0NhsnB1g2DZphBYrzCwgzkrBZloCIgqkSGta6wFXzIpby+hAZ4liZ4oinYiWvzT4NXoV98cQOnkwcihSA7hqiJEWJLfJhH36V+A9uBz+MMo2A0BEZDYDQERkNgNARGQ2A0BEZDYDQERkNgNARGQ2A0BEZDYDQEBigEAN50R9GhN7dUAAAAAElFTkSuQmCC"}]} \ No newline at end of file diff --git a/art/robes/Robes2.bbmodel b/art/robes/Robes2.bbmodel new file mode 100644 index 0000000000..62efa53758 --- /dev/null +++ b/art/robes/Robes2.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"5.0","model_format":"modded_entity","box_uv":true},"name":"Robes2","model_identifier":"","modded_entity_entity_class":"","modded_entity_version":"1.17","modded_entity_flip_y":true,"visible_box":[1,1,0],"variable_placeholders":"","multi_file_ruleset":"","variable_placeholder_buttons":[],"timeline_setups":[],"unhandled_root_fields":{},"resolution":{"width":64,"height":64},"elements":[{"name":"hood_outer","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,24,-4],"to":[4,32,4],"autouv":0,"color":4,"inflate":0.4,"origin":[0,0,0],"uv_offset":[0,16],"faces":{"north":{"uv":[8,24,16,32],"texture":0},"east":{"uv":[0,24,8,32],"texture":0},"south":{"uv":[24,24,32,32],"texture":0},"west":{"uv":[16,24,24,32],"texture":0},"up":{"uv":[16,24,8,16],"texture":0},"down":{"uv":[24,16,16,24],"texture":0}},"type":"cube","uuid":"bb31bdb7-b4f5-8fd6-0631-ad789263fce7"},{"name":"hood_inner","box_uv":true,"render_order":"behind","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,24,-4],"to":[4,32,4],"autouv":0,"color":8,"inflate":0.3,"origin":[0,0,0],"faces":{"north":{"uv":[8,8,16,16],"texture":0},"east":{"uv":[0,8,8,16],"texture":0},"south":{"uv":[24,8,32,16],"texture":0},"west":{"uv":[16,8,24,16],"texture":0},"up":{"uv":[16,8,8,0],"texture":0},"down":{"uv":[24,0,16,8],"texture":0}},"type":"cube","uuid":"7c76db23-25f3-7b95-ac9f-2e9bcf0f9759"},{"name":"body_outer","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,12,-2],"to":[4,24,2],"autouv":0,"color":5,"inflate":0.4,"origin":[0,0,0],"uv_offset":[40,16],"faces":{"north":{"uv":[44,20,52,32],"texture":0},"east":{"uv":[40,20,44,32],"texture":0},"south":{"uv":[56,20,64,32],"texture":0},"west":{"uv":[52,20,56,32],"texture":0},"up":{"uv":[52,20,44,16],"texture":0},"down":{"uv":[60,16,52,20],"texture":0}},"type":"cube","uuid":"94261ed0-a8a6-8d18-ac42-13127515d848"},{"name":"body_inner","box_uv":true,"render_order":"behind","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,12,-2],"to":[4,24,2],"autouv":0,"color":3,"inflate":0.3,"origin":[0,0,0],"uv_offset":[40,0],"faces":{"north":{"uv":[44,4,52,16],"texture":0},"east":{"uv":[40,4,44,16],"texture":0},"south":{"uv":[56,4,64,16],"texture":0},"west":{"uv":[52,4,56,16],"texture":0},"up":{"uv":[52,4,44,0],"texture":0},"down":{"uv":[60,0,52,4],"texture":0}},"type":"cube","uuid":"bd4844dd-2a0e-3f4e-fa0b-7da3d2887e40"},{"name":"left_sleeve","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-8,12,-2],"to":[-4,24,2],"autouv":0,"color":3,"mirror_uv":true,"inflate":0.3,"origin":[0,0,0],"uv_offset":[0,32],"faces":{"north":{"uv":[8,36,4,48],"texture":0},"east":{"uv":[12,36,8,48],"texture":0},"south":{"uv":[16,36,12,48],"texture":0},"west":{"uv":[4,36,0,48],"texture":0},"up":{"uv":[4,36,8,32],"texture":0},"down":{"uv":[8,32,12,36],"texture":0}},"type":"cube","uuid":"9c87cab3-03d4-97ee-21bd-9815d0e98d53"},{"name":"right_sleeve","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[4,12,-2],"to":[8,24,2],"autouv":0,"color":0,"inflate":0.3,"origin":[0,0,0],"uv_offset":[0,32],"faces":{"north":{"uv":[4,36,8,48],"texture":0},"east":{"uv":[0,36,4,48],"texture":0},"south":{"uv":[12,36,16,48],"texture":0},"west":{"uv":[8,36,12,48],"texture":0},"up":{"uv":[8,36,4,32],"texture":0},"down":{"uv":[12,32,8,36],"texture":0}},"type":"cube","uuid":"fd5e025b-d5f6-8bd3-d981-66783aa2a923"},{"name":"right_legging","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[0,0,-2],"to":[4,12,2],"autouv":0,"color":3,"inflate":0.35,"origin":[0,0,0],"uv_offset":[48,32],"faces":{"north":{"uv":[52,36,56,48],"texture":0},"east":{"uv":[48,36,52,48],"texture":0},"south":{"uv":[60,36,64,48],"texture":0},"west":{"uv":[56,36,60,48],"texture":0},"up":{"uv":[56,36,52,32],"texture":0},"down":{"uv":[60,32,56,36],"texture":0}},"type":"cube","uuid":"e035f1e5-f5da-d86a-efe6-d73b506ae82e"},{"name":"left_legging","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,0,-2],"to":[0,12,2],"autouv":0,"color":9,"mirror_uv":true,"inflate":0.35,"origin":[0,0,0],"uv_offset":[48,32],"faces":{"north":{"uv":[56,36,52,48],"texture":0},"east":{"uv":[60,36,56,48],"texture":0},"south":{"uv":[64,36,60,48],"texture":0},"west":{"uv":[52,36,48,48],"texture":0},"up":{"uv":[52,36,56,32],"texture":0},"down":{"uv":[56,32,60,36],"texture":0}},"type":"cube","uuid":"92e4165d-8268-5063-8211-7221aae1b76e"},{"name":"left_boot","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4,0,-2],"to":[0,4,2],"autouv":0,"color":2,"inflate":0.3,"origin":[0,0,0],"uv_offset":[16,40],"faces":{"north":{"uv":[20,44,24,48],"texture":0},"east":{"uv":[16,44,20,48],"texture":0},"south":{"uv":[28,44,32,48],"texture":0},"west":{"uv":[24,44,28,48],"texture":0},"up":{"uv":[24,44,20,40],"texture":0},"down":{"uv":[28,40,24,44],"texture":0}},"type":"cube","uuid":"0c26f55d-2961-ea9c-ea83-843b23d37a98"},{"name":"right_boot","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[0,0,-2],"to":[4,4,2],"autouv":0,"color":3,"inflate":0.3,"origin":[0,0,0],"uv_offset":[16,40],"faces":{"north":{"uv":[20,44,24,48],"texture":0},"east":{"uv":[16,44,20,48],"texture":0},"south":{"uv":[28,44,32,48],"texture":0},"west":{"uv":[24,44,28,48],"texture":0},"up":{"uv":[24,44,20,40],"texture":0},"down":{"uv":[28,40,24,44],"texture":0}},"type":"cube","uuid":"3bb185dc-1abc-3fe5-b883-7af7889a4f3f"},{"name":"strap","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-9.8,11.95,-3],"to":[0.2,14.95,3],"autouv":0,"color":2,"mirror_uv":true,"rotation":[0,0,-22.5],"origin":[-0.75,1.75,0],"uv_offset":[0,48],"faces":{"north":{"uv":[16,54,6,57],"texture":0},"east":{"uv":[22,54,16,57],"texture":0},"south":{"uv":[32,54,22,57],"texture":0},"west":{"uv":[6,54,0,57],"texture":0},"up":{"uv":[6,54,16,48],"texture":0},"down":{"uv":[16,48,26,54],"texture":0}},"type":"cube","uuid":"5595171c-e809-03ca-68ed-7115d9ffbb94"},{"name":"buckle","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-4.95,14.1,-3],"to":[-1.95,17.1,3],"autouv":0,"color":6,"mirror_uv":true,"inflate":0.1,"origin":[-0.75,0,0],"uv_offset":[32,48],"faces":{"north":{"uv":[41,54,38,57],"texture":0},"east":{"uv":[47,54,41,57],"texture":0},"south":{"uv":[50,54,47,57],"texture":0},"west":{"uv":[38,54,32,57],"texture":0},"up":{"uv":[38,54,41,48],"texture":0},"down":{"uv":[41,48,44,54],"texture":0}},"type":"cube","uuid":"4cb47817-d5c8-81f7-ce53-eddcf011ee3e"},{"name":"right_horn","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[4,28.5,0],"to":[12,36.5,0],"autouv":0,"color":0,"mirror_uv":true,"rotation":[0,0,75],"origin":[5,32.5,0],"uv_offset":[24,0],"faces":{"north":{"uv":[32,0,24,8],"texture":0},"east":{"uv":[32,0,32,8],"texture":0},"south":{"uv":[40,0,32,8],"texture":0},"west":{"uv":[24,0,24,8],"texture":0},"up":{"uv":[24,0,32,0],"texture":0},"down":{"uv":[32,0,40,0],"texture":0}},"type":"cube","uuid":"00b324ac-7d37-b5d8-4201-5e85760400af"},{"name":"left_horn","box_uv":true,"render_order":"default","locked":false,"export":true,"scope":0,"allow_mirror_modeling":true,"from":[-12,28.6,0],"to":[-4,36.6,0],"autouv":0,"color":0,"rotation":[0,0,-75],"origin":[-5,32.6,0],"uv_offset":[24,0],"faces":{"north":{"uv":[24,0,32,8],"texture":0},"east":{"uv":[24,0,24,8],"texture":0},"south":{"uv":[32,0,40,8],"texture":0},"west":{"uv":[32,0,32,8],"texture":0},"up":{"uv":[32,0,24,0],"texture":0},"down":{"uv":[40,0,32,0],"texture":0}},"type":"cube","uuid":"a9e5e1e6-b585-094b-da8c-835678984610"}],"groups":[{"name":"head","uuid":"340a6871-310d-6a24-43ff-ddf85346d82f","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4,32,-4],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"body","uuid":"303b4664-b31a-5ba5-b6bf-ed9ee71370bb","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"rightArm","uuid":"d74e7c20-c22d-d9d4-9aef-4faded63fc4e","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[4,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"leftArm","uuid":"63506f26-b3de-59cb-b312-386615c5bc0d","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-8,24,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"rightLeg","uuid":"e46d3e87-8f26-2f4d-963a-bdf55792cfa6","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[0,12,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"leftLeg","uuid":"39fd2105-d958-5410-6032-afffb1ec9e1d","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[-4,12,-2],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false},{"name":"sash","uuid":"01148eb6-5484-1b29-ae31-deabde803a47","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[5.45,13.2,-3],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":false,"primary_selected":true},{"name":"horns","uuid":"05a5b561-43ff-8683-4ce7-978731e9d8c5","export":true,"locked":false,"scope":0,"selected":false,"_static":{"properties":{},"temp_data":{}},"origin":[5,32.5,0],"rotation":[0,0,0],"color":0,"children":[],"reset":false,"shade":true,"mirror_uv":false,"visibility":true,"autouv":0,"isOpen":true,"primary_selected":false}],"outliner":[{"uuid":"340a6871-310d-6a24-43ff-ddf85346d82f","isOpen":true,"children":[{"uuid":"05a5b561-43ff-8683-4ce7-978731e9d8c5","isOpen":true,"children":["00b324ac-7d37-b5d8-4201-5e85760400af","a9e5e1e6-b585-094b-da8c-835678984610"]},"7c76db23-25f3-7b95-ac9f-2e9bcf0f9759","bb31bdb7-b4f5-8fd6-0631-ad789263fce7"]},{"uuid":"303b4664-b31a-5ba5-b6bf-ed9ee71370bb","isOpen":true,"children":["bd4844dd-2a0e-3f4e-fa0b-7da3d2887e40","94261ed0-a8a6-8d18-ac42-13127515d848",{"uuid":"01148eb6-5484-1b29-ae31-deabde803a47","isOpen":false,"children":["5595171c-e809-03ca-68ed-7115d9ffbb94","4cb47817-d5c8-81f7-ce53-eddcf011ee3e"]}]},{"uuid":"d74e7c20-c22d-d9d4-9aef-4faded63fc4e","isOpen":true,"children":["fd5e025b-d5f6-8bd3-d981-66783aa2a923"]},{"uuid":"63506f26-b3de-59cb-b312-386615c5bc0d","isOpen":true,"children":["9c87cab3-03d4-97ee-21bd-9815d0e98d53"]},{"uuid":"e46d3e87-8f26-2f4d-963a-bdf55792cfa6","isOpen":true,"children":["e035f1e5-f5da-d86a-efe6-d73b506ae82e","3bb185dc-1abc-3fe5-b883-7af7889a4f3f"]},{"uuid":"39fd2105-d958-5410-6032-afffb1ec9e1d","isOpen":true,"children":["92e4165d-8268-5063-8211-7221aae1b76e","0c26f55d-2961-ea9c-ea83-843b23d37a98"]}],"textures":[{"name":"","path":"","folder":"","namespace":"","id":"0","group":"","scope":0,"width":64,"height":64,"uv_width":64,"uv_height":64,"particle":false,"use_as_default":false,"layers_enabled":false,"sync_to_project":"","file_format":"png","render_mode":"default","render_sides":"auto","wrap_mode":"limited","pbr_channel":"color","fps":7,"frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"internal":true,"saved":false,"uuid":"af3aae18-9f98-d4de-7b0f-c58cd9965743","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAHOUlEQVR4XmNcE7ny/9NP7xjeffvG8Ozja4YXH94wbL43h5EBCuode/8zUAAa9xczYtP+5M6Z/zIqJoykGi3MqUGRe95+v4FiJ0vwsjCGh+/fM3z89JlBX0GekYHG4PKJbf8FRcQYRKTkyLaJn0OEQYBdEK7/w8/3YPbHH2/ANCF5ZIuZfn5/zcDy7h4D04urDMe2Lv5Pbf+DYvrHt1f/YVhVzwTseQ4uMYoCG+ZpkHuRAwPmfkLyMHWM//8++P/vRz3D34evGd7fPs3w+ek/hmvn/jEcPvKRofvGP0ZCSQ4U2vgCbeP2KgaQp0Fq3jx7BFYKS/qgQCE1IKidBRiNJHz/g0ILlHzQ8wfItZQGwL33RxhBqQBbkgcFCKFygFIPE0rRTOdebGYEORKb56mVHWCeBMX27UtnGEAeB9HEFoKgVIac0mBsZHF0eWLVszDQCYA8TE6Sp7XzmCi1AFbyYjMHWU7XwosRFAig7ECqnaBCDrmgw1boocsTq54FVM9POTGbonDAFQg5Fqkgc+E1y5rK60D+dQbktgWudgIxDoJ5El8kIJuDTT3RWeDi5SXwuhuUh/V1YxgGEsjzq8KtR2bjchMu9URlgQP7+xge3bwOLrxAngexQWIMwwCAAwBWmmKjYX70DWllwMYmRi8twunhx9twY5HZuOzCpZ5p8YX1eN0H8uDnt28ZQDH+/s0rBhAGsUFihBpBhMymNGBA7RfkFh8h87CpJyoLIMc+tlTAQGOA7nBsnkYWI0U9UQEASwUwfxIT+wxDBOANAFD1AqtiYmJmMoA8DsIgNsh/yPK09C+6PTA3IYsjV4WkqCfYIyNmPAA0joAtAKT4RRkoqeexmTnRe/p/aT4hhssvnjBUbo0FK2n3XsygKyHDABrXyN+aSVIvk6SmsBAXF9hC0OAJzHG4PA+SxydHjRQD611SYhZRAQDzOMwibAHBMADAzrQAbGusQSDZthMsBNE9j2wTPjlahQdy6kO3A58cLvewMAxyAMrzyE4EeRKU10Fizoo2DHvvHwFLw8TQ1RPyHtNgDwDkWAWxCaVIdPVDPgCQPYBcqCIHBK5AQVYPChgYRjaTYAoglOdAVR2uUMYnR2zKI7UmwaUeOZCQ/cSCXs+TUrDB1ApxycP9gx5g2NoRyHYQU28Tmw2wRRauCISJoxSCuDwPUozeoAF5DJt6kBi+VENInlDKAMUwcoBjyyLI9oPU40qJIDl4AGBLIjAxbK05kBiuEhebJ2FJ89lHhJOpkUVApr2DzmrhCjxYIKBnD5D9dKkGseVLanke5OlzD6/D/S4hIIISDqCpPpAAiEaWg9kPDgCQA0ExoyMpj6IZFLLElAmwJCeE1FSGeRpkEaWexZaM8WUzbAEO8hi6O0DqsNYCxBZSuAowbA6ABPJrBhjNQCJANpNQkifFaBZYyIAsuPL8IQN6KiBkGLbYh+kBhTiu2MAljm4fLAkji8PEkGax/2sLaoCVYFMPSvrYYh+klgWWvGCOBQUCiE1KaQ1Ti5zsQa4h1pP4Ahl5qh6XOtDMFhDjNMZXKeU/toABmY3RdwaV7Mj5i9r9eQYag1SjCpQZ7tnnOvCOD2CUAfgKF4ZhCJgYRjjACABSmsLDIeww8gfymiF8HgQFFGhsLmR5OONABgRsyQ3IDaA5CxANWoJDLB+jJQgaWAB5jFBZAFIDG4QYyAAATbgKcT0EOwFRJRPPxxp7oFQAGnXF5zHQKOxAxz7IfVRPATBP42sHDKZygtIUgLUzRCgbkJL8Sa2XSc1OIe2aDKTkefQyAmsAgNr4oGyALRXAYp/UCQhalRM0SQEgx+JKBYOl8IMFKE1SAMhwbKlgsMU+yJ00SwHIqQAW2uTEPra2OGyckBr9DEpTAMFGDGwyEhYg6Hkf5BliPQLzOHKvkdJAQB6bxNU1F0Kb00TmE9WKg439YSv4QKU8rPsMCiTkAVR0x2HrHhPqrTHQGFDcjEWv5kDuhQ2qgMYWsLk/b5odWHhS1iGGQRsA2Ja1EzsdjbwuGKQH1EYHLZQkJTJBK9d5hYXBizJA+mBsK+9YqvY98I4Koy9whvFhnkJugODaAwDSA+ukkBIAIA/DzAfpQ2ZTM1fgDADYEnfQ8lZkC5Edgu4xWMAgqweZAzOLFIejByglGyzw2Uv0gAjMI/hiEyRHrocZBgjgTAGg2ASFOizGYXyQB2FlAWjBFCx/gmjkjRHIKYWcpSywgEYOcHKyEqFwxRkAsEWR6EkRWzIHWQJzHCjQkMsK9CxEbETDAhdGg/Qhs6mVYBhxlfYgD2Er2GABAHOMnLomA7ZSH+RAcvSD9GFLMehlALoacnaggexC2c4CMxTmeeRQJuQA9EBAjyFc+nENY8GyFHIKQu/2IqshtZqFuY8FOamD2MhJD1QVoXsEPR/C1CMHGswcYvWD1CGbCzMT5HnkcoaQGoZRMBoCoyEwGgKjITAaAqMhQEoIAAB2ILuJX6i+1wAAAABJRU5ErkJggg=="}]} \ No newline at end of file