From f0b57a2bbf0d0d58a57a26e234dc0772aba0c688 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 16 May 2024 20:31:42 +0100 Subject: [PATCH 01/85] Fix trait serialization. Fixes #342 --- .../unicopia/ability/magic/spell/trait/SpellTraits.java | 2 +- .../unicopia/ability/magic/spell/trait/Trait.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java index 5c9b9ca8..f900ac24 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java @@ -319,7 +319,7 @@ public final class SpellTraits implements Iterable> { public static Stream> streamFromJson(JsonObject traits) { return traits.entrySet().stream().map(entry -> { - Trait trait = Trait.fromName(entry.getKey()).orElse(null); + Trait trait = Trait.fromId(entry.getKey()).orElse(null); if (trait == null || !entry.getValue().isJsonPrimitive() && !entry.getValue().getAsJsonPrimitive().isNumber()) { return null; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/Trait.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/Trait.java index 20b6e151..7c3741ac 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/Trait.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/Trait.java @@ -164,7 +164,11 @@ public enum Trait implements CommandArgumentEnum { } public static Optional fromName(String name) { - return Optional.ofNullable(REGISTRY.getOrDefault(name.toUpperCase(), null)); + Trait trait = REGISTRY.getOrDefault(name.toUpperCase(), null); + if (trait == null) { + Unicopia.LOGGER.error("Unknown trait: " + name); + } + return Optional.ofNullable(trait); } public static EnumArgumentType argument() { From 09cecef68ecab8f9fed90eb189eedd441b676ec4 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 16 May 2024 21:42:58 +0100 Subject: [PATCH 02/85] Fix quick moving items in the spellbook. Fixes #348 --- .../client/gui/spellbook/IngredientTree.java | 4 +- .../gui/spellbook/SpellbookChapterList.java | 10 --- .../SpellbookCraftingPageContent.java | 5 -- .../SpellbookProfilePageContent.java | 5 -- .../client/gui/spellbook/SpellbookScreen.java | 14 +-- .../SpellbookTraitDexPageContent.java | 4 +- .../container/SpellbookScreenHandler.java | 86 +++++++++++++------ .../unicopia/container/SpellbookState.java | 5 ++ 8 files changed, 74 insertions(+), 59 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/IngredientTree.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/IngredientTree.java index 831ea7ca..fb4f6337 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/IngredientTree.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/IngredientTree.java @@ -18,6 +18,8 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.item.TooltipContext; import net.minecraft.client.render.*; import com.minelittlepony.unicopia.client.render.RenderLayers; +import com.minelittlepony.unicopia.container.SpellbookState; + import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.util.math.MatrixStack; @@ -324,7 +326,7 @@ public class IngredientTree implements SpellbookRecipe.CraftingTreeBuilder { @Override public void onClick() { if (MinecraftClient.getInstance().currentScreen instanceof SpellbookScreen spellbook) { - spellbook.getState().setCurrentPageId(SpellbookChapterList.TRAIT_DEX_ID); + spellbook.getState().setCurrentPageId(SpellbookState.TRAIT_DEX_ID); spellbook.getTraitDex().pageTo(spellbook, trait); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookChapterList.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookChapterList.java index 3e91b7a1..6b206793 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookChapterList.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookChapterList.java @@ -6,16 +6,10 @@ import java.util.stream.Stream; import com.minelittlepony.common.client.gui.IViewRoot; import com.minelittlepony.unicopia.Debug; -import com.minelittlepony.unicopia.Unicopia; - import net.minecraft.client.gui.DrawContext; import net.minecraft.util.Identifier; public class SpellbookChapterList { - public static final Identifier CRAFTING_ID = Unicopia.id("crafting"); - public static final Identifier PROFILE_ID = Unicopia.id("profile"); - public static final Identifier TRAIT_DEX_ID = Unicopia.id("traits"); - private final SpellbookScreen screen; private final Chapter craftingChapter; @@ -73,10 +67,6 @@ public class SpellbookChapterList { default void copyStateFrom(Content old) {} - default boolean showInventory() { - return false; - } - default Identifier getIcon(Chapter chapter, Identifier icon) { return icon; } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookCraftingPageContent.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookCraftingPageContent.java index a6fde947..513e4e8f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookCraftingPageContent.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookCraftingPageContent.java @@ -58,11 +58,6 @@ public class SpellbookCraftingPageContent extends ScrollContainer implements Spe init(this::initPageContent); } - @Override - public boolean showInventory() { - return state.getOffset() == 0; - } - private void initPageContent() { getContentPadding().setVertical(10); getContentPadding().bottom = 30; diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java index 65c6ebe2..f0829b23 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java @@ -58,11 +58,6 @@ public class SpellbookProfilePageContent implements SpellbookChapterList.Content } } - @Override - public boolean showInventory() { - return true; - } - @Override public void draw(DrawContext context, int mouseX, int mouseY, IViewRoot container) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java index 20a1dfb7..56ff0539 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java @@ -52,12 +52,11 @@ public class SpellbookScreen extends HandledScreen imple private final RecipeBookWidget recipeBook = new RecipeBookWidget(); - private final Chapter craftingChapter; private final SpellbookTraitDexPageContent traitDex = new SpellbookTraitDexPageContent(this); private final SpellbookChapterList chapters = new SpellbookChapterList(this, - craftingChapter = new Chapter(SpellbookChapterList.CRAFTING_ID, TabSide.LEFT, 0, 0, Optional.of(new SpellbookCraftingPageContent(this))), - new Chapter(SpellbookChapterList.PROFILE_ID, TabSide.LEFT, 1, 0, Optional.of(new SpellbookProfilePageContent(this))), - new Chapter(SpellbookChapterList.TRAIT_DEX_ID, TabSide.LEFT, 3, 0, Optional.of(traitDex)) + new Chapter(SpellbookState.CRAFTING_ID, TabSide.LEFT, 0, 0, Optional.of(new SpellbookCraftingPageContent(this))), + new Chapter(SpellbookState.PROFILE_ID, TabSide.LEFT, 1, 0, Optional.of(new SpellbookProfilePageContent(this))), + new Chapter(SpellbookState.TRAIT_DEX_ID, TabSide.LEFT, 3, 0, Optional.of(traitDex)) ); private final SpellbookTabBar tabs = new SpellbookTabBar(this, chapters); @@ -68,13 +67,6 @@ public class SpellbookScreen extends HandledScreen imple backgroundWidth = 405; backgroundHeight = 219; contentBounds = new Bounds(CONTENT_PADDING, CONTENT_PADDING, backgroundWidth - CONTENT_PADDING * 2, backgroundHeight - CONTENT_PADDING * 3 - 2); - - handler.addSlotShowingCondition(slotType -> { - if (slotType == SlotType.INVENTORY) { - return chapters.getCurrentChapter().content().filter(Content::showInventory).isPresent(); - } - return chapters.getCurrentChapter() == craftingChapter; - }); handler.getSpellbookState().setSynchronizer(state -> { Channel.CLIENT_SPELLBOOK_UPDATE.sendToServer(MsgSpellbookStateChanged.create(handler, state)); }); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookTraitDexPageContent.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookTraitDexPageContent.java index c5f7f347..6322bf1c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookTraitDexPageContent.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookTraitDexPageContent.java @@ -73,7 +73,7 @@ public class SpellbookTraitDexPageContent implements SpellbookChapterList.Conten return; } page /= 2; - state = screen.getState().getState(SpellbookChapterList.TRAIT_DEX_ID); + state = screen.getState().getState(SpellbookState.TRAIT_DEX_ID); state.setOffset(page); leftPage.verticalScrollbar.scrollBy(leftPage.verticalScrollbar.getScrubber().getPosition()); rightPage.verticalScrollbar.scrollBy(rightPage.verticalScrollbar.getScrubber().getPosition()); @@ -84,7 +84,7 @@ public class SpellbookTraitDexPageContent implements SpellbookChapterList.Conten @Override public void onRecipesChanged() { - init(screen, SpellbookChapterList.TRAIT_DEX_ID); + init(screen, SpellbookState.TRAIT_DEX_ID); } private final class DexPage extends ScrollContainer { diff --git a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java index 47a088f1..de69aacf 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java @@ -1,8 +1,6 @@ package com.minelittlepony.unicopia.container; import java.util.*; -import java.util.function.Predicate; - import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe; @@ -55,8 +53,6 @@ public class SpellbookScreenHandler extends ScreenHandler { private final ScreenHandlerContext context; - private Predicate canShowSlots; - private final SpellbookState state; @Nullable @@ -166,12 +162,13 @@ public class SpellbookScreenHandler extends ScreenHandler { return state; } - public void addSlotShowingCondition(Predicate canShowSlots) { - this.canShowSlots = canShowSlots; - } - public boolean canShowSlots(SlotType type) { - return canShowSlots == null || canShowSlots.test(type); + Identifier pageId = state.getCurrentPageId().orElse(null); + boolean isCraftingPage = SpellbookState.CRAFTING_ID.equals(pageId); + return switch (type) { + case INVENTORY -> isCraftingPage ? state.getState(pageId).getOffset() == 0 : SpellbookState.PROFILE_ID.equals(pageId); + case CRAFTING -> isCraftingPage; + }; } public int getOutputSlotId() { @@ -212,11 +209,16 @@ public class SpellbookScreenHandler extends ScreenHandler { return ItemStack.EMPTY; } + @Override + public boolean canInsertIntoSlot(ItemStack stack, Slot slot) { + return slot != null && slot.canInsert(stack) && slot.isEnabled(); + } + @Override public ItemStack quickMove(PlayerEntity player, int index) { Slot sourceSlot = slots.get(index); - if (sourceSlot == null || !sourceSlot.hasStack()) { + if (sourceSlot == null || !sourceSlot.hasStack() || (sourceSlot instanceof SpellSlot)) { return ItemStack.EMPTY; } @@ -228,35 +230,69 @@ public class SpellbookScreenHandler extends ScreenHandler { } if (index >= HOTBAR_START && !(sourceSlot instanceof OutputSlot || sourceSlot instanceof InputSlot)) { - if (!gemSlot.hasStack() && gemSlot.canInsert(stack)) { - if (insertItem(transferredStack, GEM_SLOT_INDEX, GEM_SLOT_INDEX + 1, false)) { + // hotbar or inventory -> crafting grid + if (canShowSlots(SlotType.CRAFTING)) { + if (!gemSlot.hasStack() && gemSlot.canInsert(stack)) { + if (insertItem(transferredStack, GEM_SLOT_INDEX, GEM_SLOT_INDEX + 1, false)) { + onContentChanged(input); + return ItemStack.EMPTY; + } + } + + if (insertItem(transferredStack, 0, GEM_SLOT_INDEX, false)) { + sourceSlot.onQuickTransfer(transferredStack, stack); onContentChanged(input); return ItemStack.EMPTY; } } - if (insertItem(transferredStack, 0, GEM_SLOT_INDEX, false)) { - sourceSlot.onQuickTransfer(transferredStack, stack); - onContentChanged(input); - return ItemStack.EMPTY; + if (index < HOTBAR_END) { + if (canShowSlots(SlotType.INVENTORY)) { + // hotbar -> inventory + // insert into inventory - armor + if (insertItem(transferredStack, HOTBAR_END + 27, HOTBAR_END + 27 + 4, false)) { + sourceSlot.onQuickTransfer(transferredStack, stack); + onContentChanged(input); + return ItemStack.EMPTY; + } + + // insert into inventory - inventory + if (insertItem(transferredStack, HOTBAR_END, HOTBAR_END + 27, false)) { + sourceSlot.onQuickTransfer(transferredStack, stack); + onContentChanged(input); + return ItemStack.EMPTY; + } + } + } else { + // inventory -> hotbar + if (insertItem(transferredStack, HOTBAR_START, HOTBAR_END, true)) { + sourceSlot.onQuickTransfer(transferredStack, stack); + onContentChanged(input); + return ItemStack.EMPTY; + } } } else { + // crafting grid -> hotbar if (insertItem(transferredStack, HOTBAR_START, HOTBAR_END, true)) { sourceSlot.onQuickTransfer(transferredStack, stack); onContentChanged(input); return ItemStack.EMPTY; } - if (insertItem(transferredStack, HOTBAR_END + 27, HOTBAR_END + 27 + 4, false)) { - sourceSlot.onQuickTransfer(transferredStack, stack); - onContentChanged(input); - return ItemStack.EMPTY; - } + if (canShowSlots(SlotType.INVENTORY)) { + // crafting grid -> armor + if (insertItem(transferredStack, HOTBAR_END + 27, HOTBAR_END + 27 + 4, false)) { + sourceSlot.onQuickTransfer(transferredStack, stack); + onContentChanged(input); + return ItemStack.EMPTY; + } - if (insertItem(transferredStack, HOTBAR_END, HOTBAR_END + 27, false)) { - sourceSlot.onQuickTransfer(transferredStack, stack); - onContentChanged(input); - return ItemStack.EMPTY; + // crafting grid -> inventory + if (insertItem(transferredStack, HOTBAR_END, HOTBAR_END + 27, false)) { + sourceSlot.onQuickTransfer(transferredStack, stack); + onContentChanged(input); + return ItemStack.EMPTY; + } } } diff --git a/src/main/java/com/minelittlepony/unicopia/container/SpellbookState.java b/src/main/java/com/minelittlepony/unicopia/container/SpellbookState.java index c616a8a1..9fedcffc 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/SpellbookState.java +++ b/src/main/java/com/minelittlepony/unicopia/container/SpellbookState.java @@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.container; import java.util.*; import java.util.function.Consumer; +import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.network.datasync.Synchronizable; import com.minelittlepony.unicopia.util.NbtSerialisable; @@ -13,6 +14,10 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; public class SpellbookState extends Synchronizable implements NbtSerialisable { + public static final Identifier CRAFTING_ID = Unicopia.id("crafting"); + public static final Identifier PROFILE_ID = Unicopia.id("profile"); + public static final Identifier TRAIT_DEX_ID = Unicopia.id("traits"); + private Optional currentPageId = Optional.empty(); private boolean dirty; From f2a4a5f1141d289a5430b3628a54cc8019aea7e1 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 16 May 2024 21:47:17 +0100 Subject: [PATCH 03/85] Fix door lighting. Fixes #346 --- .../resources/assets/unicopia/models/block/door_left.json | 8 ++++---- .../assets/unicopia/models/block/door_right.json | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/resources/assets/unicopia/models/block/door_left.json b/src/main/resources/assets/unicopia/models/block/door_left.json index 6c5b0b27..e0a63f70 100644 --- a/src/main/resources/assets/unicopia/models/block/door_left.json +++ b/src/main/resources/assets/unicopia/models/block/door_left.json @@ -9,10 +9,10 @@ "faces": { "up": { "uv": [ 13, 0, 16, 16 ], "texture": "#bottom", "cullface": "up" }, "down": { "uv": [ 13, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" }, - "north": { "uv": [ 3, 0, 0, 16 ], "texture": "#top", "cullface": "north" }, - "south": { "uv": [ 0, 0, 3, 16 ], "texture": "#top", "cullface": "south" }, - "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "west" }, - "east": { "uv": [ 16, 0, 0, 16 ], "texture": "#top", "cullface": "east" } + "north": { "uv": [ 3, 0, 0, 16 ], "texture": "#top" }, + "south": { "uv": [ 0, 0, 3, 16 ], "texture": "#top" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#top" }, + "east": { "uv": [ 16, 0, 0, 16 ], "texture": "#top" } } } ] diff --git a/src/main/resources/assets/unicopia/models/block/door_right.json b/src/main/resources/assets/unicopia/models/block/door_right.json index bf096276..632e5e99 100644 --- a/src/main/resources/assets/unicopia/models/block/door_right.json +++ b/src/main/resources/assets/unicopia/models/block/door_right.json @@ -9,10 +9,10 @@ "faces": { "up": { "uv": [ 13, 0, 16, 16 ], "texture": "#bottom", "cullface": "up" }, "down": { "uv": [ 13, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" }, - "north": { "uv": [ 3, 0, 0, 16 ], "texture": "#top", "cullface": "north" }, - "south": { "uv": [ 0, 0, 3, 16 ], "texture": "#top", "cullface": "south" }, - "west": { "uv": [ 16, 0, 0, 16 ], "texture": "#top", "cullface": "west" }, - "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "east" } + "north": { "uv": [ 3, 0, 0, 16 ], "texture": "#top" }, + "south": { "uv": [ 0, 0, 3, 16 ], "texture": "#top" }, + "west": { "uv": [ 16, 0, 0, 16 ], "texture": "#top" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#top" } } } ] From 59bdba6437444cf2d9b166f9a849c7371fe4d18b Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 16 May 2024 22:21:20 +0100 Subject: [PATCH 04/85] Fixed food poisoning probabilities being reversed - cooked had a higher chance of poisoning rather than lower --- .../providers/FoodGroupsGenerator.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java index 3959da20..0b6e6fa5 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java @@ -57,7 +57,7 @@ public class FoodGroupsGenerator { FoodComponents.COOKED_BEEF, FoodComponents.BEEF, exporter); exporter.accept(Unicopia.id("foraging/blinding"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_BLINDING).food(4, 0.2F).ailment(CompoundAffliction.of( - new StatusEffectAffliction(StatusEffects.BLINDNESS, Range.of(30), Range.of(0), 50), + new StatusEffectAffliction(StatusEffects.BLINDNESS, Range.of(30), Range.of(0), 10), new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 12) ))); exporter.accept(Unicopia.id("foraging/dangerous"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_DANGEROUS).food(3, 0.3F).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(250), Range.of(2), 4))); @@ -69,24 +69,24 @@ public class FoodGroupsGenerator { new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(200), Range.of(2), 0) ))); exporter.accept(Unicopia.id("foraging/prickly"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_PRICKLY).food(0, 1.5F).ailment(CompoundAffliction.of( - new StatusEffectAffliction(StatusEffects.INSTANT_DAMAGE, Range.of(1), Range.of(0), 30) + new StatusEffectAffliction(StatusEffects.INSTANT_DAMAGE, Range.of(1), Range.of(0), 12) ))); exporter.accept(Unicopia.id("foraging/glowing"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_GLOWING).food(1, 1.6F).ailment(CompoundAffliction.of( - new StatusEffectAffliction(StatusEffects.GLOWING, Range.of(30), Range.of(0), 30), - new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 0) + new StatusEffectAffliction(StatusEffects.GLOWING, Range.of(30), Range.of(0), 0), + new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 30) ))); exporter.accept(Unicopia.id("foraging/risky"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_RISKY).food(9, 1.1F).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80))); exporter.accept(Unicopia.id("foraging/severely_nauseating"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SEVERE_NAUSEATING).food(3, 0.9F).ailment(CompoundAffliction.of( new StatusEffectAffliction(StatusEffects.WEAKNESS, Range.of(200), Range.of(1), 0), - new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80) + new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 7) ))); exporter.accept(Unicopia.id("foraging/severely_prickly"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SEVERE_PRICKLY).food(2, 0.9F).ailment(CompoundAffliction.of( new StatusEffectAffliction(StatusEffects.INSTANT_DAMAGE, Range.of(1), Range.of(0), 0), - new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80) + new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 50) ))); exporter.accept(Unicopia.id("foraging/strengthening"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_STRENGHENING).food(4, 0.2F).ailment(CompoundAffliction.of( new StatusEffectAffliction(StatusEffects.STRENGTH, Range.of(1300), Range.of(0), 0), - new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 70) + new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 30) ))); } @@ -94,14 +94,15 @@ public class FoodGroupsGenerator { TagKey cookedTag, TagKey rawTag, TagKey rottenTag, FoodComponent cooked, FoodComponent raw, FoodComponent rotten, BiConsumer exporter) { - exporter.accept(Unicopia.id(name + "/cooked"), new FoodGroupEffects.Builder().tag(cookedTag).food(cooked).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 25))); + exporter.accept(Unicopia.id(name + "/cooked"), new FoodGroupEffects.Builder().tag(cookedTag).food(cooked).ailment( + new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(10, 100), Range.of(1, 2), 120))); exporter.accept(Unicopia.id(name + "/raw"), new FoodGroupEffects.Builder().tag(rawTag).food(raw).ailment(CompoundAffliction.of( - new StatusEffectAffliction(StatusEffects.POISON, Range.of(45), Range.of(2), 80), - new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 65) + new StatusEffectAffliction(StatusEffects.POISON, Range.of(25, 50), Range.of(1, 2), 30), + new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(90, 100), Range.of(1, 2), 25) ))); exporter.accept(Unicopia.id(name + "/rotten"), new FoodGroupEffects.Builder().tag(rottenTag).food(rotten).ailment(CompoundAffliction.of( - new StatusEffectAffliction(StatusEffects.POISON, Range.of(45), Range.of(2), 80), - new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 95) + new StatusEffectAffliction(StatusEffects.POISON, Range.of(45, 70), Range.of(1, 2), 8), + new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(20, 130), Range.of(1, 2), 5) ))); } From 151f3604e6bce4efb5f675b36bc2f4dcdce513e4 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 16 May 2024 22:21:46 +0100 Subject: [PATCH 05/85] Fixed client/server desync when applying status effects. Fixes #349 --- .../diet/affliction/ClearLoveSicknessAffliction.java | 3 +++ .../diet/affliction/StatusEffectAffliction.java | 3 +++ .../entity/effect/FoodPoisoningStatusEffect.java | 12 ++++++++---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/diet/affliction/ClearLoveSicknessAffliction.java b/src/main/java/com/minelittlepony/unicopia/diet/affliction/ClearLoveSicknessAffliction.java index ab8786a4..4a2105f1 100644 --- a/src/main/java/com/minelittlepony/unicopia/diet/affliction/ClearLoveSicknessAffliction.java +++ b/src/main/java/com/minelittlepony/unicopia/diet/affliction/ClearLoveSicknessAffliction.java @@ -19,6 +19,9 @@ public final class ClearLoveSicknessAffliction implements Affliction { @Override public void afflict(PlayerEntity player, ItemStack stack) { player.heal(stack.isFood() ? stack.getItem().getFoodComponent().getHunger() : 1); + if (player.getWorld().isClient) { + return; + } player.removeStatusEffect(StatusEffects.NAUSEA); player.removeStatusEffect(UEffects.FOOD_POISONING); player.removeStatusEffect(StatusEffects.WEAKNESS); diff --git a/src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java b/src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java index 9bc7adff..c6bdfebd 100644 --- a/src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java +++ b/src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java @@ -42,6 +42,9 @@ public record StatusEffectAffliction(StatusEffect effect, Range seconds, Range a @Override public void afflict(PlayerEntity player, ItemStack stack) { + if (player.getWorld().isClient) { + return; + } if (chance > 0 && player.getWorld().random.nextInt(chance) > 0) { return; } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/FoodPoisoningStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/FoodPoisoningStatusEffect.java index f216cc67..6d90a953 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/FoodPoisoningStatusEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/FoodPoisoningStatusEffect.java @@ -24,16 +24,18 @@ public class FoodPoisoningStatusEffect extends StatusEffect { @Override public void applyUpdateEffect(LivingEntity entity, int amplifier) { + if (entity.getWorld().isClient) { + return; + } boolean showParticles = entity.getStatusEffect(this).shouldShowParticles(); if (!entity.hasStatusEffect(StatusEffects.NAUSEA) && entity.getRandom().nextInt(12) == 0) { - entity.addStatusEffect(new StatusEffectInstance(StatusEffects.NAUSEA, 100, 1, true, showParticles, false)); } - if (entity instanceof PlayerEntity) { - ((PlayerEntity)entity).getHungerManager().addExhaustion(0.5F); + if (entity instanceof PlayerEntity player) { + player.getHungerManager().addExhaustion(0.5F); } if (EffectUtils.isPoisoned(entity) && entity.getRandom().nextInt(12) == 0 && !entity.hasStatusEffect(StatusEffects.POISON)) { @@ -63,7 +65,9 @@ public class FoodPoisoningStatusEffect extends StatusEffect { user.getWorld().playSound(null, user.getX(), user.getY(), user.getZ(), USounds.Vanilla.ENTITY_PLAYER_BURP, SoundCategory.NEUTRAL, 1, 1 + (user.getWorld().random.nextFloat() - user.getWorld().random.nextFloat()) * 0.4f); - user.addStatusEffect(new StatusEffectInstance(StatusEffects.NAUSEA, 100, 1, true, false, false)); + if (!user.getWorld().isClient) { + user.addStatusEffect(new StatusEffectInstance(StatusEffects.NAUSEA, 100, 1, true, false, false)); + } return TypedActionResult.fail(stack); } } From 2fdd5b2730dfc7aa42c102e46d693f528bd121aa Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 16 May 2024 22:30:27 +0100 Subject: [PATCH 06/85] Add fruit to the replaceable_by_trees tag to fix #352 --- .../unicopia/datagen/providers/tag/UBlockTagProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java index a8ce0bbb..0908bbc6 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java @@ -60,6 +60,7 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider { getOrCreateTagBuilder(BlockTags.FIRE).add(UBlocks.SPECTRAL_FIRE); getOrCreateTagBuilder(BlockTags.HOE_MINEABLE).add(UBlocks.HAY_BLOCK).addOptional(Unicopia.id("rice_block")).addOptional(Unicopia.id("straw_block")); getOrCreateTagBuilder(BlockTags.SHOVEL_MINEABLE).add(UBlocks.WORM_BLOCK); + getOrCreateTagBuilder(BlockTags.REPLACEABLE_BY_TREES).add(UBlocks.GREEN_APPLE, UBlocks.SOUR_APPLE, UBlocks.GOLDEN_APPLE, UBlocks.SWEET_APPLE, UBlocks.ZAP_APPLE, UBlocks.ZAP_BULB); addZapWoodset(); addPalmWoodset(); From fffbee84e3d428b1800f170321b22f68dc800203 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 16 May 2024 22:38:19 +0100 Subject: [PATCH 07/85] Add missing entity translations and set floating artefact to use the name of its item --- .../unicopia/entity/mob/FloatingArtefactEntity.java | 6 ++++++ src/main/resources/assets/unicopia/lang/en_us.json | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/FloatingArtefactEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/FloatingArtefactEntity.java index 26fe7e5d..f653d96d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/FloatingArtefactEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/FloatingArtefactEntity.java @@ -13,6 +13,7 @@ import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -48,6 +49,11 @@ public class FloatingArtefactEntity extends StationaryObjectEntity { positionSeed = (float)(Math.random() * Math.PI * 2); } + @Override + protected Text getDefaultName() { + return getStack().getName(); + } + @Override protected void initDataTracker() { super.initDataTracker(); diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 18adf7d8..86c642e4 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -65,7 +65,6 @@ "item.unicopia.butterfly_spawn_egg": "Butterfly Spawn Egg", "item.unicopia.butterfly": "Butterfly", "item.unicopia.loot_bug_spawn_egg": "Loot Bug Spawn Egg", - "item.unicopia.loot_bug": "Loot bug", "item.unicopia.green_apple": "Granny Smith Apple", "item.unicopia.sweet_apple": "Sweet Apple Acres Apple", @@ -376,9 +375,11 @@ "block.unicopia.oats_crown": "Oats", "entity.unicopia.butterfly": "Butterfly", + "entity.unicopia.loot_bug": "Loot bug", "entity.unicopia.twittermite": "Twittermite", "entity.unicopia.specter": "Specter", "entity.unicopia.mimic": "Mimic", + "entity.unicopia.magic_beam": "Magic Beam", "entity.unicopia.cast_spell": "Cast Spell", "entity.unicopia.cast_spell.by": "a spell cast by %s", "entity.unicopia.spellbook": "Spellbook", @@ -389,6 +390,7 @@ "entity.unicopia.crystal_shards": "Crystal Shards", "entity.unicopia.ignominious_vine": "Ignominious Vine", "entity.unicopia.ignominious_bulb": "Ignominious Bulb", + "entity.unicopia.thrown_item": "Thrown Item", "player.reachDistance": "Reach Distance", "player.miningSpeed": "Mining Speed", From 6a8c0d82eea963b9cd6bbaee524ee13c9f8ab5e9 Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 17 May 2024 18:23:38 +0100 Subject: [PATCH 08/85] Ground pound now prevents fall damage. Fixes #351 --- .../ability/EarthPonyStompAbility.java | 7 +++- .../unicopia/entity/Living.java | 33 ++++++++++++----- .../unicopia/entity/player/Pony.java | 37 ++++++++----------- .../unicopia/mixin/MixinLivingEntity.java | 6 +++ .../unicopia/mixin/MixinPlayerEntity.java | 16 +------- 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java index 78314ba7..4f9ffd1c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java @@ -20,6 +20,7 @@ import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.VecHelper; +import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.enchantment.EnchantmentHelper; @@ -106,7 +107,8 @@ public class EarthPonyStompAbility implements Ability { public boolean apply(Pony iplayer, Hit data) { PlayerEntity player = iplayer.asEntity(); - Runnable r = () -> { + Float2FloatFunction r = fallDistance -> { + player.fallDistance = 0; BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum()); float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player); @@ -163,13 +165,14 @@ public class EarthPonyStompAbility implements Ability { iplayer.subtractEnergyCost(rad); iplayer.asEntity().addExhaustion(3); + return 0F; }; if (iplayer.asEntity().isOnGround()) { iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10); iplayer.asEntity().jump(); iplayer.updateVelocity(); - AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.run(), 5); + AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.get(0F), 5); } else { thrustDownwards(iplayer); iplayer.waitForFall(r); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 1696abef..d006a811 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -1,6 +1,7 @@ package com.minelittlepony.unicopia.entity; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -38,6 +39,7 @@ import com.minelittlepony.unicopia.projectile.ProjectileImpactListener; import com.minelittlepony.unicopia.server.world.DragonBreathStore; import com.minelittlepony.unicopia.util.*; +import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.BlockState; @@ -83,7 +85,8 @@ public abstract class Living implements Equine, Caste private final Interactable jumpingHeuristic; @Nullable - private Runnable landEvent; + private final AtomicReference landEvent = new AtomicReference<>(); + private float prevFallDistance; private boolean invisible = false; @@ -131,11 +134,11 @@ public abstract class Living implements Equine, Caste this.invisible = invisible; } - public void waitForFall(Runnable action) { + public void waitForFall(Float2FloatFunction action) { if (entity.isOnGround()) { - action.run(); + action.get(0F); } else { - landEvent = action; + landEvent.set(action); } } @@ -206,6 +209,7 @@ public abstract class Living implements Equine, Caste @Override public boolean beforeUpdate() { + prevFallDistance = entity.fallDistance; if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) { entity.setVelocity(entity.getVelocity().multiply(0, 1, 0)); updateVelocity(); @@ -236,9 +240,8 @@ public abstract class Living implements Equine, Caste invinsibilityTicks--; } - if (landEvent != null && entity.isOnGround() && landedChanged()) { - landEvent.run(); - landEvent = null; + if (entity.isOnGround() && landedChanged()) { + onLanded(prevFallDistance); } if (entity.hasStatusEffect(UEffects.PARALYSIS) && entity.getVelocity().horizontalLengthSquared() > 0) { @@ -261,6 +264,11 @@ public abstract class Living implements Equine, Caste transportation.tick(); } + private float onLanded(float fallDistance) { + var event = landEvent.getAndSet(null); + return event == null ? fallDistance : event.get(fallDistance); + } + public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction modifierSupplier, boolean permanent) { @Nullable EntityAttributeInstance instance = asEntity().getAttributeInstance(attribute); @@ -465,10 +473,17 @@ public abstract class Living implements Equine, Caste .isPresent(); } - protected void handleFall(float distance, float damageMultiplier, DamageSource cause) { + public float onImpact(float distance, float damageMultiplier, DamageSource cause) { + float fallDistance = onLanded(getEffectiveFallDistance(distance)); + getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).ifPresent(spell -> { - spell.getDisguise().onImpact(this, distance, damageMultiplier, cause); + spell.getDisguise().onImpact(this, fallDistance, damageMultiplier, cause); }); + return fallDistance; + } + + protected float getEffectiveFallDistance(float distance) { + return distance; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index aa174dd4..07a13cec 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -723,9 +723,22 @@ public class Pony extends Living implements Copyable, Update }); } - public Optional onImpact(float distance, float damageMultiplier, DamageSource cause) { - float originalDistance = distance; + @Override + public float onImpact(float distance, float damageMultiplier, DamageSource cause) { + distance = super.onImpact(distance, damageMultiplier, cause); + if (getCompositeRace().canUseEarth() && entity.isSneaking()) { + double radius = distance / 10; + if (radius > 0) { + EarthPonyStompAbility.spawnEffectAround(entity, entity.getSteppingPos(), radius, radius); + } + } + + return distance; + } + + @Override + protected float getEffectiveFallDistance(float distance) { boolean extraProtection = getSpellSlot().get(SpellType.SHIELD, false).isPresent(); if (!entity.isCreative() && !entity.isSpectator()) { @@ -740,14 +753,9 @@ public class Pony extends Living implements Copyable, Update if (getCompositeRace().canFly() || (getCompositeRace().canUseEarth() && entity.isSneaking())) { distance -= 5; } - distance = Math.max(0, distance); } - handleFall(distance, damageMultiplier, cause); - if (distance != originalDistance) { - return Optional.of(distance); - } - return Optional.empty(); + return Math.max(0, distance); } public void onEat(ItemStack stack) { @@ -762,19 +770,6 @@ public class Pony extends Living implements Copyable, Update } } - @SuppressWarnings("deprecation") - @Override - protected void handleFall(float distance, float damageMultiplier, DamageSource cause) { - super.handleFall(distance, damageMultiplier, cause); - - if (getCompositeRace().canUseEarth() && entity.isSneaking()) { - double radius = distance / 10; - if (radius > 0) { - EarthPonyStompAbility.spawnEffectAround(entity, entity.getLandingPos(), radius, radius); - } - } - } - public void onKill(Entity killedEntity, DamageSource damage) { if (killedEntity != null && killedEntity.getType() == EntityType.PHANTOM && getPhysics().isFlying()) { UCriteria.KILL_PHANTOM_WHILE_FLYING.trigger(entity); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java index 7d41f099..da1cff6a 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java @@ -6,6 +6,7 @@ import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -151,6 +152,11 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ get().onDamage(source, amount).ifPresent(info::setReturnValue); } + @ModifyVariable(method = "handleFallDamage(FFLnet/minecraft/entity/damage/DamageSource;)Z", at = @At("HEAD"), ordinal = 0, argsOnly = true) + private float onHandleFallDamage(float distance, float distanceAgain, float damageMultiplier, DamageSource cause) { + return get().onImpact(distance, damageMultiplier, cause); + } + @Inject(method = "hurtByWater()Z", at = @At("HEAD"), cancellable = true) private void onCanBeHurtByWater(CallbackInfoReturnable info) { TriState hurtByWater = get().canBeHurtByWater(); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java index b67432fc..d04692bb 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java @@ -26,7 +26,6 @@ import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.stat.Stats; import net.minecraft.util.Unit; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -48,24 +47,11 @@ abstract class MixinPlayerEntity extends LivingEntity implements Equine.Containe Pony.registerAttributes(info.getReturnValue()); } - @ModifyVariable(method = "applyDamage(Lnet/minecraft/entity/damage/DamageSource;F)V", at = @At("HEAD"), ordinal = 0) + @ModifyVariable(method = "applyDamage(Lnet/minecraft/entity/damage/DamageSource;F)V", at = @At("HEAD"), ordinal = 0, argsOnly = true) protected float modifyDamageAmount(float amount, DamageSource source) { return get().modifyDamage(source, amount).orElse(amount); } - @Inject(method = "handleFallDamage(FFLnet/minecraft/entity/damage/DamageSource;)Z", at = @At("HEAD"), cancellable = true) - private void onHandleFallDamage(float distance, float damageMultiplier, DamageSource cause, CallbackInfoReturnable info) { - get().onImpact(fallDistance, damageMultiplier, cause).ifPresent(newDistance -> { - PlayerEntity self = (PlayerEntity)(Object)this; - - if (distance >= 2) { - self.increaseStat(Stats.FALL_ONE_CM, Math.round(distance * 100)); - } - - info.setReturnValue(super.handleFallDamage(newDistance, damageMultiplier, cause)); - }); - } - @Inject(method = "eatFood(Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;", at = @At("HEAD")) private void onEatFood(World world, ItemStack stack, CallbackInfoReturnable info) { get().onEat(stack); From e6ec2083efbc88a42192f26f55b726ad018c9314 Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 17 May 2024 18:56:20 +0100 Subject: [PATCH 09/85] Add a fortification status effect so earth ponies can see when they're fortified --- .../magic/spell/effect/AttractionUtils.java | 9 +++-- .../unicopia/entity/effect/EffectUtils.java | 23 ++++++++++++ .../entity/effect/SimpleStatusEffect.java | 33 ++++++++++++++++++ .../unicopia/entity/effect/UEffects.java | 3 +- .../entity/player/PlayerAttributes.java | 3 ++ .../unicopia/entity/player/Pony.java | 14 ++++---- .../resources/assets/unicopia/lang/en_us.json | 1 + .../textures/mob_effect/fortification.png | Bin 0 -> 8616 bytes 8 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/effect/SimpleStatusEffect.java create mode 100644 src/main/resources/assets/unicopia/textures/mob_effect/fortification.png diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractionUtils.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractionUtils.java index 76b2d29e..2f8833e9 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractionUtils.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractionUtils.java @@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.entity.Living; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; @@ -61,12 +62,10 @@ public interface AttractionUtils { return Pony.of(entity).map(pony -> { double force = 0.75; - if (pony.getCompositeRace().canUseEarth()) { + if (EffectUtils.hasExtraDefenses(pony.asEntity())) { + force /= 12; + } else if (pony.getCompositeRace().canUseEarth()) { force /= 2; - - if (pony.asEntity().isSneaking()) { - force /= 6; - } } else if (pony.getCompositeRace().canFly()) { force *= 2; } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java index 14372955..dff45f27 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.entity.effect; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectInstance; public interface EffectUtils { static boolean isPoisoned(LivingEntity entity) { @@ -15,4 +16,26 @@ public interface EffectUtils { static boolean isChangingRace(LivingEntity entity) { return entity.getStatusEffects().stream().anyMatch(effect -> effect.getEffectType() instanceof RaceChangeStatusEffect); } + + static boolean hasExtraDefenses(LivingEntity entity) { + return entity.hasStatusEffect(UEffects.FORTIFICATION); + } + + static boolean applyStatusEffect(LivingEntity entity, StatusEffect effect, boolean apply) { + if (entity.getWorld().isClient) { + return false; + } + boolean has = entity.hasStatusEffect(effect); + if (has != apply) { + if (has) { + if (entity.getStatusEffect(effect).getDuration() == StatusEffectInstance.INFINITE) { + entity.removeStatusEffect(effect); + } + } else { + entity.addStatusEffect(new StatusEffectInstance(effect, StatusEffectInstance.INFINITE, 0, false, false, true)); + } + return true; + } + return false; + } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/SimpleStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/SimpleStatusEffect.java new file mode 100644 index 00000000..7adc3654 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/SimpleStatusEffect.java @@ -0,0 +1,33 @@ +package com.minelittlepony.unicopia.entity.effect; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectCategory; + +public class SimpleStatusEffect extends StatusEffect { + + private final boolean instant; + + public SimpleStatusEffect(StatusEffectCategory category, int color, boolean instant) { + super(category, color); + this.instant = instant; + } + + @Override + public void applyUpdateEffect(LivingEntity entity, int amplifier) { + + } + + @Override + public void applyInstantEffect(@Nullable Entity source, @Nullable Entity attacker, LivingEntity target, int amplifier, double proximity) { + + } + + @Override + public final boolean isInstant() { + return instant; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java index 00b51dd6..83feb060 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java @@ -15,7 +15,8 @@ public interface UEffects { * When affecting an entity, will give them a random chance to reproduce or duplicate themselves when they die. */ StatusEffect CORRUPT_INFLUENCE = register("corrupt_influence", new CorruptInfluenceStatusEffect(0x00FF00)); - StatusEffect PARALYSIS = register("paralysis", new StatusEffect(StatusEffectCategory.HARMFUL, 0) {}); + StatusEffect PARALYSIS = register("paralysis", new SimpleStatusEffect(StatusEffectCategory.HARMFUL, 0, false)); + StatusEffect FORTIFICATION = register("fortification", new SimpleStatusEffect(StatusEffectCategory.BENEFICIAL, 0x000077, false)); /** * Side-effect of wearing the alicorn amulet. * Causes the player to lose grip on whatever item they're holding. diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerAttributes.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerAttributes.java index 8bbccdef..b1efa4a6 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerAttributes.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerAttributes.java @@ -6,6 +6,8 @@ import java.util.function.Predicate; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; +import com.minelittlepony.unicopia.entity.effect.UEffects; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.util.Tickable; @@ -87,6 +89,7 @@ public class PlayerAttributes implements Tickable { @Override public void tick() { ATTRIBUTES.forEach(attribute -> attribute.update(pony)); + EffectUtils.applyStatusEffect(pony.asEntity(), UEffects.FORTIFICATION, pony.getCompositeRace().canUseEarth() && pony.asEntity().isSneaking()); } record ToggleableAttribute(EntityAttributeModifier modifier, List attributes, Predicate test) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 07a13cec..b8f30cd5 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -21,6 +21,7 @@ import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.effect.MetamorphosisStatusEffect; import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect; import com.minelittlepony.unicopia.entity.effect.UEffects; @@ -700,18 +701,17 @@ public class Pony extends Living implements Copyable, Update } } - if (!cause.isIn(DamageTypeTags.BYPASSES_SHIELD) + if (EffectUtils.hasExtraDefenses(entity) + && !cause.isIn(DamageTypeTags.BYPASSES_SHIELD) && !cause.isOf(DamageTypes.MAGIC) && !cause.isIn(DamageTypeTags.IS_FIRE) && !cause.isIn(DamageTypeTags.BYPASSES_INVULNERABILITY) && !cause.isOf(DamageTypes.THORNS) && !cause.isOf(DamageTypes.FREEZE)) { - if (getCompositeRace().canUseEarth() && entity.isSneaking()) { - amount /= (cause.isOf(DamageTypes.MOB_PROJECTILE) ? 3 : 2) * (entity.getHealth() < 5 ? 3 : 1); + amount /= (cause.isOf(DamageTypes.MOB_PROJECTILE) ? 3 : 2) * (entity.getHealth() < 5 ? 3 : 1); - return Optional.of(amount); - } + return Optional.of(amount); } return Optional.empty(); } @@ -727,7 +727,7 @@ public class Pony extends Living implements Copyable, Update public float onImpact(float distance, float damageMultiplier, DamageSource cause) { distance = super.onImpact(distance, damageMultiplier, cause); - if (getCompositeRace().canUseEarth() && entity.isSneaking()) { + if (EffectUtils.hasExtraDefenses(entity)) { double radius = distance / 10; if (radius > 0) { EarthPonyStompAbility.spawnEffectAround(entity, entity.getSteppingPos(), radius, radius); @@ -750,7 +750,7 @@ public class Pony extends Living implements Copyable, Update } } - if (getCompositeRace().canFly() || (getCompositeRace().canUseEarth() && entity.isSneaking())) { + if (getCompositeRace().canFly() || EffectUtils.hasExtraDefenses(entity)) { distance -= 5; } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 86c642e4..dcacc971 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -406,6 +406,7 @@ "effect.unicopia.corrupt_influence": "Corrupt Influence", "effect.unicopia.paralysis": "Paralysis", "effect.unicopia.butter_fingers": "Butterfingers", + "effect.unicopia.fortification": "Fortification", "effect.unicopia.change_race_earth": "Earth Pony Metamorphosis", "effect.unicopia.change_race_unicorn": "Unicorn Metamorphosis", diff --git a/src/main/resources/assets/unicopia/textures/mob_effect/fortification.png b/src/main/resources/assets/unicopia/textures/mob_effect/fortification.png new file mode 100644 index 0000000000000000000000000000000000000000..106e3a2f6591f2c46e14c77dda2c065da4cc6daa GIT binary patch literal 8616 zcmeHNXIN9&)=oliQUpXq3{j+LAdMCcqJ*j_O{6J=6bO(6lR!Wbks`%1A}R{X019J8 z0Sh9CN>M~W5dpE{pcHlJO+@ZK0UT!L-tT_i=ey7I{g~skviDhgt#_~Y-TNHK#w5p$ zHgeMH(l8iI&d!$X3|a-qB*nq!lEEno3?}JHcei8M+3CY1flmeogNwr8GjZ@aeFR(t zCIbA2fz5*>U`n7p4onI7p?JvD;bOw}Jm@c)=@){&?o14nj|I7Mpe+H01AS%CJ^;o{ zn4b3~=t}}HN#Q?BE}g=s(~trtKLBZC=imsdN5Ek7LCkCmIgvO6EXDwD3J@_k0uf_G z#F`+nrbL1n5swEI?L903TL^M~12*^iE4mcy8*I7`h|jDR5UE)$p#H2DJ3wD#h8v`) z_?*7V9L{jWG-foEJJWB162LXhbE#cb|z#tbhiCc4TfdE=;lPPaI#W{0fR%yQUM_Tw3V_We8$A< zl$|V==*+}GadQnmd;koqH91+q96*BDd4RVFbVP@MXVWaiVi2>406dYWW?ZxAv#mrk zG)#r6$cEBg!JP*n1c%B!HbY8w2S7K53j8z&0m{sr0nFz z*ao5zVDL~481xfHJclqldO!j+>7UKK0Lq95YN|jg+yLc>fYj7=fx0?P z1AehD;O<}6B-|^)x^y8)+-6BYTOk<_FlfgBF032?Nz^ofwNU;ywu=hQ3Dv9rWJY5N z2ssKM|LZ-d3+DK<3HPP+?0i1|qaJ_OXYRdFDUrHB3-B{e8pE`- zbhNXyM22uV3}!GL1`9uV>X^XQwM8|dp-iwNyAGqQXW3gOhb%KW*GQ%uU+AkVG7nEE z(8@t5T9HLn*2bX3_wPj&ppxUGeeY@>LS|L^Dmytv;0xXO@86fDrM+3=zbokHvQd(M z@2=(&*rC$No27hr>1aY`^pbb)?SI;zoJXC2%l5%U9>IJIad^Z!Qbn|_xh8vPL(2Ry zlw`DtpmGJwiv4d6; z$_1sz=P!8PSJZ%7weQ5KYU)1s$Pcn%>RyjXsMqP*9f@lF3${C{rlq3ad7+v&sN`+8 z`s${UQB7eWqESho5%X5qRpz0V_gAcYNiJ1}Y3TK@I5?Foc2Z-{m@~V3;mt_4-{I)| z+Q!ov&)aZauTOq*J!s*pTuIBtj0cx^?eG*&O_RCv?$ny~*4|zvXCE{(t~WPZf2d~o zsPvSxzd0oByk&biX3eN<&hV~+$)i3yNU;4LPOPxVf~sDzEGiy0Fk0S9kVhc(db}p? zY#Gf?>eRMFKDdI%*3{P5y=XEbaccWppPwr*ajAFOdEq&UAy1BMk4VZ18*KH4o1C)g9Qfuke~Qxj z^HtLpl#{wSJn$m+ka`xPqs2TrM**(Hv$!fU`NU**q^UxAspPYys+&_QyWSMtqrcNm z%@{MQM=#r7uQX7kI$GJFlm&;|BJ>?$`W7Nxh^4;sf}=?x;+l6Bh{j+P#N6Pjwg_gl zeBoO2R>@=wsaAMcY@nlzy2bnexQ>N{shmM{?OS3ooEsXG9*|4q@yX+Ek0Kr+8M63&Rema0#N8!=k;jr$eD_`1S#bYK z=M~G=?Vr3f6n{y^-;a2gvwgKUJYPwmEKoIx%eYhbYi^%s_^L=`=7EN)wDv`PTgTvE zO`|fA4v)1=74Ava#2tv!UnkS9)UMU8l49$s)20-g|qUwZqIv4hJj8+C4` z_}Q*&3~Qt`Ml_NdSKv-ubO>8+lPcEnxnuc&)c|$CODZ|8AnqqoFTXPK0rIWNLzOai zrDu+v+1H_8v%1EiK#z%ZSSZR_~cA>B&X*h4%3eJ&x*aPCkEHf6KLX!zX+2B`aUWXWC!R8GY>E zbfl^DSzKUf;AG%n53#5AnM{+{vn5Ogf||ONx{CTMb$t5yba?uBdR_YHwLVYTOUo{i zJj*Y2@wa?z{`k7Fq6<6ZJT&t0)#HTWOGBwc zK|>O#4HHGlVJfi-pPp&y zNIiFyd7c^DErMT&_bEaY85F?N*CVD#a}$_J{Msvprr^fpg*ckW7g_t)2Q+{N5k z1wGfl1hA-eH`oQ4g-@;~6+QRIKgzb#zL8xn{KiZ&(GlfSOLuc%|BljlkDhK zX$$i6@*`V}Tg*&W-MGf?e5EKb9Q7NGl3)1Kd(CH>Karl1=94l={-qa7o5N3yTJM~Q z=pE7=aT=kF6UHBnwTC4)P|B0|9tS;)JUB%aMVmg@cJ^_cnvcT>N0d8Sv8`C|*`MDq3Ru0@H&uOl7o?r1eN=mi zy+>}#ZR|u|Pe%M_sTUKq7i;Hzy7TGn=i;KL%+3^U_dw}D!B+UKwiR6}RVtSS_kX+X z$@K8Jm2kzT*#FGK^7FjQA6_rsxyDsz^PBwbmzb}9xypHQ`{v}QNlS^7@>iSmTaGo| zUh{wyexv?Ee%ZELw+9qHI5ubhBG)cg_6B#G73dnglKD0KxFEd4_CZSK@{GK^)AlyC z>Fo^4U{k?ys>yBMRDMy_+1&i2&7NEhjRl&!M|Qm&6>JM=@sa`d6t7)2mJrY?x-Yt`~ zpt^*5Yl-*%((ns9#lK7)ev`W*jb!NaDYTm;sA_-MeIabirma-(kHzd=Wn~TLFMrm# z@N?UjOA{|7g2joP*4JI?-o)^*2h6T}4x<@qobi_>Q9GZ1zPqZn_vPY)3pH=n-d+`9 zIQ+VH!eg{^NpN^#l>1lP9;f%z-2208K2E+Q`jNPdrd?Ni?YdGWs22-5%W2;RD5ZUR z;in#yh(88qO_ha9h1-cV>TNR7uyCZlBSz$GiF~IQ8Yjb>#Z}9My(T<_LJgwxk$!Z4CYyxn zy;Y7vGHE2#79$6YLx?3kfN8sfOLy6^(UrO*h-yYdtudEg9Zm!QEIOZp3}*$idBkuM zN{CAYeaLNyLJC9pK_rwrI9amfaOp^b0l@%+whCv4;ZWw%$kkjLgXm1Qo`C>&Bvb&O zA3`)V6bJ+c0=xl->u-oPGcz;9;0$p%G>Aa+BG`ONIGW8{3PDU`km)=sml?uma@a@+ zlj6q-<&#h-Fpiw9j}_wJ@ExAbn^6JiVHi#cF~k~R3|TD0xfwjZRTu!7Dd?YO@LVH8 z=!VX89w(GbrCWv3+5Dw*A!yX^`5~d)U?CkE)sP-cXMs>2m=*hnDWNmC?-`H;{!CVg zFbjzNhe$q?@w-@ms0|ts(wSQbNdJ!ehv-@E!e9{P;6NmEsG(4Kc4QI?nx9DHP?vik)N3n z9nHW16aog+(6SH#86YeL+NS_O=m%Vg!sAm8*OkKwCZV7Lgy*o|haJGC85Zm& z8rBGH#-LKrG^(i)1M5eiG8kq;6~3eMI1Ijk!lkeE2RZ_+!1fesh13-;l-?hs1p#zu z6@Xx9j1d}Z@@K&eX9ycY?~GZ-s}296$!cN1oRXlS}&duTyk3_$^2PzAQ2A ztH2*^Vd8%4ZOAYR^rdU7;`Bx_~u8y%Q}VjlCJT183zqru4H8@`vjPFjv< z(mft~;$ELuW?KiI47mA$d3`glw9GCRlHQ!f)F2PY3Y_n29b`(78FSb<&it7)Ma zeDh{4RHsE|=R?nZiH}D~{kP&H^74boqCx10%-xHu7H_4!xNh3{*mJ(Um`4_ hZqsD-^MzA(kuZ{vz)3^n`8L2EW@ojLoWIUD<{w`V)y)6^ literal 0 HcmV?d00001 From 04298eefcf953e6a56527baa44c9f2918755194f Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 17 May 2024 19:28:08 +0100 Subject: [PATCH 10/85] Cancel stomps when moving upwards --- .../ability/EarthPonyStompAbility.java | 128 ++++++++++-------- .../unicopia/entity/LandingEventHandler.java | 68 ++++++++++ .../unicopia/entity/Living.java | 28 +--- 3 files changed, 145 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/LandingEventHandler.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java index 4f9ffd1c..6e862f6f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java @@ -6,9 +6,11 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.AwaitTickQueue; import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; +import com.minelittlepony.unicopia.entity.LandingEventHandler; import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.player.Pony; @@ -20,7 +22,6 @@ import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.VecHelper; -import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.enchantment.EnchantmentHelper; @@ -105,74 +106,89 @@ public class EarthPonyStompAbility implements Ability { @Override public boolean apply(Pony iplayer, Hit data) { - PlayerEntity player = iplayer.asEntity(); + final PlayerEntity player = iplayer.asEntity(); + final double initialY = player.getY() + 5; - Float2FloatFunction r = fallDistance -> { - player.fallDistance = 0; - BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum()); - - float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player); - - iplayer.asWorld().getOtherEntities(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> { - double dist = Math.sqrt(center.getSquaredDistance(i.getBlockPos())); - - if (dist <= rad + 3) { - double inertia = 2 / dist; - - if (i instanceof LivingEntity) { - inertia *= 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, (LivingEntity)i); - } - inertia /= heavyness; - - double liftAmount = Math.sin(Math.PI * dist / rad) * 12 * iplayer.getPhysics().getGravitySignum(); - - i.addVelocity( - -(player.getX() - i.getX()) / inertia, - -(player.getY() - i.getY() - liftAmount) / inertia + (dist < 1 ? dist : 0), - -(player.getZ() - i.getZ()) / inertia); - - double amount = (1.5F * player.getAttributeInstance(EntityAttributes.GENERIC_ATTACK_DAMAGE).getValue() + heavyness * 0.4) / (float)(dist * 1.3F); - - if (i instanceof PlayerEntity) { - Race.Composite race = Pony.of((PlayerEntity)i).getCompositeRace(); - if (race.canUseEarth()) { - amount /= 3; - } - - if (race.canFly()) { - amount *= 4; - } - } - - if (i instanceof LivingEntity) { - amount /= 1 + (EnchantmentHelper.getEquipmentLevel(UEnchantments.PADDED, (LivingEntity)i) / 6F); - } - - i.damage(iplayer.damageOf(UDamageTypes.SMASH, iplayer), (float)amount); - Living.updateVelocity(i); + var r = new LandingEventHandler.Callback() { + @Override + public float dispatch(float fallDistance) { + // fail if landing above the starting position + if (player.getY() > initialY) { + return fallDistance; } - }); - double radius = rad + heavyness * 0.3; + player.fallDistance = 0; + BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum()); - spawnEffectAround(player, center, radius, rad); + float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player); - ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0); - BlockState steppingState = player.getSteppingBlockState(); - if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) { - ParticleUtils.spawnParticle(player.getWorld(), new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), player.getBlockPos().down().toCenterPos(), Vec3d.ZERO); + iplayer.asWorld().getOtherEntities(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> { + double dist = Math.sqrt(center.getSquaredDistance(i.getBlockPos())); + + if (dist <= rad + 3) { + double inertia = 2 / dist; + + if (i instanceof LivingEntity) { + inertia *= 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, (LivingEntity)i); + } + inertia /= heavyness; + + double liftAmount = Math.sin(Math.PI * dist / rad) * 12 * iplayer.getPhysics().getGravitySignum(); + + i.addVelocity( + -(player.getX() - i.getX()) / inertia, + -(player.getY() - i.getY() - liftAmount) / inertia + (dist < 1 ? dist : 0), + -(player.getZ() - i.getZ()) / inertia); + + double amount = (1.5F * player.getAttributeInstance(EntityAttributes.GENERIC_ATTACK_DAMAGE).getValue() + heavyness * 0.4) / (float)(dist * 1.3F); + + if (i instanceof PlayerEntity) { + Race.Composite race = Pony.of((PlayerEntity)i).getCompositeRace(); + if (race.canUseEarth()) { + amount /= 3; + } + + if (race.canFly()) { + amount *= 4; + } + } + + if (i instanceof LivingEntity) { + amount /= 1 + (EnchantmentHelper.getEquipmentLevel(UEnchantments.PADDED, (LivingEntity)i) / 6F); + } + + i.damage(iplayer.damageOf(UDamageTypes.SMASH, iplayer), (float)amount); + Living.updateVelocity(i); + } + }); + + double radius = rad + heavyness * 0.3; + + spawnEffectAround(player, center, radius, rad); + + ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0); + BlockState steppingState = player.getSteppingBlockState(); + if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) { + ParticleUtils.spawnParticle(player.getWorld(), new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), player.getBlockPos().down().toCenterPos(), Vec3d.ZERO); + } + + iplayer.subtractEnergyCost(rad); + iplayer.asEntity().addExhaustion(3); + return 0F; } - iplayer.subtractEnergyCost(rad); - iplayer.asEntity().addExhaustion(3); - return 0F; + @Override + public void onCancelled() { + System.out.println("Cancel Stomp"); + iplayer.playSound(USounds.GUI_ABILITY_FAIL, 1F); + } }; if (iplayer.asEntity().isOnGround()) { iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10); iplayer.asEntity().jump(); iplayer.updateVelocity(); - AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.get(0F), 5); + AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.dispatch(0F), 5); } else { thrustDownwards(iplayer); iplayer.waitForFall(r); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/LandingEventHandler.java b/src/main/java/com/minelittlepony/unicopia/entity/LandingEventHandler.java new file mode 100644 index 00000000..41516581 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/LandingEventHandler.java @@ -0,0 +1,68 @@ +package com.minelittlepony.unicopia.entity; + +import java.util.concurrent.atomic.AtomicReference; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.util.Tickable; + +public class LandingEventHandler implements Tickable { + + private final Living living; + + @Nullable + private final AtomicReference callback = new AtomicReference<>(); + private double prevY; + private float prevFallDistance; + + public LandingEventHandler(Living living) { + this.living = living; + } + + public void setCallback(LandingEventHandler.Callback callback) { + if (living.asEntity().isOnGround()) { + callback.dispatch(0F); + } else { + updateCallback(callback); + } + } + + public void beforeTick() { + + } + + @Override + public void tick() { + if (living.asEntity().getY() > prevY) { + discard(); + } + prevY = living.asEntity().getY(); + + if (living.asEntity().isOnGround() && living.landedChanged()) { + fire(prevFallDistance); + } + prevFallDistance = living.asEntity().fallDistance; + } + + float fire(float fallDistance) { + var event = callback.getAndSet(null); + return event == null ? fallDistance : event.dispatch(fallDistance); + } + + void discard() { + updateCallback(null); + } + + void updateCallback(@Nullable Callback callback) { + var event = this.callback.getAndSet(callback); + if (event != null) { + event.onCancelled(); + } + } + + public interface Callback { + float dispatch(float fallDistance); + + void onCancelled(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index d006a811..95631823 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -1,7 +1,6 @@ package com.minelittlepony.unicopia.entity; import java.util.*; -import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -39,7 +38,6 @@ import com.minelittlepony.unicopia.projectile.ProjectileImpactListener; import com.minelittlepony.unicopia.server.world.DragonBreathStore; import com.minelittlepony.unicopia.util.*; -import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.BlockState; @@ -84,10 +82,6 @@ public abstract class Living implements Equine, Caste private final Interactable landedHeuristic; private final Interactable jumpingHeuristic; - @Nullable - private final AtomicReference landEvent = new AtomicReference<>(); - private float prevFallDistance; - private boolean invisible = false; @Nullable @@ -101,6 +95,7 @@ public abstract class Living implements Equine, Caste private final List tickers = new ArrayList<>(); + private final LandingEventHandler landEvent = addTicker(new LandingEventHandler(this)); private final Enchantments enchants = addTicker(new Enchantments(this)); private final ItemTracker armour = addTicker(new ItemTracker(this)); //private final Transportation transportation = new Transportation<>(this); @@ -134,12 +129,8 @@ public abstract class Living implements Equine, Caste this.invisible = invisible; } - public void waitForFall(Float2FloatFunction action) { - if (entity.isOnGround()) { - action.get(0F); - } else { - landEvent.set(action); - } + public void waitForFall(LandingEventHandler.Callback callback) { + landEvent.setCallback(callback); } public boolean sneakingChanged() { @@ -209,7 +200,7 @@ public abstract class Living implements Equine, Caste @Override public boolean beforeUpdate() { - prevFallDistance = entity.fallDistance; + landEvent.beforeTick(); if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) { entity.setVelocity(entity.getVelocity().multiply(0, 1, 0)); updateVelocity(); @@ -240,10 +231,6 @@ public abstract class Living implements Equine, Caste invinsibilityTicks--; } - if (entity.isOnGround() && landedChanged()) { - onLanded(prevFallDistance); - } - if (entity.hasStatusEffect(UEffects.PARALYSIS) && entity.getVelocity().horizontalLengthSquared() > 0) { entity.setVelocity(entity.getVelocity().multiply(0, 1, 0)); updateVelocity(); @@ -264,11 +251,6 @@ public abstract class Living implements Equine, Caste transportation.tick(); } - private float onLanded(float fallDistance) { - var event = landEvent.getAndSet(null); - return event == null ? fallDistance : event.get(fallDistance); - } - public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction modifierSupplier, boolean permanent) { @Nullable EntityAttributeInstance instance = asEntity().getAttributeInstance(attribute); @@ -474,7 +456,7 @@ public abstract class Living implements Equine, Caste } public float onImpact(float distance, float damageMultiplier, DamageSource cause) { - float fallDistance = onLanded(getEffectiveFallDistance(distance)); + float fallDistance = landEvent.fire(getEffectiveFallDistance(distance)); getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).ifPresent(spell -> { spell.getDisguise().onImpact(this, fallDistance, damageMultiplier, cause); From e053539d1b821f52040ccb02acfe98bd225be3dd Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 17 May 2024 19:28:52 +0100 Subject: [PATCH 11/85] Fixed earth ponies being able to stomp whilst flying with elytra and using riptide --- .../unicopia/ability/EarthPonyStompAbility.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java index 6e862f6f..82586e85 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java @@ -82,7 +82,9 @@ public class EarthPonyStompAbility implements Ability { @Override public Optional prepare(Pony player) { if (player.asEntity().getVelocity().y * player.getPhysics().getGravitySignum() < 0 - && !player.asEntity().getAbilities().flying) { + && !player.asEntity().getAbilities().flying + && !player.asEntity().isFallFlying() + && !player.asEntity().isUsingRiptide()) { thrustDownwards(player); return Hit.INSTANCE; } From 1d156305668b41c24777ad81caf792b54e176d3d Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 18 May 2024 13:14:20 +0100 Subject: [PATCH 12/85] Properly replace existing spells when casting one with different traits. #353 --- .../unicopia/ability/UnicornCastingAbility.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index 64a0e4bf..fae2d49c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -100,12 +100,19 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility { if (newSpell.getResult() != ActionResult.FAIL && canCast(newSpell.getValue().type())) { CustomisedSpellType spell = newSpell.getValue(); + if (newSpell.getResult() == ActionResult.CONSUME) { + CustomisedSpellType equippedType = player.getCharms().getEquippedSpell(player.getCharms().getHand()); + if (equippedType.type() == spell.type()) { + player.getCharms().equipSpell(player.getCharms().getHand(), spell); + } + } + boolean hasExact = player.getSpellSlot().contains(spell); boolean removed = player.getSpellSlot().removeWhere(s -> { - return s.findMatches(spell).findAny().isPresent() && (spell.isEmpty() || !SpellType.PLACED_SPELL.test(s)); + return s.findMatches(spell.type()).findAny().isPresent() && (spell.isEmpty() || !SpellType.PLACED_SPELL.test(s)); }, true); player.subtractEnergyCost(removed ? 2 : 4); - if (!removed) { + if (!hasExact && !spell.isEmpty()) { Spell s = spell.apply(player, CastingMethod.DIRECT); if (s == null) { player.spawnParticles(ParticleTypes.LARGE_SMOKE, 6); From 95ffe5b0b5836bc4c343ffe43c837d5b3f951b0d Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 18 May 2024 14:29:47 +0100 Subject: [PATCH 13/85] Serialize spell type and traits together, and make affinity names translatable --- .../com/minelittlepony/unicopia/Affinity.java | 11 +- .../ability/UnicornCastingAbility.java | 4 +- .../magic/spell/AbstractDelegatingSpell.java | 19 +-- .../ability/magic/spell/PlaceableSpell.java | 4 +- .../unicopia/ability/magic/spell/Spell.java | 32 ++--- .../ability/magic/spell/SpellReference.java | 2 +- .../magic/spell/effect/AbstractSpell.java | 18 +-- .../spell/effect/CustomisedSpellType.java | 33 +++-- .../ability/magic/spell/effect/SpellType.java | 136 +++++++++++++----- .../client/gui/DismissSpellScreen.java | 17 +-- .../client/render/HornFeatureRenderer.java | 2 +- .../entity/MagicBeamEntityRenderer.java | 2 +- .../render/spell/PlacedSpellRenderer.java | 2 +- .../render/spell/ShieldSpellRenderer.java | 2 +- .../spell/SpellEffectsRenderDispatcher.java | 6 +- .../client/render/spell/SpellRenderer.java | 2 +- .../entity/player/PlayerCharmTracker.java | 2 +- .../unicopia/entity/player/Pony.java | 2 +- .../unicopia/item/EnchantedStaffItem.java | 6 +- .../unicopia/server/world/Ether.java | 12 +- .../resources/assets/unicopia/lang/en_us.json | 4 + 21 files changed, 188 insertions(+), 130 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/Affinity.java b/src/main/java/com/minelittlepony/unicopia/Affinity.java index e1c4e3a9..724cbdc4 100644 --- a/src/main/java/com/minelittlepony/unicopia/Affinity.java +++ b/src/main/java/com/minelittlepony/unicopia/Affinity.java @@ -2,8 +2,10 @@ package com.minelittlepony.unicopia; import java.util.Locale; +import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.StringIdentifiable; +import net.minecraft.util.Util; public enum Affinity implements StringIdentifiable { GOOD(Formatting.BLUE, -1, 0), @@ -20,10 +22,13 @@ public enum Affinity implements StringIdentifiable { public static final Affinity[] VALUES = values(); + private final String translationKey; + Affinity(Formatting color, int corruption, float alignment) { this.color = color; this.corruption = corruption; this.alignment = alignment; + this.translationKey = Util.createTranslationKey("affinity", Unicopia.id(name().toLowerCase(Locale.ROOT))); } @Override @@ -36,7 +41,11 @@ public enum Affinity implements StringIdentifiable { } public String getTranslationKey() { - return this == BAD ? "curse" : "spell"; + return translationKey; + } + + public Text getDisplayName() { + return Text.translatable(getTranslationKey()); } public int getCorruption() { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index fae2d49c..d47f098d 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -108,9 +108,7 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility { } boolean hasExact = player.getSpellSlot().contains(spell); - boolean removed = player.getSpellSlot().removeWhere(s -> { - return s.findMatches(spell.type()).findAny().isPresent() && (spell.isEmpty() || !SpellType.PLACED_SPELL.test(s)); - }, true); + boolean removed = !spell.isStackable() && player.getSpellSlot().removeWhere(s -> s.findMatches(spell.type()).findAny().isPresent(), true); player.subtractEnergyCost(removed ? 2 : 4); if (!hasExact && !spell.isEmpty()) { Spell s = spell.apply(player, CastingMethod.DIRECT); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index 68a006ed..c27fb13c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -5,11 +5,8 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; -import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; -import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; @@ -26,10 +23,10 @@ public abstract class AbstractDelegatingSpell implements Spell, private UUID uuid = UUID.randomUUID(); - private final SpellType type; + private final CustomisedSpellType type; public AbstractDelegatingSpell(CustomisedSpellType type) { - this.type = type.type(); + this.type = type; } public abstract Collection getDelegates(); @@ -45,20 +42,10 @@ public abstract class AbstractDelegatingSpell implements Spell, } @Override - public Affinity getAffinity() { - return Affinity.NEUTRAL; - } - - @Override - public SpellType getType() { + public CustomisedSpellType getTypeAndTraits() { return type; } - @Override - public SpellTraits getTraits() { - return getDelegates().stream().map(Spell::getTraits).reduce(SpellTraits.EMPTY, SpellTraits::union); - } - @Override public final UUID getUuid() { return uuid; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index 1eb59540..ab724eaa 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -154,7 +154,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS } private void checkDetachment(Caster source, EntityValues target) { - if (getWorld(source).map(Ether::get).map(ether -> ether.get(getType(), target, placedSpellId)).isEmpty()) { + if (getWorld(source).map(Ether::get).map(ether -> ether.get(getTypeAndTraits().type(), target, placedSpellId)).isEmpty()) { setDead(); } } @@ -202,7 +202,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS if (!source.isClient()) { castEntity.getTarget().ifPresent(target -> { getWorld(source).map(Ether::get) - .ifPresent(ether -> ether.remove(getType(), target.uuid())); + .ifPresent(ether -> ether.remove(getTypeAndTraits().type(), target.uuid())); }); castEntity.set(null); getSpellEntity(source).ifPresent(e -> { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index 0c504041..30a93dd2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -7,11 +7,12 @@ import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; import org.spongepowered.include.com.google.common.base.Objects; +import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; -import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.util.NbtSerialisable; import net.minecraft.nbt.NbtCompound; @@ -24,14 +25,18 @@ public interface Spell extends NbtSerialisable, Affine { Serializer SERIALIZER = Serializer.of(Spell::readNbt, Spell::writeNbt); /** - * Returns the registered type of this spell. + * Returns the full type that describes this spell. */ - SpellType getType(); + CustomisedSpellType getTypeAndTraits(); - /** - * Gets the traits of this spell. - */ - SpellTraits getTraits(); + default boolean isOf(SpellType type) { + return getTypeAndTraits().type() == type; + } + + @Override + default Affinity getAffinity() { + return getTypeAndTraits().type().getAffinity(); + } /** * The unique id of this particular spell instance. @@ -132,15 +137,8 @@ public interface Spell extends NbtSerialisable, Affine { @Nullable static T readNbt(@Nullable NbtCompound compound) { try { - if (compound != null && compound.contains("effect_id")) { - @SuppressWarnings("unchecked") - T effect = (T)SpellType.getKey(compound).withTraits().create(); - - if (effect != null) { - effect.fromNBT(compound); - } - - return effect; + if (compound != null) { + return CustomisedSpellType.fromNBT(compound).create(compound); } } catch (Exception e) { Unicopia.LOGGER.fatal("Invalid spell nbt {}", e); @@ -155,7 +153,7 @@ public interface Spell extends NbtSerialisable, Affine { static NbtCompound writeNbt(Spell effect) { NbtCompound compound = effect.toNBT(); - effect.getType().toNbt(compound); + effect.getTypeAndTraits().toNbt(compound); return compound; } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java index cca32178..97152693 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java @@ -44,7 +44,7 @@ public final class SpellReference implements NbtSerialisable { public void toNBT(NbtCompound compound) { if (spell != null && !spell.isDead()) { spell.toNBT(compound); - spell.getType().toNbt(compound); + spell.getTypeAndTraits().type().toNbt(compound); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java index 1660c01e..ada82e85 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java @@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; import java.util.UUID; -import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; @@ -17,7 +16,7 @@ public abstract class AbstractSpell implements Spell { private boolean hidden; private boolean destroyed; - private CustomisedSpellType type; + private final CustomisedSpellType type; private UUID uuid = UUID.randomUUID(); @@ -30,17 +29,16 @@ public abstract class AbstractSpell implements Spell { return uuid; } - @Override - public final SpellType getType() { + protected final SpellType getType() { return type.type(); } + @Override public final CustomisedSpellType getTypeAndTraits() { return type; } - @Override - public final SpellTraits getTraits() { + protected final SpellTraits getTraits() { return type.traits(); } @@ -80,11 +78,6 @@ public abstract class AbstractSpell implements Spell { this.hidden = hidden; } - @Override - public Affinity getAffinity() { - return getType().getAffinity(); - } - protected void onDestroyed(Caster caster) { } @@ -121,9 +114,6 @@ public abstract class AbstractSpell implements Spell { dying = compound.getBoolean("dying"); dead = compound.getBoolean("dead"); hidden = compound.getBoolean("hidden"); - if (compound.contains("traits")) { - type = type.type().withTraits(SpellTraits.fromNbt(compound.getCompound("traits")).orElse(SpellTraits.EMPTY)); - } } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java index 4c346401..bd0e73e8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java @@ -21,6 +21,10 @@ public record CustomisedSpellType ( return type.isEmpty(); } + public boolean isStackable() { + return type().isStackable(); + } + public T create() { try { return type.getFactory().create(this); @@ -31,6 +35,14 @@ public record CustomisedSpellType ( return null; } + @Nullable + public T create(NbtCompound compound) { + T spell = create(); + if (spell != null) { + spell.fromNBT(compound); + } + return spell; + } @Nullable public T apply(Caster caster, CastingMethod method) { @@ -50,8 +62,8 @@ public record CustomisedSpellType ( } @Override - public boolean test(Spell spell) { - return type.test(spell) && spell.getTraits().equals(traits); + public boolean test(@Nullable Spell spell) { + return spell != null && spell.getTypeAndTraits().equals(this); } public ItemStack getDefaultStack() { @@ -62,17 +74,14 @@ public record CustomisedSpellType ( return isEmpty() ? TypedActionResult.fail(this) : TypedActionResult.pass(this); } - public NbtCompound toNBT() { - NbtCompound tag = new NbtCompound(); - type.toNbt(tag); - tag.put("traits", traits.toNbt()); - return tag; + public NbtCompound toNbt(NbtCompound compound) { + type.toNbt(compound); + compound.put("traits", traits.toNbt()); + return compound; } - public static CustomisedSpellType fromNBT(NbtCompound compound) { - SpellType type = SpellType.getKey(compound); - SpellTraits traits = SpellTraits.fromNbt(compound.getCompound("traits")).orElse(type.getTraits()); - - return type.withTraits(traits); + public static CustomisedSpellType fromNBT(NbtCompound compound) { + SpellType type = SpellType.getKey(compound); + return type.withTraits(SpellTraits.fromNbt(compound.getCompound("traits")).orElse(type.getTraits())); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index e963c0e7..c73def7c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -34,47 +34,47 @@ import net.minecraft.server.command.ServerCommandSource; public final class SpellType implements Affine, SpellPredicate { public static final Identifier EMPTY_ID = Unicopia.id("none"); - public static final SpellType EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, GemstoneItem.Shape.ROUND, SpellTraits.EMPTY, t -> null); + public static final SpellType EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, false, GemstoneItem.Shape.ROUND, SpellTraits.EMPTY, t -> null); public static final Registry> REGISTRY = RegistryUtils.createSimple(Unicopia.id("spells")); public static final RegistryKey>> REGISTRY_KEY = REGISTRY.getKey(); private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id)); - public static final SpellType PLACED_SPELL = register("placed", Affinity.NEUTRAL, 0, false, GemstoneItem.Shape.DONUT, SpellTraits.EMPTY, PlaceableSpell::new); - public static final SpellType THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, GemstoneItem.Shape.DONUT, SpellTraits.EMPTY, ThrowableSpell::new); + public static final SpellType PLACED_SPELL = register("placed", builder(PlaceableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().stackable().shape(GemstoneItem.Shape.DONUT)); + public static final SpellType THROWN_SPELL = register("thrown", builder(ThrowableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().shape(GemstoneItem.Shape.DONUT)); - public static final SpellType CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, DispersableDisguiseSpell::new); - public static final SpellType FEED = register("feed", Affinity.BAD, 0xBDBDF9, false, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, ChangelingFeedingSpell::new); - public static final SpellType RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.ROCKET, SpellTraits.EMPTY, RainboomAbilitySpell::new); - public static final SpellType RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.FLAME, SpellTraits.EMPTY, RageAbilitySpell::new); - public static final SpellType TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.STAR, SpellTraits.EMPTY, TimeControlAbilitySpell::new); + public static final SpellType CHANGELING_DISGUISE = register("disguise", builder(DispersableDisguiseSpell::new).affinity(Affinity.BAD).color(0x19E48E).unobtainable().shape(GemstoneItem.Shape.ARROW)); + public static final SpellType FEED = register("feed", SpellType.builder(ChangelingFeedingSpell::new).affinity(Affinity.BAD).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.ARROW)); + public static final SpellType RAINBOOM = register("rainboom", builder(RainboomAbilitySpell::new).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.ROCKET)); + public static final SpellType RAGE = register("rage", builder(RageAbilitySpell::new).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.FLAME)); + public static final SpellType TIME_CONTROL = register("time_control", builder(TimeControlAbilitySpell::new).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.STAR)); - public static final SpellType FROST = register("frost", Affinity.GOOD, 0xEABBFF, true, GemstoneItem.Shape.TRIANGLE, IceSpell.DEFAULT_TRAITS, IceSpell::new); - public static final SpellType CHILLING_BREATH = register("chilling_breath", Affinity.NEUTRAL, 0xFFEAFF, true, GemstoneItem.Shape.TRIANGLE, ChillingBreathSpell.DEFAULT_TRAITS, ChillingBreathSpell::new); - public static final SpellType SCORCH = register("scorch", Affinity.BAD, 0xF8EC1F, true, GemstoneItem.Shape.FLAME, ScorchSpell.DEFAULT_TRAITS, ScorchSpell::new); - public static final SpellType FLAME = register("flame", Affinity.GOOD, 0xFFBB99, true, GemstoneItem.Shape.FLAME, FireSpell.DEFAULT_TRAITS, FireSpell::new); - public static final SpellType INFERNAL = register("infernal", Affinity.BAD, 0xFFAA00, true, GemstoneItem.Shape.FLAME, InfernoSpell.DEFAULT_TRAITS, InfernoSpell::new); - public static final SpellType SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, GemstoneItem.Shape.SHIELD, ShieldSpell.DEFAULT_TRAITS, ShieldSpell::new); - public static final SpellType ARCANE_PROTECTION = register("arcane_protection", Affinity.BAD, 0x99CDAA, true, GemstoneItem.Shape.SHIELD, AreaProtectionSpell.DEFAULT_TRAITS, AreaProtectionSpell::new); - public static final SpellType VORTEX = register("vortex", Affinity.NEUTRAL, 0xFFEA88, true, GemstoneItem.Shape.VORTEX, AttractiveSpell.DEFAULT_TRAITS, AttractiveSpell::new); - public static final SpellType DARK_VORTEX = register("dark_vortex", Affinity.BAD, 0xA33333, true, GemstoneItem.Shape.VORTEX, DarkVortexSpell.DEFAULT_TRAITS, DarkVortexSpell::new); - public static final SpellType NECROMANCY = register("necromancy", Affinity.BAD, 0xFA3A3A, true, GemstoneItem.Shape.SKULL, SpellTraits.EMPTY, NecromancySpell::new); - public static final SpellType SIPHONING = register("siphoning", Affinity.NEUTRAL, 0xFFA3AA, true, GemstoneItem.Shape.LAMBDA, SpellTraits.EMPTY, SiphoningSpell::new); - public static final SpellType REVEALING = register("reveal", Affinity.GOOD, 0xFFFFAF, true, GemstoneItem.Shape.CROSS, SpellTraits.EMPTY, DisperseIllusionSpell::new); - public static final SpellType AWKWARD = register("awkward", Affinity.GOOD, 0x3A59FF, true, GemstoneItem.Shape.ICE, SpellTraits.EMPTY, AwkwardSpell::new); - public static final SpellType TRANSFORMATION = register("transformation", Affinity.GOOD, 0x19E48E, true, GemstoneItem.Shape.BRUSH, SpellTraits.EMPTY, TransformationSpell::new); - public static final SpellType FEATHER_FALL = register("feather_fall", Affinity.GOOD, 0x00EEFF, true, GemstoneItem.Shape.LAMBDA, FeatherFallSpell.DEFAULT_TRAITS, FeatherFallSpell::new); - public static final SpellType CATAPULT = register("catapult", Affinity.GOOD, 0x22FF00, true, GemstoneItem.Shape.ROCKET, CatapultSpell.DEFAULT_TRAITS, CatapultSpell::new); - public static final SpellType FIRE_BOLT = register("fire_bolt", Affinity.GOOD, 0xFF8811, true, GemstoneItem.Shape.FLAME, FireBoltSpell.DEFAULT_TRAITS, FireBoltSpell::new); - public static final SpellType LIGHT = register("light", Affinity.GOOD, 0xEEFFAA, true, GemstoneItem.Shape.STAR, LightSpell.DEFAULT_TRAITS, LightSpell::new); - public static final SpellType DISPLACEMENT = register("displacement", Affinity.NEUTRAL, 0x9900FF, true, GemstoneItem.Shape.BRUSH, PortalSpell.DEFAULT_TRAITS, DisplacementSpell::new); - public static final SpellType PORTAL = register("portal", Affinity.GOOD, 0x99FFFF, true, GemstoneItem.Shape.RING, PortalSpell.DEFAULT_TRAITS, PortalSpell::new); - public static final SpellType MIMIC = register("mimic", Affinity.GOOD, 0xFFFF00, true, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, MimicSpell::new); - public static final SpellType MIND_SWAP = register("mind_swap", Affinity.BAD, 0xF9FF99, true, GemstoneItem.Shape.WAVE, SpellTraits.EMPTY, MindSwapSpell::new); - public static final SpellType HYDROPHOBIC = register("hydrophobic", Affinity.NEUTRAL, 0xF999FF, true, GemstoneItem.Shape.ROCKET, SpellTraits.EMPTY, s -> new HydrophobicSpell(s, FluidTags.WATER)); - public static final SpellType BUBBLE = register("bubble", Affinity.NEUTRAL, 0xF999FF, true, GemstoneItem.Shape.DONUT, BubbleSpell.DEFAULT_TRAITS, BubbleSpell::new); - public static final SpellType DISPEL_EVIL = register("dispel_evil", Affinity.GOOD, 0x00FF00, true, GemstoneItem.Shape.CROSS, DispellEvilSpell.DEFAULT_TRAITS, DispellEvilSpell::new); + public static final SpellType FROST = register("frost", builder(IceSpell::new).color(0xEABBFF).shape(GemstoneItem.Shape.TRIANGLE).traits(IceSpell.DEFAULT_TRAITS)); + public static final SpellType CHILLING_BREATH = register("chilling_breath", builder(ChillingBreathSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEAFF).shape(GemstoneItem.Shape.TRIANGLE).traits(ChillingBreathSpell.DEFAULT_TRAITS)); + public static final SpellType SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS)); + public static final SpellType FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS)); + public static final SpellType INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS)); + public static final SpellType SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS)); + public static final SpellType ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS)); + public static final SpellType VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS)); + public static final SpellType DARK_VORTEX = register("dark_vortex", builder(DarkVortexSpell::new).affinity(Affinity.BAD).color(0xA33333).shape(GemstoneItem.Shape.VORTEX).traits(DarkVortexSpell.DEFAULT_TRAITS)); + public static final SpellType NECROMANCY = register("necromancy", builder(NecromancySpell::new).affinity(Affinity.BAD).color(0xFA3A3A).shape(GemstoneItem.Shape.SKULL)); + public static final SpellType SIPHONING = register("siphoning", builder(SiphoningSpell::new).affinity(Affinity.NEUTRAL).color(0xFFA3AA).shape(GemstoneItem.Shape.LAMBDA)); + public static final SpellType REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS)); + public static final SpellType AWKWARD = register("awkward", builder(AwkwardSpell::new).affinity(Affinity.NEUTRAL).color(0x3A59FF).shape(GemstoneItem.Shape.ICE)); + public static final SpellType TRANSFORMATION = register("transformation", builder(TransformationSpell::new).color(0x19E48E).shape(GemstoneItem.Shape.BRUSH)); + public static final SpellType FEATHER_FALL = register("feather_fall", builder(FeatherFallSpell::new).color(0x00EEFF).shape(GemstoneItem.Shape.LAMBDA).traits(FeatherFallSpell.DEFAULT_TRAITS)); + public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS)); + public static final SpellType FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS)); + public static final SpellType LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS)); + public static final SpellType DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS)); + public static final SpellType PORTAL = register("portal", builder(PortalSpell::new).color(0x99FFFF).shape(GemstoneItem.Shape.RING).traits(PortalSpell.DEFAULT_TRAITS)); + public static final SpellType MIMIC = register("mimic", builder(MimicSpell::new).color(0xFFFF00).shape(GemstoneItem.Shape.ARROW)); + public static final SpellType MIND_SWAP = register("mind_swap", builder(MindSwapSpell::new).affinity(Affinity.BAD).color(0xF9FF99).shape(GemstoneItem.Shape.WAVE)); + public static final SpellType HYDROPHOBIC = register("hydrophobic", SpellType.builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.ROCKET)); + public static final SpellType BUBBLE = register("bubble", builder(BubbleSpell::new).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.DONUT).traits(BubbleSpell.DEFAULT_TRAITS)); + public static final SpellType DISPEL_EVIL = register("dispel_evil", builder(DispellEvilSpell::new).color(0x00FF00).shape(GemstoneItem.Shape.CROSS).traits(DispellEvilSpell.DEFAULT_TRAITS)); public static void bootstrap() {} @@ -82,6 +82,7 @@ public final class SpellType implements Affine, SpellPredicate< private final Affinity affinity; private final int color; private final boolean obtainable; + private final boolean stackable; private final GemstoneItem.Shape shape; private final Factory factory; @@ -94,7 +95,7 @@ public final class SpellType implements Affine, SpellPredicate< private final ItemStack defaultStack; - private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory factory) { + private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, boolean stackable, GemstoneItem.Shape shape, SpellTraits traits, Factory factory) { this.id = id; this.affinity = affinity; this.color = color; @@ -102,6 +103,7 @@ public final class SpellType implements Affine, SpellPredicate< this.shape = shape; this.factory = factory; this.traits = traits; + this.stackable = stackable; traited = new CustomisedSpellType<>(this, traits); defaultStack = UItems.GEMSTONE.getDefaultStack(this); } @@ -110,6 +112,10 @@ public final class SpellType implements Affine, SpellPredicate< return obtainable; } + public boolean isStackable() { + return stackable; + } + public Identifier getId() { return id; } @@ -163,7 +169,7 @@ public final class SpellType implements Affine, SpellPredicate< @Override public boolean test(@Nullable Spell spell) { - return spell != null && spell.getType() == this; + return spell != null && spell.getTypeAndTraits().type() == this; } public void toNbt(NbtCompound tag) { @@ -179,12 +185,12 @@ public final class SpellType implements Affine, SpellPredicate< return "SpellType[" + getTranslationKey() + "]"; } - public static SpellType register(String name, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory factory) { - return register(Unicopia.id(name), affinity, color, obtainable, shape, traits, factory); + public static SpellType register(String name, Builder builder) { + return register(Unicopia.id(name), builder); } - public static SpellType register(Identifier id, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory factory) { - return Registry.register(REGISTRY, id, new SpellType<>(id, affinity, color, obtainable, shape, traits, factory)); + public static SpellType register(Identifier id, Builder builder) { + return Registry.register(REGISTRY, id, builder.build(id)); } @SuppressWarnings("unchecked") @@ -209,4 +215,56 @@ public final class SpellType implements Affine, SpellPredicate< public interface Factory { T create(CustomisedSpellType type); } + + public static Builder builder(Factory factory) { + return new Builder<>(factory); + } + + static class Builder { + private final Factory factory; + private Affinity affinity = Affinity.GOOD; + private int color; + private boolean obtainable = true; + private boolean stackable = false; + private GemstoneItem.Shape shape = GemstoneItem.Shape.ROUND; + private SpellTraits traits = SpellTraits.EMPTY; + + Builder(Factory factory) { + this.factory = factory; + } + + public Builder affinity(Affinity affinity) { + this.affinity = affinity; + return this; + } + + public Builder color(int color) { + this.color = color; + return this; + } + + public Builder unobtainable() { + obtainable = false; + return this; + } + + public Builder stackable() { + stackable = true; + return this; + } + + public Builder shape(GemstoneItem.Shape shape) { + this.shape = shape; + return this; + } + + public Builder traits(SpellTraits traits) { + this.traits = traits; + return this; + } + + public SpellType build(Identifier id) { + return new SpellType<>(id, affinity, color, obtainable, stackable, shape, traits, factory); + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 8361a045..17182cef 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -164,18 +164,19 @@ public class DismissSpellScreen extends GameGui { public void render(DrawContext context, int mouseX, int mouseY, float tickDelta) { MatrixStack matrices = context.getMatrices(); - var type = actualSpell.getType().withTraits(actualSpell.getTraits()); + var type = actualSpell.getTypeAndTraits(); + var affinity = actualSpell.getAffinity(); copy.set(mouseX - width * 0.5F - x * 0.5F, mouseY - height * 0.5F - y * 0.5F, 0, 0); - DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, actualSpell.getAffinity().getColor().getColorValue()); + DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, affinity.getColor().getColorValue()); DrawableUtil.renderItemIcon(context, actualSpell.isDead() ? UItems.BOTCHED_GEM.getDefaultStack() : type.getDefaultStack(), x - 8 - copy.x * 0.2F, y - 8 - copy.y * 0.2F, 1 ); - int color = actualSpell.getType().getColor() << 2; + int color = type.type().getColor() << 2; matrices.push(); matrices.translate(x, y, 0); @@ -187,15 +188,15 @@ public class DismissSpellScreen extends GameGui { List tooltip = new ArrayList<>(); - MutableText name = actualSpell.getType().getName().copy(); - color = actualSpell.getType().getColor(); + MutableText name = type.type().getName().copy(); + color = type.type().getColor(); name.setStyle(name.getStyle().withColor(color == 0 ? 0xFFAAAAAA : color)); tooltip.add(Text.translatable("gui.unicopia.dispell_screen.spell_type", name)); - actualSpell.getType().getTraits().appendTooltip(tooltip); + type.traits().appendTooltip(tooltip); tooltip.add(ScreenTexts.EMPTY); - tooltip.add(Text.translatable("gui.unicopia.dispell_screen.affinity", actualSpell.getAffinity().name()).formatted(actualSpell.getAffinity().getColor())); + tooltip.add(Text.translatable("gui.unicopia.dispell_screen.affinity", affinity.getDisplayName()).formatted(affinity.getColor())); tooltip.add(ScreenTexts.EMPTY); - tooltip.addAll(TextHelper.wrap(Text.translatable(actualSpell.getType().getTranslationKey() + ".lore").formatted(actualSpell.getAffinity().getColor()), 180).toList()); + tooltip.addAll(TextHelper.wrap(Text.translatable(type.type().getTranslationKey() + ".lore").formatted(affinity.getColor()), 180).toList()); if (spell instanceof TimedSpell timed) { tooltip.add(ScreenTexts.EMPTY); tooltip.add(Text.translatable("gui.unicopia.dispell_screen.time_left", StringHelper.formatTicks(timed.getTimer().getTicksRemaining()))); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java index 068263e5..786dee41 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java @@ -55,7 +55,7 @@ public class HornFeatureRenderer implements AccessoryFea return pony.getAbilities().getActiveStat() .flatMap(Stat::getActiveAbility) .map(ability -> ability.getColor(pony)) - .filter(i -> i != -1).or(() -> pony.getSpellSlot().get(SpellPredicate.IS_NOT_PLACED, false).map(spell -> spell.getType().getColor())); + .filter(i -> i != -1).or(() -> pony.getSpellSlot().get(SpellPredicate.IS_NOT_PLACED, false).map(spell -> spell.getTypeAndTraits().type().getColor())); }).ifPresent(color -> { model.setState(true); model.render(stack, ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayers.getMagicColored((0x99 << 24) | color), false, false), lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/MagicBeamEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/MagicBeamEntityRenderer.java index 26e2297a..24d4a042 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/MagicBeamEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/MagicBeamEntityRenderer.java @@ -57,7 +57,7 @@ public class MagicBeamEntityRenderer extends EntityRenderer { ); RenderLayer layer = entity.getSpellSlot().get(true) - .map(spell -> (0x99 << 24) | spell.getType().getColor()) + .map(spell -> (0x99 << 24) | spell.getTypeAndTraits().type().getColor()) .map(RenderLayers::getMagicColored) .orElseGet(RenderLayers::getMagicColored); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java index fbdfce47..ee08654d 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java @@ -66,7 +66,7 @@ public class PlacedSpellRenderer extends SpellRenderer { float angle = (animationProgress / 9F) % 360; - int color = delegate.getType().getColor(); + int color = delegate.getTypeAndTraits().type().getColor(); float red = Color.r(color); float green = Color.g(color); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java index 1fc202ad..70fd70f3 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java @@ -27,7 +27,7 @@ public class ShieldSpellRenderer extends SpellRenderer { double height = caster.asEntity().getEyeY() - caster.getOriginVector().y; matrices.translate(0, height, 0); - int typeColor = spell.getType().getColor(); + int typeColor = spell.getTypeAndTraits().type().getColor(); int ponyColor = MineLPDelegate.getInstance().getMagicColor(caster.getOriginatingCaster().asEntity()); int color = ColorHelper.lerp(caster.getCorruption().getScaled(1) * (tickDelta / (1 + caster.asWorld().random.nextFloat())), diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index c87430da..90bfbbb2 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -68,7 +68,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader @SuppressWarnings("unchecked") public SpellRenderer getRenderer(S spell) { - return (SpellRenderer)renderers.getOrDefault(spell.getType(), SpellRenderer.DEFAULT); + return (SpellRenderer)renderers.getOrDefault(spell.getTypeAndTraits().type(), SpellRenderer.DEFAULT); } public void render(MatrixStack matrices, VertexConsumerProvider vertices, Spell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { @@ -127,8 +127,8 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader caster.getSpellSlot().stream(AllSpells.INSTANCE, false).flatMap(spell -> Stream.of( Text.literal("UUID: " + spell.getUuid()), - Text.literal("|>Type: ").append(Text.literal(spell.getType().getId().toString()).styled(s -> s.withColor(spell.getType().getColor()))), - Text.of("|>Traits: " + spell.getTraits()), + Text.literal("|>Type: ").append(Text.literal(spell.getTypeAndTraits().type().getId().toString()).styled(s -> s.withColor(spell.getTypeAndTraits().type().getColor()))), + Text.of("|>Traits: " + spell.getTypeAndTraits().traits()), Text.literal("|>HasRenderer: ").append(Text.literal((getRenderer(spell) != null) + "").formatted(getRenderer(spell) != null ? Formatting.GREEN : Formatting.RED)) ) ) diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java index cdaf9f79..74e72212 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java @@ -42,7 +42,7 @@ public class SpellRenderer { matrices.push(); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(animationProgress)); - client.getItemRenderer().renderItem(spell.getType().withTraits(spell.getTraits()).getDefaultStack(), ModelTransformationMode.FIXED, light, 0, matrices, vertices, caster.asWorld(), 0); + client.getItemRenderer().renderItem(spell.getTypeAndTraits().getDefaultStack(), ModelTransformationMode.FIXED, light, 0, matrices, vertices, caster.asWorld(), 0); matrices.pop(); if (spell instanceof TimedSpell timed) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java index aeaf4d73..2721ec83 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java @@ -66,7 +66,7 @@ public class PlayerCharmTracker implements NbtSerialisable { public void toNBT(NbtCompound compound) { NbtList equippedSpells = new NbtList(); for (CustomisedSpellType spell : handSpells) { - equippedSpells.add(spell.toNBT()); + equippedSpells.add(spell.toNbt(new NbtCompound())); } compound.put("handSpells", equippedSpells); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index b8f30cd5..5502920a 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -955,7 +955,7 @@ public class Pony extends Living implements Copyable, Update if (spell.getAffinity() == Affinity.BAD && entity.getWorld().random.nextInt(20) == 0) { getCorruption().add(entity.getRandom().nextBetween(1, 10)); } - getCorruption().add((int)spell.getTraits().getCorruption() * 10); + getCorruption().add((int)spell.getTypeAndTraits().traits().getCorruption() * 10); setDirty(); } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java index 08798972..6d08b1f7 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; @@ -46,7 +47,10 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch public static SpellType getSpellType(Entity entity, boolean remove) { if (entity instanceof CastSpellEntity cast) { - return cast.getSpellSlot().get(c -> !SpellPredicate.IS_PLACED.test(c), true).map(Spell::getType).orElse(SpellType.empty()); + return cast.getSpellSlot().get(c -> !SpellPredicate.IS_PLACED.test(c), true) + .map(Spell::getTypeAndTraits) + .map(CustomisedSpellType::type) + .orElse(SpellType.empty()); } if (entity instanceof PlayerEntity player) { if (remove) { diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index d60b7607..1dd46a92 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -25,7 +25,7 @@ public class Ether extends PersistentState { return WorldOverlay.getPersistableStorage(world, ID, Ether::new, Ether::new); } - private final Map>>> endpoints; + private final Map, Map>>> endpoints; private final Object locker = new Object(); @@ -33,7 +33,7 @@ public class Ether extends PersistentState { Ether(World world, NbtCompound compound) { this.world = world; - this.endpoints = NbtSerialisable.readMap(compound.getCompound("endpoints"), Identifier::tryParse, typeNbt -> { + this.endpoints = NbtSerialisable.readMap(compound.getCompound("endpoints"), id -> SpellType.getKey(Identifier.tryParse(id)), typeNbt -> { return NbtSerialisable.readMap((NbtCompound)typeNbt, UUID::fromString, entityNbt -> { return NbtSerialisable.readMap((NbtCompound)entityNbt, UUID::fromString, Entry::new); }); @@ -49,7 +49,7 @@ public class Ether extends PersistentState { public NbtCompound writeNbt(NbtCompound compound) { synchronized (locker) { pruneNodes(); - compound.put("endpoints", NbtSerialisable.writeMap(endpoints, Identifier::toString, entities -> { + compound.put("endpoints", NbtSerialisable.writeMap(endpoints, type -> type.getId().toString(), entities -> { return NbtSerialisable.writeMap(entities, UUID::toString, spells -> { return NbtSerialisable.writeMap(spells, UUID::toString, Entry::toNBT); }); @@ -62,7 +62,7 @@ public class Ether extends PersistentState { public Entry getOrCreate(T spell, Caster caster) { synchronized (locker) { Entry entry = (Entry)endpoints - .computeIfAbsent(spell.getType().getId(), typeId -> new HashMap<>()) + .computeIfAbsent(spell.getTypeAndTraits().type(), typeId -> new HashMap<>()) .computeIfAbsent(caster.asEntity().getUuid(), entityId -> new HashMap<>()) .computeIfAbsent(spell.getUuid(), spellid -> { markDirty(); @@ -82,7 +82,7 @@ public class Ether extends PersistentState { public void remove(SpellType spellType, UUID entityId) { synchronized (locker) { - endpoints.computeIfPresent(spellType.getId(), (typeId, entries) -> { + endpoints.computeIfPresent(spellType, (typeId, entries) -> { if (entries.remove(entityId) != null) { markDirty(); } @@ -104,7 +104,7 @@ public class Ether extends PersistentState { @SuppressWarnings("unchecked") public Entry get(T spell, Caster caster) { - return get((SpellType)spell.getType(), caster.asEntity().getUuid(), spell.getUuid()); + return get((SpellType)spell.getTypeAndTraits().type(), caster.asEntity().getUuid(), spell.getUuid()); } public Entry get(SpellType spell, EntityReference.EntityValues entityId, @Nullable UUID spellId) { diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index dcacc971..717632bd 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -725,6 +725,10 @@ "ability.unicopia.dash": "Flying Dash", "ability.unicopia.change_form": "Change Form", "ability.unicopia.sonar_pulse": "Sonar Pulse", + + "affinity.unicopia.good": "Good", + "affinity.unicopia.bad": "Bad", + "affinity.unicopia.neutral": "Neutral", "gui.unicopia.trait.label": "Element of %s", "gui.unicopia.trait.group": "\n %s", From 8a3abf56225ccf6a3aec162341d34e1982fe623b Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 18 May 2024 14:55:41 +0100 Subject: [PATCH 14/85] Display the amount of corruption you would gain from casting a spell --- .../java/com/minelittlepony/unicopia/Affinity.java | 2 +- .../unicopia/client/gui/DismissSpellScreen.java | 2 +- .../minelittlepony/unicopia/entity/player/Pony.java | 2 +- .../minelittlepony/unicopia/item/GemstoneItem.java | 11 ++++++++--- src/main/resources/assets/unicopia/lang/en_us.json | 2 ++ 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/Affinity.java b/src/main/java/com/minelittlepony/unicopia/Affinity.java index 724cbdc4..c84e3810 100644 --- a/src/main/java/com/minelittlepony/unicopia/Affinity.java +++ b/src/main/java/com/minelittlepony/unicopia/Affinity.java @@ -45,7 +45,7 @@ public enum Affinity implements StringIdentifiable { } public Text getDisplayName() { - return Text.translatable(getTranslationKey()); + return Text.translatable(getTranslationKey()).formatted(getColor()); } public int getCorruption() { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 17182cef..8633b6f7 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -194,7 +194,7 @@ public class DismissSpellScreen extends GameGui { tooltip.add(Text.translatable("gui.unicopia.dispell_screen.spell_type", name)); type.traits().appendTooltip(tooltip); tooltip.add(ScreenTexts.EMPTY); - tooltip.add(Text.translatable("gui.unicopia.dispell_screen.affinity", affinity.getDisplayName()).formatted(affinity.getColor())); + tooltip.add(Text.translatable("gui.unicopia.dispell_screen.affinity", affinity.getDisplayName())); tooltip.add(ScreenTexts.EMPTY); tooltip.addAll(TextHelper.wrap(Text.translatable(type.type().getTranslationKey() + ".lore").formatted(affinity.getColor()), 180).toList()); if (spell instanceof TimedSpell timed) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 5502920a..87a8d8d9 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -955,7 +955,7 @@ public class Pony extends Living implements Copyable, Update if (spell.getAffinity() == Affinity.BAD && entity.getWorld().random.nextInt(20) == 0) { getCorruption().add(entity.getRandom().nextBetween(1, 10)); } - getCorruption().add((int)spell.getTypeAndTraits().traits().getCorruption() * 10); + getCorruption().add(((int)spell.getTypeAndTraits().traits().getCorruption() * 10) + spell.getTypeAndTraits().type().getAffinity().getCorruption()); setDirty(); } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java index cc2a70cf..3ccf6cae 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java @@ -80,15 +80,20 @@ public class GemstoneItem extends Item implements MultiItem, EnchantableItem { super.appendTooltip(stack, world, lines, tooltipContext); if (EnchantableItem.isEnchanted(stack)) { - SpellType key = EnchantableItem.getSpellKey(stack); + CustomisedSpellType type = getSpellEffect(stack); - MutableText line = Text.translatable(key.getTranslationKey() + ".lore").formatted(key.getAffinity().getColor()); + MutableText line = Text.translatable(type.type().getTranslationKey() + ".lore").formatted(type.type().getAffinity().getColor()); if (!InteractionManager.getInstance().getClientSpecies().canCast()) { line = line.formatted(Formatting.OBFUSCATED); } - lines.addAll(TextHelper.wrap(line, 180).toList()); + lines.add(Text.empty()); + float corruption = ((int)type.traits().getCorruption() * 10) + type.type().getAffinity().getCorruption(); + if (corruption != 0) { + lines.add(Text.translatable("affinity.unicopia.when_cast").formatted(Formatting.GRAY)); + lines.add(Text.translatable("affinity.unicopia.corruption", corruption > 0 ? "+" : "-", ItemStack.MODIFIER_FORMAT.format(Math.abs(corruption))).formatted(corruption < 0 ? Formatting.DARK_GREEN : Formatting.RED)); + } } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 717632bd..a6c45570 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -729,6 +729,8 @@ "affinity.unicopia.good": "Good", "affinity.unicopia.bad": "Bad", "affinity.unicopia.neutral": "Neutral", + "affinity.unicopia.when_cast": "When Cast:", + "affinity.unicopia.corruption": " %s%.2f Corruption", "gui.unicopia.trait.label": "Element of %s", "gui.unicopia.trait.group": "\n %s", From 0c9c3caae2e9c1cadd242ac170fcb5c7ceddfaef Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 18 May 2024 19:40:59 +0100 Subject: [PATCH 15/85] Fixed unable to place palm signs on walls --- src/main/java/com/minelittlepony/unicopia/block/UBlocks.java | 4 ++-- src/main/java/com/minelittlepony/unicopia/item/UItems.java | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java b/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java index 33c5f576..521281ac 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java +++ b/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java @@ -112,9 +112,9 @@ public interface UBlocks { Block PALM_TRAPDOOR = register("palm_trapdoor", new TrapdoorBlock(Settings.create().mapColor(PALM_PLANKS.getDefaultMapColor()).instrument(Instrument.BASS).strength(3).nonOpaque().allowsSpawning(BlockConstructionUtils::never).burnable(), UWoodTypes.PALM.setType()), ItemGroups.FUNCTIONAL); Block PALM_PRESSURE_PLATE = register("palm_pressure_plate", new PressurePlateBlock(PressurePlateBlock.ActivationRule.EVERYTHING, Settings.create().mapColor(PALM_PLANKS.getDefaultMapColor()).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD).pistonBehavior(PistonBehavior.DESTROY), UWoodTypes.PALM.setType()), ItemGroups.BUILDING_BLOCKS); Block PALM_BUTTON = register("palm_button", BlockConstructionUtils.woodenButton(), ItemGroups.BUILDING_BLOCKS); - Block PALM_SIGN = register("palm_sign", new SignBlock(Settings.create().mapColor(PALM_PLANKS.getDefaultMapColor()).solid().instrument(Instrument.BASS).noCollision().strength(1).burnable().sounds(BlockSoundGroup.WOOD), UWoodTypes.PALM), ItemGroups.FUNCTIONAL); + Block PALM_SIGN = register("palm_sign", new SignBlock(Settings.create().mapColor(PALM_PLANKS.getDefaultMapColor()).solid().instrument(Instrument.BASS).noCollision().strength(1).burnable().sounds(BlockSoundGroup.WOOD), UWoodTypes.PALM)); Block PALM_WALL_SIGN = register("palm_wall_sign", new WallSignBlock(Settings.create().mapColor(PALM_PLANKS.getDefaultMapColor()).solid().instrument(Instrument.BASS).noCollision().strength(1).dropsLike(PALM_SIGN).burnable(), UWoodTypes.PALM)); - Block PALM_HANGING_SIGN = register("palm_hanging_sign", new HangingSignBlock(Settings.create().mapColor(PALM_LOG.getDefaultMapColor()).solid().instrument(Instrument.BASS).noCollision().strength(1).burnable(), UWoodTypes.PALM), ItemGroups.FUNCTIONAL); + Block PALM_HANGING_SIGN = register("palm_hanging_sign", new HangingSignBlock(Settings.create().mapColor(PALM_LOG.getDefaultMapColor()).solid().instrument(Instrument.BASS).noCollision().strength(1).burnable(), UWoodTypes.PALM)); Block PALM_WALL_HANGING_SIGN = register("palm_wall_hanging_sign", new WallHangingSignBlock(Settings.create().mapColor(PALM_LOG.getDefaultMapColor()).solid().instrument(Instrument.BASS).noCollision().strength(1.0f).burnable().dropsLike(PALM_HANGING_SIGN), UWoodTypes.PALM)); Block PALM_LEAVES = register("palm_leaves", BlockConstructionUtils.createLeavesBlock(BlockSoundGroup.GRASS), ItemGroups.BUILDING_BLOCKS); diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 689e3e3d..6b012f20 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -159,6 +159,8 @@ public interface UItems { Item PALM_BOAT = ItemGroupRegistry.register(TerraformBoatItemHelper.registerBoatItem(Unicopia.id("palm_boat"), UWoodTypes.PALM_BOAT_TYPE, false), ItemGroups.FUNCTIONAL); Item PALM_CHEST_BOAT = ItemGroupRegistry.register(TerraformBoatItemHelper.registerBoatItem(Unicopia.id("palm_chest_boat"), UWoodTypes.PALM_BOAT_TYPE, true), ItemGroups.FUNCTIONAL); + Item PALM_SIGN = register("palm_sign", new SignItem(new Item.Settings(), UBlocks.PALM_SIGN, UBlocks.PALM_WALL_SIGN), ItemGroups.FUNCTIONAL); + Item PALM_HANGING_SIGN = register("palm_hanging_sign", new HangingSignItem(UBlocks.PALM_HANGING_SIGN, UBlocks.PALM_WALL_HANGING_SIGN, new Item.Settings()), ItemGroups.FUNCTIONAL); Item SPELLBOOK = register("spellbook", new SpellbookItem(new Item.Settings().maxCount(1).rarity(Rarity.UNCOMMON)), ItemGroups.TOOLS); From c09b02d8c87b1907b2c1a5b381e348b741108935 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 18 May 2024 21:10:10 +0100 Subject: [PATCH 16/85] Fix and add farmer's delight cutting table recipes for all the palm and zap wood blocks --- .../recipe/CuttingBoardRecipeJsonBuilder.java | 146 ++++++++++++++++++ .../providers/recipe/URecipeProvider.java | 43 ++++++ .../unicopia/recipes/cutting/hay_fries.json | 2 +- 3 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/CuttingBoardRecipeJsonBuilder.java diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/CuttingBoardRecipeJsonBuilder.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/CuttingBoardRecipeJsonBuilder.java new file mode 100644 index 00000000..6aa9924d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/CuttingBoardRecipeJsonBuilder.java @@ -0,0 +1,146 @@ +package com.minelittlepony.unicopia.datagen.providers.recipe; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.spongepowered.include.com.google.common.base.Preconditions; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import net.minecraft.advancement.Advancement; +import net.minecraft.advancement.AdvancementRewards; +import net.minecraft.advancement.CriterionMerger; +import net.minecraft.advancement.criterion.CriterionConditions; +import net.minecraft.advancement.criterion.RecipeUnlockedCriterion; +import net.minecraft.data.server.recipe.CraftingRecipeJsonBuilder; +import net.minecraft.data.server.recipe.RecipeJsonProvider; +import net.minecraft.item.Item; +import net.minecraft.item.ItemConvertible; +import net.minecraft.recipe.Ingredient; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.registry.Registries; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.util.Identifier; + +public class CuttingBoardRecipeJsonBuilder { + private final Advancement.Builder advancementBuilder = Advancement.Builder.createUntelemetered(); + + private final ItemConvertible output; + private final TagKey tool; + + private final List> results = new ArrayList<>(); + private final List ingredients = new ArrayList<>(); + + public static CuttingBoardRecipeJsonBuilder create(ItemConvertible output, TagKey tool) { + return new CuttingBoardRecipeJsonBuilder(output, tool); + } + + protected CuttingBoardRecipeJsonBuilder(ItemConvertible output, TagKey tool) { + this.output = output; + this.tool = tool; + result(output); + } + + public CuttingBoardRecipeJsonBuilder input(ItemConvertible input) { + ingredients.add(Ingredient.ofItems(input)); + return this; + } + + public CuttingBoardRecipeJsonBuilder result(ItemConvertible result) { + results.add(() -> Registries.ITEM.getId(result.asItem())); + return this; + } + + public CuttingBoardRecipeJsonBuilder result(Identifier result) { + results.add(() -> result); + return this; + } + + public CuttingBoardRecipeJsonBuilder criterion(String name, CriterionConditions condition) { + advancementBuilder.criterion(name, condition); + return this; + } + + public void offerTo(Consumer exporter, Identifier id) { + id = id.withPrefixedPath("cutting/"); + Preconditions.checkState(!advancementBuilder.getCriteria().isEmpty(), "No way of obtaining recipe " + id); + advancementBuilder + .parent(CraftingRecipeJsonBuilder.ROOT) + .criterion("has_the_recipe", RecipeUnlockedCriterion.create(id)) + .rewards(AdvancementRewards.Builder.recipe(id)) + .criteriaMerger(CriterionMerger.OR); + exporter.accept(new JsonProvider(id, id.withPrefixedPath("recipes/"))); + } + + public void offerTo(Consumer exporter) { + offerTo(exporter, Registries.ITEM.getId(output.asItem())); + } + + public void offerTo(Consumer exporter, String recipePath) { + Identifier recipeId = new Identifier(recipePath); + if (recipeId.equals(Registries.ITEM.getId(output.asItem()))) { + throw new IllegalStateException("Recipe " + recipePath + " should remove its 'save' argument as it is equal to default one"); + } + offerTo(exporter, recipeId); + } + + private class JsonProvider implements RecipeJsonProvider { + private final Identifier recipeId; + private final Identifier advancementId; + public JsonProvider(Identifier recipeId, Identifier advancementId) { + this.recipeId = recipeId; + this.advancementId = advancementId; + } + + @Override + public JsonObject toJson() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("type", "farmersdelight:cutting"); + serialize(jsonObject); + return jsonObject; + } + + @Override + public void serialize(JsonObject json) { + JsonArray ingredientsJson = new JsonArray(); + for (var ingredient : ingredients) { + ingredientsJson.add(ingredient.toJson()); + } + json.add("ingredients", ingredientsJson); + JsonObject toolJson = new JsonObject(); + toolJson.addProperty("type", "farmersdelight:tool"); + toolJson.addProperty("tag", tool.id().toString()); + json.add("tool", toolJson); + JsonArray resultJson = new JsonArray(); + for (var result : results) { + JsonObject o = new JsonObject(); + o.addProperty("item", result.get().toString()); + resultJson.add(o); + } + json.add("result", resultJson); + } + + @Override + public Identifier getRecipeId() { + return recipeId; + } + + @Override + public RecipeSerializer getSerializer() { + return RecipeSerializer.SHAPELESS; + } + + @Override + public JsonObject toAdvancementJson() { + return advancementBuilder.toJson(); + } + + @Override + public Identifier getAdvancementId() { + return advancementId; + } + + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/URecipeProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/URecipeProvider.java index c6585b49..1534c7ed 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/URecipeProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/recipe/URecipeProvider.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.datagen.providers.recipe; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.stream.Stream; @@ -23,10 +24,12 @@ import com.mojang.datafixers.util.Either; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.fabricmc.fabric.api.resource.conditions.v1.DefaultResourceConditions; import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; import net.minecraft.advancement.criterion.InventoryChangedCriterion; import net.minecraft.block.Block; import net.minecraft.block.Blocks; +import net.minecraft.data.family.BlockFamily.Variant; import net.minecraft.data.server.recipe.ComplexRecipeJsonBuilder; import net.minecraft.data.server.recipe.RecipeJsonProvider; import net.minecraft.data.server.recipe.RecipeProvider; @@ -43,6 +46,7 @@ import net.minecraft.recipe.book.RecipeCategory; import net.minecraft.registry.Registries; import net.minecraft.registry.tag.ItemTags; import net.minecraft.registry.tag.TagKey; +import net.minecraft.util.Identifier; public class URecipeProvider extends FabricRecipeProvider { private static final List WOOLS = List.of(Items.BLACK_WOOL, Items.BLUE_WOOL, Items.BROWN_WOOL, Items.CYAN_WOOL, Items.GRAY_WOOL, Items.GREEN_WOOL, Items.LIGHT_BLUE_WOOL, Items.LIGHT_GRAY_WOOL, Items.LIME_WOOL, Items.MAGENTA_WOOL, Items.ORANGE_WOOL, Items.PINK_WOOL, Items.PURPLE_WOOL, Items.RED_WOOL, Items.YELLOW_WOOL, Items.WHITE_WOOL); @@ -77,6 +81,9 @@ public class URecipeProvider extends FabricRecipeProvider { .input(ConventionalItemTags.GLASS_BLOCKS) .input(UItems.SUNGLASSES).criterion("has_broken_sunglasses", conditionsFromItem(UItems.BROKEN_SUNGLASSES)) .offerTo(exporter, convertBetween(UItems.SUNGLASSES, UItems.BROKEN_SUNGLASSES)); + + // farmers delight + offerFarmersDelightCuttingRecipes(withConditions(exporter, DefaultResourceConditions.allModsLoaded("farmersdelight"))); } private void generateVanillaRecipeExtensions(Consumer exporter) { @@ -681,6 +688,42 @@ public class URecipeProvider extends FabricRecipeProvider { PatternTemplate.SEVEN_COLOR.offerTo(exporter, UItems.RAINBOW_BED_SHEETS, UItems.RAINBOW_BED_SHEETS, Items.LIGHT_BLUE_WOOL, Items.RED_WOOL, Items.ORANGE_WOOL, Items.YELLOW_WOOL, Items.BLUE_WOOL, Items.GREEN_WOOL, Items.PURPLE_WOOL); } + private void offerFarmersDelightCuttingRecipes(Consumer exporter) { + + // unwaxing + UBlockFamilies.WAXED_ZAP.getVariants().forEach((variant, waxed) -> { + if (variant == Variant.WALL_SIGN) return; + var unwaxed = UBlockFamilies.ZAP.getVariant(variant); + CuttingBoardRecipeJsonBuilder.create(unwaxed, ItemTags.AXES) + .input(waxed).criterion(hasItem(waxed), conditionsFromItem(waxed)) + .result(Items.HONEYCOMB) + .offerTo(exporter, getItemPath(unwaxed) + "_from_waxed"); + }); + List.of(UBlockFamilies.ZAP, UBlockFamilies.PALM).forEach(family -> { + family.getVariants().forEach((variant, block) -> { + if (variant == Variant.WALL_SIGN) return; + CuttingBoardRecipeJsonBuilder.create(family.getBaseBlock(), ItemTags.AXES) + .input(block).criterion(hasItem(block), conditionsFromItem(block)) + .offerTo(exporter, getItemPath(block)); + }); + }); + CuttingBoardRecipeJsonBuilder.create(UBlocks.PALM_PLANKS, ItemTags.AXES) + .input(UBlocks.PALM_HANGING_SIGN).criterion(hasItem(UBlocks.PALM_HANGING_SIGN), conditionsFromItem(UBlocks.PALM_HANGING_SIGN)) + .offerTo(exporter); + + Map.of( + UBlocks.PALM_LOG, UBlocks.STRIPPED_PALM_LOG, + UBlocks.PALM_WOOD, UBlocks.STRIPPED_PALM_WOOD, + UBlocks.ZAP_LOG, UBlocks.STRIPPED_ZAP_LOG, + UBlocks.ZAP_WOOD, UBlocks.STRIPPED_ZAP_WOOD + ).forEach((unstripped, stripped) -> { + CuttingBoardRecipeJsonBuilder.create(stripped, ItemTags.AXES) + .input(unstripped).criterion(hasItem(unstripped), conditionsFromItem(unstripped)) + .result(new Identifier("farmersdelight:tree_bark")) + .offerTo(exporter, convertBetween(stripped, unstripped)); + }); + } + public static void offerCompactingRecipe(Consumer exporter, RecipeCategory category, ItemConvertible output, ItemConvertible input, int resultCount) { offerCompactingRecipe(exporter, category, output, input, hasItem(input), resultCount); } diff --git a/src/main/resources/data/unicopia/recipes/cutting/hay_fries.json b/src/main/resources/data/unicopia/recipes/cutting/hay_fries.json index c0694f55..abb99342 100644 --- a/src/main/resources/data/unicopia/recipes/cutting/hay_fries.json +++ b/src/main/resources/data/unicopia/recipes/cutting/hay_fries.json @@ -7,7 +7,7 @@ ], "tool": { "type": "farmersdelight:tool", - "tag": "c:tools/axes" + "tag": "minecraft:axes" }, "result": [ { From 2cdce6504c7268d9323e46debe12a6b119c14ee7 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 19 May 2024 00:16:18 +0100 Subject: [PATCH 17/85] Only regenerate when the pegasus has reached the ground. Fixes #356 --- .../unicopia/entity/player/ManaContainer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java b/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java index c527430d..511e333d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java @@ -99,13 +99,13 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl energy.addPercent(-1); } - if (pony.getCompositeRace().canFly() && !pony.getPhysics().isFlying()) { - exhaustion.multiply(0.8F); + if (pony.getCompositeRace().canFly() && !pony.getPhysics().isFlying() && pony.asEntity().isOnGround()) { + exhaustion.multiply(0.99F); } else { exhaustion.addPercent(-1); } - if (!pony.getCompositeRace().canFly() || !pony.getPhysics().isFlying()) { + if (!pony.getCompositeRace().canFly() || (!pony.getPhysics().isFlying() && pony.asEntity().isOnGround())) { if (mana.getPercentFill() < 1 && mana.getShadowFill(1) <= mana.getPercentFill(1)) { mana.addPercent(MathHelper.clamp(1 + pony.getLevel().get(), 1, 50) / 4F); } From 715519e1f13c0b4d29561101a6444e2bc79a0f55 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 19 May 2024 00:17:34 +0100 Subject: [PATCH 18/85] Increase energy cost when flying over the void. Fixes #356 --- .../unicopia/entity/player/PlayerPhysics.java | 22 +++++++++++++------ .../unicopia/util/PosHelper.java | 4 ++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index 8aed9af4..5229258f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -393,7 +393,9 @@ public class PlayerPhysics extends EntityPhysics implements Tickab private void tickGrounded() { prevStrafe = 0; strafe = 0; - ticksInAir = 0; + if (entity.isOnGround()) { + ticksInAir = 0; + } wallHitCooldown = MAX_WALL_HIT_CALLDOWN; soundPlaying = false; descentRate = 0; @@ -524,9 +526,15 @@ public class PlayerPhysics extends EntityPhysics implements Tickab mana.add(MathHelper.clamp(cost, -100, 0)); - if (mana.getPercentFill() < 0.2) { - pony.getMagicalReserves().getExertion().addPercent(2); - pony.getMagicalReserves().getExhaustion().add(2 + (int)(getHorizontalMotion() * 50)); + boolean overVoid = PosHelper.isOverVoid(pony.asWorld(), pony.getOrigin(), getGravitySignum()); + + if (overVoid) { + mana.addPercent(-2); + } + + if (mana.getPercentFill() < (overVoid ? 0.4F : 0.2F)) { + pony.getMagicalReserves().getExertion().addPercent(overVoid ? 4 : 2); + pony.getMagicalReserves().getExhaustion().add((overVoid ? 4 : 0) + 2 + (int)(getHorizontalMotion() * 50)); if (mana.getPercentFill() < 0.1 && ticksInAir % 10 == 0) { float exhaustion = (0.3F * ticksInAir) / 70; @@ -537,10 +545,10 @@ public class PlayerPhysics extends EntityPhysics implements Tickab entity.addExhaustion(exhaustion); } - if (pony.getMagicalReserves().getExhaustion().get() > 99 && ticksInAir % 25 == 0) { - entity.damage(pony.damageOf(UDamageTypes.EXHAUSTION), 2); + if (pony.getMagicalReserves().getExhaustion().getPercentFill() > 0.99F && ticksInAir % 25 == 0 && !pony.isClient()) { + entity.damage(pony.damageOf(UDamageTypes.EXHAUSTION), entity.getWorld().random.nextBetween(2, 4)); - if (entity.getWorld().random.nextInt(110) == 1 && !pony.isClient()) { + if (entity.getWorld().random.nextInt(110) == 1) { pony.getLevel().add(1); if (Abilities.RAINBOOM.canUse(pony.getCompositeRace())) { pony.getMagicalReserves().getCharge().addPercent(4); diff --git a/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java b/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java index 2cb644e4..f050c796 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java +++ b/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java @@ -37,6 +37,10 @@ public interface PosHelper { return mutable.toImmutable(); } + static boolean isOverVoid(World world, BlockPos pos, int signum) { + return signum > 0 && findSolidGroundAt(world, pos, signum).getY() < world.getBottomY(); + } + static void fastAll(BlockPos origin, Consumer consumer, Direction... directions) { final BlockPos immutable = origin instanceof BlockPos.Mutable m ? m.toImmutable() : origin; final BlockPos.Mutable mutable = origin instanceof BlockPos.Mutable m ? m : origin.mutableCopy(); From 648f1838e7678c50839e64ad723ed8ff3faefc4a Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 19 May 2024 18:03:28 +0100 Subject: [PATCH 19/85] Fixed mimics rolling multiple times --- .../MixinLootableContainerBlockEntity.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLootableContainerBlockEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLootableContainerBlockEntity.java index dcf21efe..36cc4a75 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLootableContainerBlockEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLootableContainerBlockEntity.java @@ -10,6 +10,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.entity.mob.MimicEntity; +import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.entity.LockableContainerBlockEntity; import net.minecraft.block.entity.LootableContainerBlockEntity; import net.minecraft.entity.player.PlayerEntity; @@ -22,7 +23,7 @@ import net.minecraft.util.Identifier; abstract class MixinLootableContainerBlockEntity extends LockableContainerBlockEntity implements MimicEntity.MimicGeneratable { private Identifier mimicLootTable; private boolean allowMimics = true; - private boolean isMimic; + private TriState isMimic = TriState.DEFAULT; @Shadow @Nullable @@ -32,24 +33,25 @@ abstract class MixinLootableContainerBlockEntity extends LockableContainerBlockE @Inject(method = "deserializeLootTable", at = @At("HEAD")) private void deserializeMimic(NbtCompound nbt, CallbackInfoReturnable info) { - isMimic = nbt.getBoolean("mimic"); + isMimic = nbt.contains("mimic") ? TriState.of(nbt.getBoolean("mimic")) : TriState.DEFAULT; } @Inject(method = "serializeLootTable", at = @At("HEAD")) private void serializeMimic(NbtCompound nbt, CallbackInfoReturnable info) { - nbt.putBoolean("mimic", isMimic); + if (isMimic != TriState.DEFAULT) { + nbt.putBoolean("mimic", isMimic.get()); + } } @Override public void setAllowMimics(boolean allowMimics) { this.allowMimics = allowMimics; - this.isMimic &= allowMimics; markDirty(); } @Override public void setMimic(boolean mimic) { - isMimic = mimic; + isMimic = TriState.of(mimic); markDirty(); } @@ -68,10 +70,16 @@ abstract class MixinLootableContainerBlockEntity extends LockableContainerBlockE shift = Shift.AFTER ), cancellable = true) private void onCreateMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player, CallbackInfoReturnable info) { - if (player != null && (isMimic || (allowMimics && MimicEntity.shouldConvert(player.getWorld(), getPos(), player, mimicLootTable)))) { - var mimic = MimicEntity.spawnFromChest(player.getWorld(), getPos()); - if (mimic != null) { - info.setReturnValue(mimic.createScreenHandler(syncId, playerInventory, player)); + if (player != null && allowMimics) { + if (isMimic == TriState.DEFAULT) { + isMimic = TriState.of(MimicEntity.shouldConvert(player.getWorld(), getPos(), player, mimicLootTable)); + } + + if (isMimic.get()) { + var mimic = MimicEntity.spawnFromChest(player.getWorld(), getPos()); + if (mimic != null) { + info.setReturnValue(mimic.createScreenHandler(syncId, playerInventory, player)); + } } mimicLootTable = null; } From 5d4c0d0dd0effe28f8a5eeaaa233d39b6eabf462 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 19 May 2024 18:27:22 +0100 Subject: [PATCH 20/85] Set world and position on mimic chests when rendering to make sure they render correctly --- .../client/render/entity/MimicEntityRenderer.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/MimicEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/MimicEntityRenderer.java index 1195e6c1..7656c7af 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/MimicEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/MimicEntityRenderer.java @@ -1,6 +1,7 @@ package com.minelittlepony.unicopia.client.render.entity; import com.minelittlepony.unicopia.entity.mob.MimicEntity; +import com.minelittlepony.unicopia.mixin.MixinBlockEntity; import net.minecraft.block.ChestBlock; import net.minecraft.block.entity.BlockEntity; @@ -74,6 +75,8 @@ public class MimicEntityRenderer extends MobEntityRenderer Date: Sun, 19 May 2024 20:21:46 +0100 Subject: [PATCH 21/85] Configure skeletons to target flying players over players on the ground, and fire at them with more accuracy --- .../unicopia/entity/Creature.java | 5 +++ .../unicopia/entity/Living.java | 1 - .../ai/PrioritizedActiveTargetGoal.java | 35 ++++++++++++++++ .../unicopia/entity/ai/TargettingUtil.java | 40 +++++++++++++++++++ .../mixin/MixinAbstractSkeletonEntity.java | 31 ++++++++++++++ src/main/resources/unicopia.mixin.json | 1 + 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/ai/PrioritizedActiveTargetGoal.java create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/MixinAbstractSkeletonEntity.java diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index cd0277dd..40d90e32 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -17,6 +17,8 @@ import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; import com.minelittlepony.unicopia.entity.ai.EatMuffinGoal; import com.minelittlepony.unicopia.entity.ai.FleeExplosionGoal; +import com.minelittlepony.unicopia.entity.ai.PrioritizedActiveTargetGoal; +import com.minelittlepony.unicopia.entity.ai.TargettingUtil; import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; @@ -152,6 +154,9 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) { goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter)); + if (entity instanceof AbstractSkeletonEntity) { + targets.add(1, new PrioritizedActiveTargetGoal<>((MobEntity)entity, PlayerEntity.class, TargettingUtil.FLYING_PREFERRED, true)); + } } if (entity instanceof PigEntity pig) { eatMuffinGoal = new EatMuffinGoal(pig, targetter); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 95631823..7a1807db 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -98,7 +98,6 @@ public abstract class Living implements Equine, Caste private final LandingEventHandler landEvent = addTicker(new LandingEventHandler(this)); private final Enchantments enchants = addTicker(new Enchantments(this)); private final ItemTracker armour = addTicker(new ItemTracker(this)); - //private final Transportation transportation = new Transportation<>(this); private final Transportation transportation = new Transportation<>(this); protected Living(T entity, TrackedData effect) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/PrioritizedActiveTargetGoal.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/PrioritizedActiveTargetGoal.java new file mode 100644 index 00000000..67ea7796 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/PrioritizedActiveTargetGoal.java @@ -0,0 +1,35 @@ +package com.minelittlepony.unicopia.entity.ai; + +import java.util.Comparator; +import java.util.function.Predicate; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.goal.ActiveTargetGoal; +import net.minecraft.entity.mob.MobEntity; + +public class PrioritizedActiveTargetGoal extends ActiveTargetGoal { + + private final Comparator prioritySorting; + + public PrioritizedActiveTargetGoal(MobEntity mob, Class targetClass, Comparator prioritySorting, boolean checkVisibility) { + super(mob, targetClass, checkVisibility); + this.prioritySorting = prioritySorting; + } + + public PrioritizedActiveTargetGoal(MobEntity mob, Class targetClass, Comparator prioritySorting, boolean checkVisibility, Predicate targetPredicate) { + super(mob, targetClass, 10, checkVisibility, false, targetPredicate); + this.prioritySorting = prioritySorting; + } + + public PrioritizedActiveTargetGoal(MobEntity mob, Class targetClass, Comparator prioritySorting, boolean checkVisibility, boolean checkCanNavigate) { + super(mob, targetClass, 10, checkVisibility, checkCanNavigate, null); + this.prioritySorting = prioritySorting; + } + + @Override + protected void findClosestTarget() { + targetEntity = TargettingUtil.getTargets(targetClass, targetPredicate, mob, getSearchBox(getFollowRange())) + .sorted(prioritySorting.thenComparing(TargettingUtil.nearestTo(mob))) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java new file mode 100644 index 00000000..fe611c57 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java @@ -0,0 +1,40 @@ +package com.minelittlepony.unicopia.entity.ai; + +import java.util.Comparator; +import java.util.stream.Stream; + +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.TargetPredicate; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; + +public interface TargettingUtil { + Comparator FLYING_PREFERRED = Comparator.comparing(e -> Pony.of(e).getPhysics().isFlying() ? 0 : 1); + + @SuppressWarnings("unchecked") + static Stream getTargets(Class type, TargetPredicate predicate, LivingEntity subject, Box searchArea) { + if (type == PlayerEntity.class || type == ServerPlayerEntity.class) { + return (Stream)subject.getWorld().getPlayers(predicate, subject, searchArea).stream(); + } + return subject.getWorld().getTargets(type, predicate, subject, searchArea).stream(); + } + + static Comparator nearestTo(LivingEntity subject) { + Vec3d fromPos = subject.getEyePos(); + return Comparator.comparing(e -> fromPos.distanceTo(e.getPos())); + } + + static Vec3d getProjectedPos(LivingEntity entity) { + if (entity instanceof PlayerEntity player) { + Vec3d velocity = Pony.of(player).getPhysics().getClientVelocity(); + System.out.println(velocity); + return entity.getEyePos().add(velocity.multiply(1.5)).add(0, -1, 0); + } + return entity.getEyePos().add(entity.getVelocity()); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinAbstractSkeletonEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinAbstractSkeletonEntity.java new file mode 100644 index 00000000..62d7936d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinAbstractSkeletonEntity.java @@ -0,0 +1,31 @@ +package com.minelittlepony.unicopia.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +import com.minelittlepony.unicopia.entity.ai.TargettingUtil; +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.mob.AbstractSkeletonEntity; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.PersistentProjectileEntity; +import net.minecraft.util.math.Vec3d; + +@Mixin(AbstractSkeletonEntity.class) +abstract class MixinAbstractSkeletonEntity extends HostileEntity { + MixinAbstractSkeletonEntity() { super(null, null); } + + @ModifyArg(method = "attack", at = @At(value = "INVOKE", target = "net/minecraft/world/World.spawnEntity(Lnet/minecraft/entity/Entity;)Z")) + private Entity modifyAccuracy(Entity entity) { + if (entity instanceof PersistentProjectileEntity projectile && getTarget() instanceof PlayerEntity player && Pony.of(player).getPhysics().isFlying()) { + Vec3d targetPos = TargettingUtil.getProjectedPos(player) + .add(0, player.getHeight() * 0.33333F, 0) + .subtract(projectile.getPos()); + projectile.setVelocity(targetPos.x, targetPos.y + targetPos.horizontalLength() * 0.2, targetPos.z, 1.6F, (14 - getWorld().getDifficulty().getId() * 4) * 0.25F); + } + return entity; + } +} diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index ba92c81c..f09a4e9c 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -7,6 +7,7 @@ "compatibilityLevel": "JAVA_17", "mixins": [ "MixinAbstractDecorationEntity", + "MixinAbstractSkeletonEntity", "MixinBlazeEntity", "MixinBlock", "MixinBlockEntity", From a42aaeefc06f45bb8be1640c5593c8796de00740 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 19 May 2024 20:23:38 +0100 Subject: [PATCH 22/85] Only spawn specters in dark areas --- .../com/minelittlepony/unicopia/entity/mob/UEntities.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java index e3f3d9c8..3e2e28f4 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java @@ -86,13 +86,13 @@ public interface UEntities { .trackRangeChunks(8) .dimensions(EntityDimensions.fixed(3, 2))); EntityType SPECTER = register("specter", FabricEntityTypeBuilder.createMob().spawnGroup(SpawnGroup.MONSTER).entityFactory(SpecterEntity::new) - .spawnRestriction(Location.ON_GROUND, Type.MOTION_BLOCKING_NO_LEAVES, HostileEntity::canSpawnIgnoreLightLevel) + .spawnRestriction(Location.ON_GROUND, Type.MOTION_BLOCKING_NO_LEAVES, HostileEntity::canSpawnInDark) .fireImmune() .spawnableFarFromPlayer() .dimensions(EntityDimensions.fixed(1, 2))); EntityType MIMIC = register("mimic", FabricEntityTypeBuilder.create(SpawnGroup.MONSTER, MimicEntity::new) .fireImmune() - //.disableSummon() + .disableSummon() .dimensions(EntityDimensions.changing(0.875F, 0.875F))); static EntityType register(String name, FabricEntityTypeBuilder builder) { From a1ed8e53192d9cf111dee3dc9a318ce3b035a90b Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 20 May 2024 00:42:30 +0100 Subject: [PATCH 23/85] Specters can now spawn with and carry equipment --- .../unicopia/client/URenderers.java | 3 +- .../render/entity/SpecterEntityRenderer.java | 41 +++++++++++ .../unicopia/entity/mob/SpecterEntity.java | 68 ++++++++++++++++--- 3 files changed, 101 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/entity/SpecterEntityRenderer.java diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index ffb412b5..617041bd 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -56,7 +56,6 @@ import net.minecraft.client.particle.SpriteProvider; import net.minecraft.client.render.*; import net.minecraft.client.render.VertexConsumerProvider.Immediate; import net.minecraft.client.render.block.entity.BlockEntityRendererFactories; -import net.minecraft.client.render.entity.EmptyEntityRenderer; import net.minecraft.client.render.entity.FlyingItemEntityRenderer; import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.model.json.ModelTransformationMode; @@ -115,7 +114,7 @@ public interface URenderers { EntityRendererRegistry.register(UEntities.LOOT_BUG, LootBugEntityRenderer::new); EntityRendererRegistry.register(UEntities.TENTACLE, TentacleEntityRenderer::new); EntityRendererRegistry.register(UEntities.IGNOMINIOUS_BULB, IgnominiousBulbEntityRenderer::new); - EntityRendererRegistry.register(UEntities.SPECTER, EmptyEntityRenderer::new); + EntityRendererRegistry.register(UEntities.SPECTER, SpecterEntityRenderer::new); EntityRendererRegistry.register(UEntities.MIMIC, MimicEntityRenderer::new); BlockEntityRendererFactories.register(UBlockEntities.WEATHER_VANE, WeatherVaneBlockEntityRenderer::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpecterEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpecterEntityRenderer.java new file mode 100644 index 00000000..763fd887 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpecterEntityRenderer.java @@ -0,0 +1,41 @@ +package com.minelittlepony.unicopia.client.render.entity; + +import com.minelittlepony.unicopia.entity.mob.SpecterEntity; + +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.entity.BipedEntityRenderer; +import net.minecraft.client.render.entity.EntityRendererFactory.Context; +import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer; +import net.minecraft.client.render.entity.model.BipedEntityModel; +import net.minecraft.client.render.entity.model.EntityModelLayers; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.screen.PlayerScreenHandler; +import net.minecraft.util.Identifier; + +public class SpecterEntityRenderer extends BipedEntityRenderer { + + public SpecterEntityRenderer(Context context) { + super(context, new SpecterEntityModel(context.getPart(EntityModelLayers.PLAYER)), 0); + addFeature(new ArmorFeatureRenderer<>(this, + new BipedEntityModel<>(context.getPart(EntityModelLayers.PLAYER_INNER_ARMOR)), + new BipedEntityModel<>(context.getPart(EntityModelLayers.PLAYER_OUTER_ARMOR)), + context.getModelManager())); + } + + @Override + public Identifier getTexture(SpecterEntity entity) { + return PlayerScreenHandler.BLOCK_ATLAS_TEXTURE; + } + + static class SpecterEntityModel extends BipedEntityModel { + public SpecterEntityModel(ModelPart root) { + super(root); + } + + @Override + public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha) { + // noop + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpecterEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpecterEntity.java index 91f9b407..7d99db13 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpecterEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpecterEntity.java @@ -2,11 +2,15 @@ package com.minelittlepony.unicopia.entity.mob; import org.jetbrains.annotations.Nullable; +import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.particle.FootprintParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; +import net.minecraft.entity.EntityData; import net.minecraft.entity.EntityType; +import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.SpawnReason; import net.minecraft.entity.ai.goal.ActiveTargetGoal; import net.minecraft.entity.ai.goal.LookAroundGoal; import net.minecraft.entity.ai.goal.LookAtEntityGoal; @@ -19,12 +23,18 @@ import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Items; +import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.BlockStateParticleEffect; import net.minecraft.particle.ParticleTypes; import net.minecraft.registry.tag.BlockTags; import net.minecraft.sound.SoundEvent; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.Difficulty; import net.minecraft.world.GameRules; +import net.minecraft.world.LocalDifficulty; +import net.minecraft.world.ServerWorldAccess; import net.minecraft.world.World; public class SpecterEntity extends HostileEntity { @@ -44,21 +54,21 @@ public class SpecterEntity extends HostileEntity { @Override protected void initGoals() { - this.goalSelector.add(1, new SwimGoal(this)); - this.goalSelector.add(4, new MeleeAttackGoal(this, 1.0, true)); - this.goalSelector.add(5, new WanderAroundFarGoal(this, 0.8)); - this.goalSelector.add(6, new LookAtEntityGoal(this, PlayerEntity.class, 8.0f)); - this.goalSelector.add(6, new LookAroundGoal(this)); - this.targetSelector.add(1, new RevengeGoal(this)); - this.targetSelector.add(2, new TargetGoal<>(this, PlayerEntity.class)); + goalSelector.add(1, new SwimGoal(this)); + goalSelector.add(4, new MeleeAttackGoal(this, 1.0, true)); + goalSelector.add(5, new WanderAroundFarGoal(this, 0.8)); + goalSelector.add(6, new LookAtEntityGoal(this, PlayerEntity.class, 8.0f)); + goalSelector.add(6, new LookAroundGoal(this)); + targetSelector.add(1, new RevengeGoal(this)); + //this.targetSelector.add(2, new TargetGoal<>(this, PlayerEntity.class)); } - @SuppressWarnings("deprecation") @Override public void tick() { Vec3d prevPosition = getPos(); super.tick(); - if (getBrightnessAtEyes() < 0.5F || getTarget() != null) { + + if (getTarget() != null) { ParticleUtils.spawnParticles(ParticleTypes.AMBIENT_ENTITY_EFFECT, this, 6); if (getWorld().getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING)) { @@ -66,6 +76,8 @@ public class SpecterEntity extends HostileEntity { getWorld().breakBlock(getBlockPos(), true); } } + + } if (!hasVehicle() && isOnGround()) { @@ -83,6 +95,23 @@ public class SpecterEntity extends HostileEntity { } } + @Override + public void setAttacker(@Nullable LivingEntity attacker) { + if (!getWorld().isClient && attacker != null) { + getWorld().getEntitiesByClass(SpecterEntity.class, this.getBoundingBox().expand(5), e -> e != this && e.getTarget() == null).forEach(specter -> { + specter.notifyPartyAttacker(this, attacker); + }); + } + super.setAttacker(attacker); + } + + private void notifyPartyAttacker(SpecterEntity sender, @Nullable LivingEntity attacker) { + super.setAttacker(attacker); + getNavigation().stop(); + getNavigation().startMovingTo(sender, 3); + playSound(USounds.Vanilla.ENTITY_VEX_HURT, 1, 0.5F); + } + @Override public float getSoundPitch() { return super.getSoundPitch() * 0.3F; @@ -104,6 +133,27 @@ public class SpecterEntity extends HostileEntity { } + @Nullable + @Override + public EntityData initialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData data, @Nullable NbtCompound entityNbt) { + data = super.initialize(world, difficulty, spawnReason, data, entityNbt); + Random random = world.getRandom(); + float diff = difficulty.getClampedLocalDifficulty(); + setCanPickUpLoot(random.nextFloat() < 0.55F * diff); + initEquipment(random, difficulty); + return data; + } + + @Override + protected void initEquipment(Random random, LocalDifficulty localDifficulty) { + if (random.nextFloat() < (getWorld().getDifficulty() == Difficulty.HARD ? 0.05F : 0.01F)) { + if (random.nextFloat() < (getWorld().getDifficulty() == Difficulty.HARD ? 0.5F : 0.1F)) { + super.initEquipment(random, localDifficulty); + } + equipStack(EquipmentSlot.MAINHAND, (random.nextInt(3) == 0 ? Items.STONE_SWORD : Items.WOODEN_SWORD).getDefaultStack()); + } + } + static class TargetGoal extends ActiveTargetGoal { public TargetGoal(SpecterEntity specter, Class targetEntityClass) { super(specter, targetEntityClass, true); From e81967830777133a0578ee7adb5b62244777d0b6 Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 20 May 2024 00:45:04 +0100 Subject: [PATCH 24/85] Fixed fruit dropping more than they're supposed to (should only happen if you have fortune!!!) Also removed the placeholder plunder vine drops. --- .../loot/UBlockLootTableProvider.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockLootTableProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockLootTableProvider.java index 9c625a1d..c39e781c 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockLootTableProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UBlockLootTableProvider.java @@ -55,7 +55,8 @@ import net.minecraft.util.StringIdentifiable; public class UBlockLootTableProvider extends FabricBlockLootTableProvider { - private static final ConditionalLootFunction.Builder FORTUNE_BONUS = ApplyBonusLootFunction.binomialWithBonusCount(Enchantments.FORTUNE, 0.5714286F, 3); + private static final ConditionalLootFunction.Builder BASE_PRESERVING_FORTUNE_BONUS = ApplyBonusLootFunction.binomialWithBonusCount(Enchantments.FORTUNE, 0.8714286F, 0); + private static final ConditionalLootFunction.Builder CROPS_FORTUNE_BONUS = ApplyBonusLootFunction.binomialWithBonusCount(Enchantments.FORTUNE, 0.5714286F, 3); public UBlockLootTableProvider(FabricDataOutput output) { super(output); @@ -108,8 +109,8 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider { }); addDrop(UBlocks.GOLDEN_APPLE, LootTable.builder().pool(LootPool.builder() .rolls(exactly(1)) - .with(applyStateCondition(UBlocks.GOLDEN_APPLE, EnchantedFruitBlock.ENCHANTED, false, applyExplosionDecay(UBlocks.GOLDEN_APPLE, ItemEntry.builder(Items.GOLDEN_APPLE))).apply(FORTUNE_BONUS)) - .with(applyStateCondition(UBlocks.GOLDEN_APPLE, EnchantedFruitBlock.ENCHANTED, true, applyExplosionDecay(UBlocks.GOLDEN_APPLE, ItemEntry.builder(Items.ENCHANTED_GOLDEN_APPLE))).apply(FORTUNE_BONUS)) + .with(applyStateCondition(UBlocks.GOLDEN_APPLE, EnchantedFruitBlock.ENCHANTED, false, applyExplosionDecay(UBlocks.GOLDEN_APPLE, ItemEntry.builder(Items.GOLDEN_APPLE))).apply(BASE_PRESERVING_FORTUNE_BONUS)) + .with(applyStateCondition(UBlocks.GOLDEN_APPLE, EnchantedFruitBlock.ENCHANTED, true, applyExplosionDecay(UBlocks.GOLDEN_APPLE, ItemEntry.builder(Items.ENCHANTED_GOLDEN_APPLE))).apply(BASE_PRESERVING_FORTUNE_BONUS)) )); List.of(UBlocks.GREEN_APPLE_LEAVES, UBlocks.SOUR_APPLE_LEAVES, UBlocks.SWEET_APPLE_LEAVES, UBlocks.GOLDEN_OAK_LEAVES).forEach(block -> addDrop(block, this::fruitLeavesDrops)); addDrop(UBlocks.MANGO_LEAVES, block -> leavesDrops(block, UTreeGen.MANGO_TREE.sapling().get(), 0.025F, 0.027777778F, 0.03125F, 0.041666668F, 0.1F)); // same chance as jungle @@ -177,13 +178,13 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider { addDrop(UBlocks.BANANAS, LootTable.builder() .pool(addSurvivesExplosionCondition(UBlocks.BANANAS, LootPool.builder() .rolls(exactly(1)) - .with(item(UItems.BANANA, between(6, 12F)).apply(FORTUNE_BONUS)) + .with(item(UItems.BANANA, between(6, 12F)).apply(CROPS_FORTUNE_BONUS)) ))); addDrop(UBlocks.PINEAPPLE, LootTable.builder() .pool(addSurvivesExplosionCondition(UBlocks.PINEAPPLE, LootPool.builder() .rolls(exactly(1)) .with(item(UItems.PINEAPPLE, between(6, 12F)) - .apply(FORTUNE_BONUS) + .apply(BASE_PRESERVING_FORTUNE_BONUS) .conditionally(BlockStatePropertyLootCondition.builder(UBlocks.PINEAPPLE).properties(StatePredicate.Builder.create() .exactMatch(Properties.BLOCK_HALF, BlockHalf.TOP) .exactMatch(Properties.AGE_7, Properties.AGE_7_MAX)))) @@ -191,8 +192,8 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider { addDrop(UBlocks.ROCKS, applyExplosionDecay(UBlocks.ROCKS, LootTable.builder() .pool(applyStateCondition(UBlocks.ROCKS, Properties.AGE_7, Properties.AGE_7_MAX, LootPool.builder() .rolls(exactly(1)) - .with(ItemEntry.builder(UItems.WEIRD_ROCK).conditionally(RandomChanceLootCondition.builder(0.25F)).apply(FORTUNE_BONUS)) - .with(ItemEntry.builder(UItems.ROCK).apply(FORTUNE_BONUS)))) + .with(ItemEntry.builder(UItems.WEIRD_ROCK).conditionally(RandomChanceLootCondition.builder(0.25F)).apply(CROPS_FORTUNE_BONUS)) + .with(ItemEntry.builder(UItems.ROCK).apply(CROPS_FORTUNE_BONUS)))) .pool(LootPool.builder() .rolls(exactly(1)) .with(ItemEntry.builder(UItems.PEBBLES))) @@ -200,16 +201,15 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider { addDrop(UBlocks.GOLD_ROOT, applyExplosionDecay(UBlocks.GOLD_ROOT, LootTable.builder() .pool(LootPool.builder().with(ItemEntry.builder(Items.GOLDEN_CARROT))) .pool(applyStateCondition(UBlocks.GOLD_ROOT, CarrotsBlock.AGE, 7, LootPool.builder()) - .with(ItemEntry.builder(Items.GOLDEN_CARROT).apply(FORTUNE_BONUS))))); + .with(ItemEntry.builder(Items.GOLDEN_CARROT).apply(CROPS_FORTUNE_BONUS))))); + /* addDrop(UBlocks.PLUNDER_VINE, applyExplosionDecay(UBlocks.PLUNDER_VINE, LootTable.builder() - .pool(LootPool.builder().rolls(exactly(4)) + .pool(LootPool.builder().rolls(exactly(1)).conditionally(RandomChanceLootCondition.builder(0.25F)) .with(ItemEntry.builder(Items.STICK)) - .with(ItemEntry.builder(Items.DEAD_BUSH))) - .pool(LootPool.builder().rolls(exactly(1)) - .with(ItemEntry.builder(Items.STICK)) - .with(ItemEntry.builder(Items.DEAD_BUSH)) - .with(ItemEntry.builder(UItems.GRYPHON_FEATHER))) + .with(ItemEntry.builder(Items.DEAD_BUSH)) + .with(ItemEntry.builder(UItems.GRYPHON_FEATHER).conditionally(RandomChanceLootCondition.builder(0.2F)))) )); + */ // hay addDrop(UBlocks.HAY_BLOCK, b -> edibleBlockDrops(b, Items.WHEAT)); @@ -231,7 +231,7 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider { .with(ItemEntry.builder(baseCrop.getSeedsItem())))) .pool(applyStateCondition(baseCrop, baseCrop.getAgeProperty(), baseCrop.getMaxAge(), LootPool.builder() .rolls(exactly(1)) - .with(ItemEntry.builder(baseCrop.getSeedsItem()).apply(FORTUNE_BONUS))))); + .with(ItemEntry.builder(baseCrop.getSeedsItem()).apply(CROPS_FORTUNE_BONUS))))); SegmentedCropBlock stage = baseCrop; while ((stage = stage.getNext()) != null) { @@ -295,14 +295,14 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider { .rolls(exactly(1)) .with(ItemEntry.builder(shell)) .apply(ShellsBlock.COUNT.getValues(), count -> applyStateCondition(block, ShellsBlock.COUNT, count, SetCountLootFunction.builder(exactly(count)))) - .apply(FORTUNE_BONUS))); + .apply(BASE_PRESERVING_FORTUNE_BONUS))); } public LootTable.Builder fortuneBonusDrops(ItemConvertible drop) { return LootTable.builder().pool(addSurvivesExplosionCondition(drop, LootPool.builder() .rolls(exactly(1)) - .with(ItemEntry.builder(drop).apply(FORTUNE_BONUS)))); + .with(ItemEntry.builder(drop).apply(BASE_PRESERVING_FORTUNE_BONUS)))); } public static ConstantLootNumberProvider exactly(float n) { From 80b885514f3c0ae0d1f0a4557b137a44ae1aae89 Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 20 May 2024 01:49:02 +0100 Subject: [PATCH 25/85] Add broken wings status effect --- .../unicopia/client/gui/HudEffects.java | 3 +-- .../unicopia/entity/Living.java | 3 +-- .../unicopia/entity/effect/EffectUtils.java | 12 +++++++-- .../unicopia/entity/effect/UEffects.java | 1 + .../unicopia/entity/player/PlayerPhysics.java | 25 +++++++++++++++++- .../resources/assets/unicopia/lang/en_us.json | 1 + .../textures/mob_effect/broken_wings.png | Bin 0 -> 7982 bytes 7 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 src/main/resources/assets/unicopia/textures/mob_effect/broken_wings.png diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/HudEffects.java b/src/main/java/com/minelittlepony/unicopia/client/gui/HudEffects.java index 2188245d..4d0bd016 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/HudEffects.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/HudEffects.java @@ -7,7 +7,6 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.entity.duck.EntityDuck; -import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.effect.UEffects; import com.minelittlepony.unicopia.entity.player.Pony; @@ -31,7 +30,7 @@ public class HudEffects { private static void apply(Pony pony, float tickDelta, boolean on) { if (on) { - if (!pony.asEntity().hasStatusEffect(StatusEffects.HUNGER) && EffectUtils.getAmplifier(pony.asEntity(), UEffects.FOOD_POISONING) > 0) { + if (!pony.asEntity().hasStatusEffect(StatusEffects.HUNGER) && pony.asEntity().hasStatusEffect(UEffects.FOOD_POISONING)) { addedHunger = true; pony.asEntity().addStatusEffect(new StatusEffectInstance(StatusEffects.HUNGER, 1, 1, false, false)); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 7a1807db..fa8cf61d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -23,7 +23,6 @@ import com.minelittlepony.unicopia.entity.behaviour.Guest; import com.minelittlepony.unicopia.entity.damage.MagicalDamageSource; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; import com.minelittlepony.unicopia.entity.effect.CorruptInfluenceStatusEffect; -import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.effect.UEffects; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.input.Heuristic; @@ -200,7 +199,7 @@ public abstract class Living implements Equine, Caste @Override public boolean beforeUpdate() { landEvent.beforeTick(); - if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) { + if (entity.hasStatusEffect(UEffects.PARALYSIS) && entity.getVelocity().horizontalLengthSquared() > 0) { entity.setVelocity(entity.getVelocity().multiply(0, 1, 0)); updateVelocity(); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java index dff45f27..208ccf04 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java @@ -6,11 +6,19 @@ import net.minecraft.entity.effect.StatusEffectInstance; public interface EffectUtils { static boolean isPoisoned(LivingEntity entity) { - return getAmplifier(entity, UEffects.FOOD_POISONING) > 2; + return getAmplifier(entity, UEffects.FOOD_POISONING) > 1; + } + + static boolean hasABrokenWing(LivingEntity entity) { + return entity.hasStatusEffect(UEffects.BROKEN_WINGS); + } + + static boolean hasBothBrokenWing(LivingEntity entity) { + return getAmplifier(entity, UEffects.BROKEN_WINGS) > 1; } static int getAmplifier(LivingEntity entity, StatusEffect effect) { - return entity.hasStatusEffect(effect) ? entity.getStatusEffect(effect).getAmplifier() : 0; + return entity.hasStatusEffect(effect) ? entity.getStatusEffect(effect).getAmplifier() + 1 : 0; } static boolean isChangingRace(LivingEntity entity) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java index 83feb060..586a053b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java @@ -17,6 +17,7 @@ public interface UEffects { StatusEffect CORRUPT_INFLUENCE = register("corrupt_influence", new CorruptInfluenceStatusEffect(0x00FF00)); StatusEffect PARALYSIS = register("paralysis", new SimpleStatusEffect(StatusEffectCategory.HARMFUL, 0, false)); StatusEffect FORTIFICATION = register("fortification", new SimpleStatusEffect(StatusEffectCategory.BENEFICIAL, 0x000077, false)); + StatusEffect BROKEN_WINGS = register("broken_wings", new SimpleStatusEffect(StatusEffectCategory.BENEFICIAL, 0xEEAA00, false)); /** * Side-effect of wearing the alicorn amulet. * Causes the player to lose grip on whatever item they're holding. diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index 5229258f..cebc54c6 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -16,6 +16,7 @@ import com.minelittlepony.unicopia.compat.ad_astra.OxygenApi; import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar; import com.minelittlepony.unicopia.input.Heuristic; import com.minelittlepony.unicopia.item.AmuletItem; @@ -229,6 +230,10 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (wasFlying) { entity.calculateDimensions(); } + + if (!pony.isClient()) { + pony.setDirty(); + } } public double getHorizontalMotion() { @@ -285,6 +290,19 @@ public class PlayerPhysics extends EntityPhysics implements Tickab cancelFlight(false); } + if (!pony.isClient()) { + System.out.println(ticksInAir + " " + type.canFly() + " " + isFlying() + " " + EffectUtils.hasBothBrokenWing(entity)); + if (type.canFly() + && isFlying() + && EffectUtils.hasBothBrokenWing(entity) + && ticksInAir > 90) { + + entity.getWorld().playSoundFromEntity(null, entity, USounds.Vanilla.ENTITY_PLAYER_BIG_FALL, SoundCategory.PLAYERS, 2, 1F); + entity.damage(entity.getDamageSources().generic(), 3); + cancelFlight(true); + } + } + if (entity.isOnGround()) { isCancelled = false; } @@ -441,7 +459,12 @@ public class PlayerPhysics extends EntityPhysics implements Tickab entity.fallDistance = 0; - applyThrust(velocity); + if (!EffectUtils.hasABrokenWing(entity) || entity.age % 50 < 25) { + applyThrust(velocity); + } else if (entity.getWorld().random.nextInt(40) == 0) { + entity.getWorld().playSoundFromEntity(null, entity, USounds.Vanilla.ENTITY_PLAYER_BIG_FALL, SoundCategory.PLAYERS, 2, 1.5F); + entity.damage(entity.getDamageSources().generic(), 0.5F); + } if (type.isAvian()) { if (pony.getObservedSpecies() != Race.BAT && entity.getWorld().random.nextInt(9000) == 0) { diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index a6c45570..fa43ed75 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -407,6 +407,7 @@ "effect.unicopia.paralysis": "Paralysis", "effect.unicopia.butter_fingers": "Butterfingers", "effect.unicopia.fortification": "Fortification", + "effect.unicopia.broken_wings": "Broken Wings", "effect.unicopia.change_race_earth": "Earth Pony Metamorphosis", "effect.unicopia.change_race_unicorn": "Unicorn Metamorphosis", diff --git a/src/main/resources/assets/unicopia/textures/mob_effect/broken_wings.png b/src/main/resources/assets/unicopia/textures/mob_effect/broken_wings.png new file mode 100644 index 0000000000000000000000000000000000000000..f83f4b0fc89966e120d83c9822a00f6ac18ffeab GIT binary patch literal 7982 zcmeHMd0diN+kS8tZOVi)(~&4gjSx@}Wz-g>)IvqgrQA?JaRUKU($e-~nyE3(7M+SR zEmLc9NlVR|$`-R6m(m$?DlKi%G&T44Jh)Ud@Av!OzTfx$*CU7LaL#?Mb6?kep9AM{ zkE`>l8Ax3u1VJ+#9qiq}9Rn9N74R5f}=o zLu1ecHjFgI35K2G1lOlHtpIh!Nq=EwR6ePrC+jeGgu(=-13Y%Jj?;uEnDTx6(ReE~ z%W0+KN-z;j1H6qlLw1mwii)a=vYM)@s=B%wQWG^pQ$s^@-fZoeD1BXnZ}oNc^e~G| zjWF0H3-$DjsU}N^Br=(7U}R-uX=ZI|PBw!<5bEmcni`rqGiK z_DK?fsH&+WHGo0kELbT;1tmpgWhEuhy9x9| zN?OXZ7m${#Xfs)=*l3j5mY+|kEnIP-67BY|dy#pNaH~3U&Rm^&x`y8w8JjF7Q!J>K zRx~?%`pQ)fj!y0#YdyWZebxoDIoyy?UYJN6vmrK4vT@t?9XogJ-Xl#ukdk^Z?a<*P zvXiGWPiJMHIs5Cyg2JNWOC_b(uK#x9=B=vRcWQsHt8Zw0^tkD-r_Y|ZwZC}T(fO{Y z_kCagz=y#hm>0}*>Y8BoH(pwRmx7X#qLM1i3!xAT6W3BwUO-Zry_~7aiq^)OZBaw5 z`1!-@(-6%>FZCTmMhYrip#z)dXoOB0%sIwVh8;BsW;Cr8(hLs=DrgppZRPPm*rw<}lf;)l`*W!2T24>q;%FDav#{@&ni z*%y@O8eSr;i8#BD4PSE+xRYg5B z&kfG2KSmGrN|&sfNk`Xt-D&Mk^l2Z+4Hw&N>>EujD7)`3eT&<5a{kt#VnSK`ljE-W zZ}^$#P)xcY13^c*{?7$n-+1O=TZLcyK#3%>cKAv41}L|)GPiSh-Jjq1x-0|wXr~y< zq!4JrsT7SZs2@qh&9ARvu0vOvh`x<@aSz4x>06|{5smKQ2%cW>zuDyfBIm&Kai}SM zY#busOZ^8bj=bI!;*aw#d~YahIN5hMJUn4w__DVDu6|Bod;8$JCyAmPp)%=U?|FEl zPfM>Zt|CvN{EydXT#}o9iKcJr3s7iSb(4(lS58O_2=v;l@g`xP3w}6&P}d@pE>6O! zNLz9%cE%(s-v5h^@-#B`oPpku=hklmGPTi%wy+{0O4)~8l zCkE09c8}xz_?rXjUcGwhG-y^K$;j4^((%AgVzIP+%;xmDUXuYhOafmYxC3cTPTQ`LSC^SAo zdGYHi%0A4yQat=**T^iHG}kXVb>9lNHsnP*--G)4UM7J9lfx%1N_ z&qXFRaqEw*JBzYO?JK)KRvw@4lb3fT!dbV!uKiljICQZqi%PuxV;Jk}8@E+% zT79&oy}fvKqg2@jZsN>Kz`PKkeCk=x|wtoVw-PfOiW9oifH@Lt?!Bo$055M z?LGZ-Y6q=Lq%HY|E@{jzUI zwoKYT(;7q#x3}kBX^v-(TdAR~`>$)QXgZWKpO`buwXf;1@nBW?=vC6u+q~37y1!@D zY+7*<=X@f!ZGOgqT|_3G;lV7UqrB#|%U56E!}ayW-S_ibC4W@r)AH%E^EU&>F5c~0 z*Z6Xy2W}YG5uY&{my7bc5%ez6yXfGB_P@@zTpMZunc}5Y2bKyX`4Pkd5fHV(BkOjg zi$uN--sgy|(CVg$QLU(akOLlt6 znzJ6yi?#r_y|3xr!qXB4>UNeo8OucN$W*I0$3188nf69^P@Td6u)Y>+Zap8S+n#g4 zVBgR#!ey|r6g9QDlss`dX4nVzq;kEw>0I%v_spRT*{BJ9Yfmq178m{qmSpi6XT7Y$ zZpRD@f${Mw;2(Hp)wS$%cas{Q+p7SS*VHx6S^Ma52Q~0)VHrK}?4aJAvQlNBR^2$X zb16^@Oz>M9()e6y_N_y;v)U;*)3XhI>;3Q5=Lf$KsgyW%zRa@*+g=x;?C#yoX)P_` z7aD{qOnQRO)TXCD8q`o9)YyUAnEq(<2|q(oOs#v)1Mi=pN6Q*|D1UHaaec0HZ9I9g zjU68MczwtY+|gX5Xdm(H^&^$*Qh^U>noh$@5O{VVry&!(!rf1lMQs5a$I6NQ5}meI zr&o7{UZu}_FUR#xzFBKtyuKeL1vpviz29Uw$G;Q<8AN&uKJ&IkmftMV9Sx~!e|01; zuf%Ea?V@ogEueqkWem_Oz!b(-P4q5c24r5-JMGcY6X2ScEIW&y+rJa+WH{XvAc}{R z^=bEA#;_Dzzc8jxO#V&&h>N@r6~C0&Z_CXDD??`D7_xYaQNtS^5Dg(+t$|)G5mL#8l6a^ zhcQ<-NwnTv*($}E%1G^4kdPoX>txI}_3J4(FkQ|EjWL6ad!Xrj=;|g^T2aphkk$`f z9u4m6Yyp|Gt{~+c-$b}ic9_1ZU}2L)-v(XX=;(7_FN@-oaIg+{R3>ej)kfp}{=7WP z(f7}UALs%*^xX%&CeI{Sp-G-H1)`d~ccaIADNUF;Fq=p06S8pIbX%NyA-{ z6^}!{i5)d#4DijG5zv(Q$4FwU0mZ9vZ8g)Mp*H}=#8w;|QM`JcRkj0c_6N)9`I(`z zqWCwF!YNJ5)Lq{X#3^gb z3>4F0Is6;Kw_aRW?R78OV5D?#Y#Y2c1%4LezsDS2eodE-biG2B*XXB>iqcvN^J|Bj zt2bDgI5%1~f$_vw0Og;*y#9l>rQ?qwr#;Q!aD>>-v$Jz`w6ntqgnTY9f&)Qu>6?DG zak%b^+Tr5<0~W3N{ccP9Z08LZus;DjZwc6jQq@gGuU=q97)uBt3-ZLJBaue{;o zrRueO)(9ecgTPJv^X#tGNPJL2cbvhCGSQ_0+hw7ihq--=AVzWZn#CsVJvl*LxD~r0 z9Xns{L6VUp??YaGywV5B+-E*xU1PqAVUcw~F3ct-sFSZP?r-e7( z{$6wL`&3Te@88mqKX`9d(n5A-A4kq7(PG?|uwUACJTr(Mon3+wuDx1yAxW29m1i(A zb8}6@;+t7lP6=kKm08}uW%=N;MuF~6y_;TJ=4xX;X!>^OC+4c(+nn6;GW6lXK*9V= zm)?fn`BqS(sJV3BuO^q>_7}M>QRoVJ&yWPZobxiEx4ohKR)^yLOrK1C(l)z5nf>Ee zwwnfGYTi7dz8M^aa&HRDN!aWha2}51d3cMx8Ea_4{76$4n;*n6jf)h>&kxp1;{>eW zaE=%g#0lX=*iniEz&xU1^^;C zViqPYG9pSui?hMXacQ6qHxsZJxrsR32I~#Zx^{da2SYX`n-cN#INk;`tSu5_Eo5_P zZuToDA;2daY^Yc)pb-eMv9YGH=B9jM2!Ui}Wkn#G5zNf+zydFlM2T5(_$bjr7-9m$ zo+Ant@&sZYKMDh5vV!gcm80j{;(UW+~=zKZ^C4Z*Y&C&Zmxm;nTRESx<478v`o_gJ#bUj)C2C zw70>+^V8V;U>=($uad2(R4WTM1@Q?qU|KCW%V2AX!i- zmgW>QE3(-qqdhr75y(UsQ~rEMJ{%4U4UhrCvfw-g0P=Rgg=Qz@u*7_!2cI8dgPndd zG~LYr%Zberv+P-74gj5gR^&1DtOy4x#0dvrI0m21<4XQFYk2WstbsiUxdTrG=9kEu zCRUU?Cwk)3#K#Dpd?{ft@Y`j1~xCS7ZRp7 z!%5A6zyHl^G8X^MDKMC?lYEiBU*-BL*B2@9MaEyV>#JN}q`(&$f6cD{H@T1>k5il| z@GB@59F~%945xylmP*j-RrXLb^c&PPaI>2QTGRy&J|YOx(1r^FI+Csf8db%P47%z| zWfWwD^IAZy1^<;ZavJUzU8ek+Yy)yl{tB_}O? z`Zy_n_sY=)2mKZtv%bM&CNd=jXQl=UdN3`F1dRk(c)0ZnfxA z^EGN~*Iwo$Fx4uGy5n!%l^y9RRcjsNtl1lpy-16bnjQM;(T%R2^s25KXN2)#kyW!* zP_LgN7%L407yhU%sLOr3<;+;q;!E5gA8(p#zw@{4y-Qe+mppI?XJ20_sFw6^Qt8~6 zG;|WVr#A3%vW`w#%PBWgC`My=t%F*1$*r<-Rnr{pmTDdo;nVA|+|91&*S&cpMwU&2 zR*dGH^g-+M9*^A Date: Mon, 20 May 2024 16:02:52 +0100 Subject: [PATCH 26/85] Move server-affecting mixins to their own package --- .../mixin/MixinChunkBlockLightProvider.java | 10 ---------- .../{ => server}/MixinPlayerManager.java | 2 +- .../MixinServerPlayNetworkHandler.java | 2 +- .../{ => server}/MixinServerPlayerEntity.java | 2 +- .../mixin/{ => server}/MixinServerWorld.java | 14 +------------ .../mixin/server/MixinSleepManager.java | 20 +++++++++++++++++++ src/main/resources/unicopia.mixin.json | 10 +++++----- 7 files changed, 29 insertions(+), 31 deletions(-) rename src/main/java/com/minelittlepony/unicopia/mixin/{ => server}/MixinPlayerManager.java (97%) rename src/main/java/com/minelittlepony/unicopia/mixin/{ => server}/MixinServerPlayNetworkHandler.java (97%) rename src/main/java/com/minelittlepony/unicopia/mixin/{ => server}/MixinServerPlayerEntity.java (98%) rename src/main/java/com/minelittlepony/unicopia/mixin/{ => server}/MixinServerWorld.java (77%) create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/server/MixinSleepManager.java diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinChunkBlockLightProvider.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinChunkBlockLightProvider.java index db7ec5cf..e8a40cfb 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinChunkBlockLightProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinChunkBlockLightProvider.java @@ -37,16 +37,6 @@ abstract class MixinChunkBlockLightProvider extends ChunkLightProvider { } } - /* - @Inject(method = "getLightSourceLuminance", at = @At("RETURN"), cancellable = true) - private void onGetLightSourceLuminance(long blockPos, BlockState blockState, CallbackInfoReturnable info) { - int x = ChunkSectionPos.getSectionCoord(BlockPos.unpackLongX(blockPos)); - int z = ChunkSectionPos.getSectionCoord(BlockPos.unpackLongZ(blockPos)); - if (chunkProvider.getChunk(x, z) instanceof WorldChunk chunk) { - info.setReturnValue(Math.max(info.getReturnValue(), LightSources.get(chunk.getWorld()).getLuminance(blockPos))); - } - }*/ - @Inject(method = "method_51529", at = @At("TAIL")) private void onMethod_51529(long blockPos, CallbackInfo info) { long sectionPos = ChunkSectionPos.fromBlockPos(blockPos); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerManager.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPlayerManager.java similarity index 97% rename from src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerManager.java rename to src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPlayerManager.java index ce8be7b9..0c845c1c 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPlayerManager.java @@ -1,4 +1,4 @@ -package com.minelittlepony.unicopia.mixin; +package com.minelittlepony.unicopia.mixin.server; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinServerPlayNetworkHandler.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java similarity index 97% rename from src/main/java/com/minelittlepony/unicopia/mixin/MixinServerPlayNetworkHandler.java rename to src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java index 9ec1f042..c6580d88 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinServerPlayNetworkHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java @@ -1,4 +1,4 @@ -package com.minelittlepony.unicopia.mixin; +package com.minelittlepony.unicopia.mixin.server; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinServerPlayerEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayerEntity.java similarity index 98% rename from src/main/java/com/minelittlepony/unicopia/mixin/MixinServerPlayerEntity.java rename to src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayerEntity.java index 17bb934d..2ae21fe5 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinServerPlayerEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayerEntity.java @@ -1,4 +1,4 @@ -package com.minelittlepony.unicopia.mixin; +package com.minelittlepony.unicopia.mixin.server; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinServerWorld.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerWorld.java similarity index 77% rename from src/main/java/com/minelittlepony/unicopia/mixin/MixinServerWorld.java rename to src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerWorld.java index 019d5cbd..b24c24ae 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinServerWorld.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerWorld.java @@ -1,6 +1,5 @@ -package com.minelittlepony.unicopia.mixin; +package com.minelittlepony.unicopia.mixin.server; -import java.util.List; import java.util.function.BooleanSupplier; import org.spongepowered.asm.mixin.Mixin; @@ -8,16 +7,13 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Constant; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyConstant; -import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.server.world.NocturnalSleepManager; import net.minecraft.block.BlockState; -import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; -import net.minecraft.server.world.SleepManager; import net.minecraft.util.math.BlockPos; import net.minecraft.world.StructureWorldAccess; import net.minecraft.world.World; @@ -57,11 +53,3 @@ abstract class MixinServerWorld extends World implements StructureWorldAccess, N getNocturnalSleepManager().skipTime(); } } - -@Mixin(SleepManager.class) -abstract class MixinSleepManager { - @ModifyVariable(method = "update(Ljava/util/List;)Z", at = @At("HEAD")) - public List modifyPlayers(List players) { - return players.size() <= 0 ? players : ((NocturnalSleepManager.Source)players.get(0).getWorld()).getNocturnalSleepManager().filterPlayers(players); - } -} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinSleepManager.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinSleepManager.java new file mode 100644 index 00000000..76c18b65 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinSleepManager.java @@ -0,0 +1,20 @@ +package com.minelittlepony.unicopia.mixin.server; + +import java.util.List; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import com.minelittlepony.unicopia.server.world.NocturnalSleepManager; + +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.SleepManager; + +@Mixin(SleepManager.class) +abstract class MixinSleepManager { + @ModifyVariable(method = "update(Ljava/util/List;)Z", at = @At("HEAD")) + public List modifyPlayers(List players) { + return players.size() <= 0 ? players : ((NocturnalSleepManager.Source)players.get(0).getWorld()).getNocturnalSleepManager().filterPlayers(players); + } +} diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index f09a4e9c..5de80517 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -37,15 +37,10 @@ "MixinPersistentProjectileEntity", "MixinPlayerEntity", "MixinPlayerInventory", - "MixinPlayerManager", "MixinPointOfInterestType", "MixinPowderSnowBlock", "MixinProjectileEntity", "MixinPufferfishEntity", - "MixinServerPlayerEntity", - "MixinServerPlayNetworkHandler", - "MixinServerWorld", - "MixinSleepManager", "MixinSheepEntity", "MixinShulkerEntity", "MixinStateManager", @@ -56,6 +51,11 @@ "MixinWardenEntity", "MixinWorld", "PointOfInterestTypesAccessor", + "server.MixinPlayerManager", + "server.MixinServerPlayerEntity", + "server.MixinServerPlayNetworkHandler", + "server.MixinServerWorld", + "server.MixinSleepManager", "gravity.MixinBrain", "gravity.MixinEntity", "gravity.MixinLivingEntity", From 1f2df6daf5ead36dffca1476d2da3ec4d7d1a30f Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 21 May 2024 22:47:21 +0100 Subject: [PATCH 27/85] Fix: Fix casting # Conflicts: # src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java # Conflicts: # src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java --- .../unicopia/ability/UnicornCastingAbility.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index d47f098d..44edde82 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -107,8 +107,8 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility { } } - boolean hasExact = player.getSpellSlot().contains(spell); - boolean removed = !spell.isStackable() && player.getSpellSlot().removeWhere(s -> s.findMatches(spell.type()).findAny().isPresent(), true); + boolean hasExact = !spell.isStackable() && player.getSpellSlot().contains(s -> !s.getTypeAndTraits().isStackable() && spell.test(s)); + boolean removed = !spell.isStackable() && player.getSpellSlot().removeWhere(s -> !s.getTypeAndTraits().isStackable() && s.findMatches(spell.type()).findAny().isPresent(), true); player.subtractEnergyCost(removed ? 2 : 4); if (!hasExact && !spell.isEmpty()) { Spell s = spell.apply(player, CastingMethod.DIRECT); From d38a02dcd47bdb998e82e1b2293086fe6211d635 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 21 May 2024 21:22:43 +0100 Subject: [PATCH 28/85] Fix: Fix reference losing traits when serializing --- .../unicopia/ability/magic/spell/SpellReference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java index 97152693..c222de90 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java @@ -44,7 +44,7 @@ public final class SpellReference implements NbtSerialisable { public void toNBT(NbtCompound compound) { if (spell != null && !spell.isDead()) { spell.toNBT(compound); - spell.getTypeAndTraits().type().toNbt(compound); + spell.getTypeAndTraits().toNbt(compound); } } From 9f407dfb76136bb15ed3a395ee7bdeff86f6e48f Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 21 May 2024 21:27:18 +0100 Subject: [PATCH 29/85] Revert "Change ether to use type keys" This reverts commit 2ca337a8b813e2bf4fe3bd4949338aa476c568e4. --- .../minelittlepony/unicopia/server/world/Ether.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index 1dd46a92..73ffa38d 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -25,7 +25,7 @@ public class Ether extends PersistentState { return WorldOverlay.getPersistableStorage(world, ID, Ether::new, Ether::new); } - private final Map, Map>>> endpoints; + private final Map>>> endpoints; private final Object locker = new Object(); @@ -33,7 +33,7 @@ public class Ether extends PersistentState { Ether(World world, NbtCompound compound) { this.world = world; - this.endpoints = NbtSerialisable.readMap(compound.getCompound("endpoints"), id -> SpellType.getKey(Identifier.tryParse(id)), typeNbt -> { + this.endpoints = NbtSerialisable.readMap(compound.getCompound("endpoints"), Identifier::tryParse, typeNbt -> { return NbtSerialisable.readMap((NbtCompound)typeNbt, UUID::fromString, entityNbt -> { return NbtSerialisable.readMap((NbtCompound)entityNbt, UUID::fromString, Entry::new); }); @@ -49,7 +49,7 @@ public class Ether extends PersistentState { public NbtCompound writeNbt(NbtCompound compound) { synchronized (locker) { pruneNodes(); - compound.put("endpoints", NbtSerialisable.writeMap(endpoints, type -> type.getId().toString(), entities -> { + compound.put("endpoints", NbtSerialisable.writeMap(endpoints, Identifier::toString, entities -> { return NbtSerialisable.writeMap(entities, UUID::toString, spells -> { return NbtSerialisable.writeMap(spells, UUID::toString, Entry::toNBT); }); @@ -62,7 +62,7 @@ public class Ether extends PersistentState { public Entry getOrCreate(T spell, Caster caster) { synchronized (locker) { Entry entry = (Entry)endpoints - .computeIfAbsent(spell.getTypeAndTraits().type(), typeId -> new HashMap<>()) + .computeIfAbsent(spell.getTypeAndTraits().type().getId(), typeId -> new HashMap<>()) .computeIfAbsent(caster.asEntity().getUuid(), entityId -> new HashMap<>()) .computeIfAbsent(spell.getUuid(), spellid -> { markDirty(); @@ -82,7 +82,7 @@ public class Ether extends PersistentState { public void remove(SpellType spellType, UUID entityId) { synchronized (locker) { - endpoints.computeIfPresent(spellType, (typeId, entries) -> { + endpoints.computeIfPresent(spellType.getId(), (typeId, entries) -> { if (entries.remove(entityId) != null) { markDirty(); } From f8f60a8d3dc48364968ebeb0d4726104d41249e1 Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 20 May 2024 20:56:44 +0100 Subject: [PATCH 30/85] Implement custom data tracker --- .../com/minelittlepony/unicopia/Race.java | 2 + .../ability/magic/SpellPredicate.java | 2 +- .../client/render/spell/AllSpells.java | 8 - .../spell/SpellEffectsRenderDispatcher.java | 3 +- .../unicopia/entity/Creature.java | 56 ++++--- .../unicopia/entity/EntityPhysics.java | 19 ++- .../unicopia/entity/ItemImpl.java | 37 ++--- .../unicopia/entity/ItemPhysics.java | 6 +- .../unicopia/entity/Living.java | 33 ++-- .../unicopia/entity/mob/CastSpellEntity.java | 4 +- .../unicopia/entity/player/Acrobatics.java | 31 ++-- .../unicopia/entity/player/ManaContainer.java | 44 +++--- .../entity/player/PlayerLevelStore.java | 16 +- .../unicopia/entity/player/PlayerPhysics.java | 5 +- .../unicopia/entity/player/Pony.java | 55 +++---- .../unicopia/mixin/MixinEntity.java | 23 ++- .../unicopia/network/Channel.java | 2 + .../unicopia/network/track/DataTracker.java | 143 ++++++++++++++++++ .../network/track/DataTrackerManager.java | 83 ++++++++++ .../network/track/MsgTrackedValues.java | 46 ++++++ .../unicopia/network/track/Trackable.java | 12 ++ .../network/track/TrackableDataType.java | 38 +++++ .../unicopia/projectile/MagicBeamEntity.java | 9 +- .../util/serialization/PacketCodec.java | 11 ++ 24 files changed, 512 insertions(+), 176 deletions(-) delete mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/spell/AllSpells.java create mode 100644 src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java create mode 100644 src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java create mode 100644 src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java create mode 100644 src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java create mode 100644 src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java diff --git a/src/main/java/com/minelittlepony/unicopia/Race.java b/src/main/java/com/minelittlepony/unicopia/Race.java index 90644373..2380c241 100644 --- a/src/main/java/com/minelittlepony/unicopia/Race.java +++ b/src/main/java/com/minelittlepony/unicopia/Race.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Ability; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.util.RegistryUtils; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; @@ -44,6 +45,7 @@ public record Race ( public static final String DEFAULT_ID = "unicopia:unset"; public static final Registry REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID); public static final Registry COMMAND_REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race/grantable"), DEFAULT_ID); + public static final PacketCodec PACKET_CODEC = PacketCodec.ofRegistry(REGISTRY); public static final RegistryKey> REGISTRY_KEY = REGISTRY.getKey(); private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("commands.race.fail", id)); private static final Function COMPOSITES = Util.memoize(race -> new Composite(race, null, null)); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java index 3a7213c7..358c4fb6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java @@ -7,10 +7,10 @@ import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.effect.MimicSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.ShieldSpell; - import net.minecraft.entity.Entity; public interface SpellPredicate extends Predicate { + SpellPredicate ALL = spell -> true; SpellPredicate CAN_SUPPRESS = s -> s instanceof IllusionarySpell; SpellPredicate IS_PLACED = s -> s instanceof PlaceableSpell; SpellPredicate IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/AllSpells.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/AllSpells.java deleted file mode 100644 index c6c5c2ff..00000000 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/AllSpells.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.minelittlepony.unicopia.client.render.spell; - -import com.minelittlepony.unicopia.ability.magic.SpellPredicate; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; - -public interface AllSpells extends SpellPredicate { - AllSpells INSTANCE = spell -> true; -} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index 90bfbbb2..4c78034a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.Living; @@ -124,7 +125,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader caster.asEntity().getDisplayName().copy().append(" (" + Registries.ENTITY_TYPE.getId(caster.asEntity().getType()) + ")"), caster.getMaster() != null ? Text.literal("Master: ").append(caster.getMaster().getDisplayName()) : Text.empty() ), - caster.getSpellSlot().stream(AllSpells.INSTANCE, false).flatMap(spell -> + caster.getSpellSlot().stream(SpellPredicate.ALL, false).flatMap(spell -> Stream.of( Text.literal("UUID: " + spell.getUuid()), Text.literal("|>Type: ").append(Text.literal(spell.getTypeAndTraits().type().getId().toString()).styled(s -> s.withColor(spell.getTypeAndTraits().type().getColor()))), diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index 40d90e32..46453917 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -21,6 +21,9 @@ import com.minelittlepony.unicopia.entity.ai.PrioritizedActiveTargetGoal; import com.minelittlepony.unicopia.entity.ai.TargettingUtil; import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; @@ -28,7 +31,6 @@ import net.minecraft.entity.SpawnGroup; import net.minecraft.entity.ai.goal.*; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.EntityAttributes; -import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.mob.*; @@ -39,13 +41,7 @@ import net.minecraft.nbt.NbtElement; import net.minecraft.util.math.MathHelper; public class Creature extends Living implements WeaklyOwned.Mutable { - private static final TrackedData EFFECT = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); - private static final TrackedData MASTER = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); - public static final TrackedData GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT); - private static final TrackedData EATING = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.INTEGER); - private static final TrackedData DISCORDED = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN); - private static final TrackedData SMITTEN = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN); - + static final TrackedData EFFECT = net.minecraft.entity.data.DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); public static void boostrap() {} private final EntityPhysics physics; @@ -69,26 +65,27 @@ public class Creature extends Living implements WeaklyOwned.Mutabl .isEmpty(); }); + protected final DataTracker.Entry master; + protected final DataTracker.Entry eating; + protected final DataTracker.Entry discorded; + protected final DataTracker.Entry smitten; + public Creature(LivingEntity entity) { - super(entity, EFFECT); - physics = new EntityPhysics<>(entity, GRAVITY); + super(entity); + physics = new EntityPhysics<>(entity, tracker); addTicker(physics); addTicker(this::updateConsumption); - } - @Override - public void initDataTracker() { - super.initDataTracker(); - entity.getDataTracker().startTracking(MASTER, owner.toNBT()); - entity.getDataTracker().startTracking(EATING, 0); - entity.getDataTracker().startTracking(DISCORDED, false); - entity.getDataTracker().startTracking(SMITTEN, false); + master = tracker.startTracking(TrackableDataType.of(PacketCodec.NBT), owner.toNBT()); + eating = tracker.startTracking(TrackableDataType.of(PacketCodec.INT), 0); + discorded = tracker.startTracking(TrackableDataType.of(PacketCodec.BOOLEAN), false); + smitten = tracker.startTracking(TrackableDataType.of(PacketCodec.BOOLEAN), false); } @Override public void setMaster(LivingEntity owner) { this.owner.set(owner); - entity.getDataTracker().set(MASTER, this.owner.toNBT()); + tracker.set(master, this.owner.toNBT()); if (owner != null) { targets.ifPresent(this::initMinionAi); } @@ -99,20 +96,20 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } public boolean isDiscorded() { - return entity.getDataTracker().get(DISCORDED); + return tracker.get(this.discorded); } public boolean isSmitten() { - return entity.getDataTracker().get(SMITTEN); + return tracker.get(this.smitten); } public void setSmitten(boolean smitten) { smittenTicks = smitten ? 20 : 0; - entity.getDataTracker().set(SMITTEN, smitten); + tracker.set(this.smitten, smitten); } public void setDiscorded(boolean discorded) { - entity.getDataTracker().set(DISCORDED, discorded); + tracker.set(this.discorded, discorded); discordedChanged = true; } @@ -124,9 +121,8 @@ public class Creature extends Living implements WeaklyOwned.Mutabl @Override public EntityReference getMasterReference() { - if (entity.getDataTracker().containsKey(MASTER)) { - NbtCompound data = entity.getDataTracker().get(MASTER); - owner.fromNBT(data); + if (master != null) { + owner.fromNBT(tracker.get(master)); } return owner; } @@ -239,10 +235,10 @@ public class Creature extends Living implements WeaklyOwned.Mutabl private void updateConsumption() { if (isClient()) { - eatTimer = entity.getDataTracker().get(EATING); + eatTimer = tracker.get(eating); } else if (eatMuffinGoal != null) { eatTimer = eatMuffinGoal.getTimer(); - entity.getDataTracker().set(EATING, eatTimer); + tracker.set(eating, eatTimer); } } @@ -331,8 +327,8 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } if (compound.contains("master", NbtElement.COMPOUND_TYPE)) { owner.fromNBT(compound.getCompound("master")); - if (entity.getDataTracker().containsKey(MASTER)) { - entity.getDataTracker().set(MASTER, owner.toNBT()); + if (master != null) { + tracker.set(master, owner.toNBT()); } if (owner.isSet()) { targets.ifPresent(this::initMinionAi); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java index 749ee3cf..2aba94c8 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java @@ -1,14 +1,16 @@ package com.minelittlepony.unicopia.entity; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.Tickable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import net.minecraft.block.BlockState; import net.minecraft.block.FenceGateBlock; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.mob.MobEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.registry.tag.BlockTags; @@ -18,15 +20,18 @@ import net.minecraft.util.math.Vec3d; public class EntityPhysics implements Physics, Copyable>, Tickable { - private final TrackedData gravity; - protected final T entity; private float lastGravity = 1; - public EntityPhysics(T entity, TrackedData gravity) { + private final DataTracker tracker; + protected final DataTracker.Entry gravity; + + public EntityPhysics(T entity, DataTracker tracker) { this.entity = entity; - this.gravity = gravity; + this.tracker = tracker; + //this.gravity = gravity; + gravity = tracker.startTracking(TrackableDataType.of(PacketCodec.FLOAT), 1F); } @Override @@ -91,12 +96,12 @@ public class EntityPhysics implements Physics, Copyable { - private static final TrackedData ITEM_RACE = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.STRING); - static final TrackedData ITEM_GRAVITY = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.FLOAT); - private final ItemEntity entity; private final ItemPhysics physics; - private Race serverRace; + private final DataTrackerManager trackers; + protected final DataTracker tracker; + + private final DataTracker.Entry race; public ItemImpl(ItemEntity owner) { this.entity = owner; - this.physics = new ItemPhysics(owner); + this.trackers = Trackable.of(entity).getDataTrackers(); + this.tracker = trackers.getPrimaryTracker(); + this.physics = new ItemPhysics(owner, tracker); + + race = tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); } @Override public void initDataTracker() { - entity.getDataTracker().startTracking(ITEM_GRAVITY, 1F); - entity.getDataTracker().startTracking(ITEM_RACE, Race.REGISTRY.getId(Race.HUMAN).toString()); } @Override @@ -58,13 +60,6 @@ public class ItemImpl implements Equine { public boolean beforeUpdate() { if (!entity.getWorld().isClient) { - Race race = getSpecies(); - if (race != serverRace) { - serverRace = race; - setSpecies(Race.HUMAN); - setSpecies(race); - } - if (WantItNeedItEnchantment.getLevel(entity) > 0) { var random = entity.getWorld().random; @@ -150,12 +145,12 @@ public class ItemImpl implements Equine { @Override public Race getSpecies() { - return Race.fromName(entity.getDataTracker().get(ITEM_RACE), Race.HUMAN); + return tracker.get(race); } @Override public void setSpecies(Race race) { - entity.getDataTracker().set(ITEM_RACE, Race.REGISTRY.getId(race).toString()); + tracker.set(this.race, race); } @Override @@ -165,7 +160,7 @@ public class ItemImpl implements Equine { @Override public void toNBT(NbtCompound compound) { - compound.putString("owner_race", Race.REGISTRY.getId(getSpecies()).toString()); + compound.putString("owner_race", getSpecies().getId().toString()); physics.toNBT(compound); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java index b747dd0a..04b5425d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java @@ -1,10 +1,12 @@ package com.minelittlepony.unicopia.entity; +import com.minelittlepony.unicopia.network.track.DataTracker; + import net.minecraft.entity.ItemEntity; class ItemPhysics extends EntityPhysics { - public ItemPhysics(ItemEntity entity) { - super(entity, ItemImpl.ITEM_GRAVITY); + public ItemPhysics(ItemEntity entity, DataTracker tracker) { + super(entity, tracker); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index fa8cf61d..407608f1 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -32,10 +32,15 @@ import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.network.datasync.EffectSync; import com.minelittlepony.unicopia.network.datasync.Transmittable; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.DataTrackerManager; +import com.minelittlepony.unicopia.network.track.Trackable; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.projectile.ProjectileImpactListener; import com.minelittlepony.unicopia.server.world.DragonBreathStore; import com.minelittlepony.unicopia.util.*; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; import net.fabricmc.fabric.api.util.TriState; @@ -48,7 +53,6 @@ import net.minecraft.entity.attribute.EntityAttributeInstance; import net.minecraft.entity.attribute.EntityAttributeModifier; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageTypes; -import net.minecraft.entity.data.*; import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.ProjectileEntity; @@ -64,6 +68,7 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.util.Hand; +import net.minecraft.util.Util; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -71,7 +76,7 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public abstract class Living implements Equine, Caster, Transmittable { - private static final TrackedData> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID); + //private static final TrackedData> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID); protected final T entity; @@ -99,19 +104,26 @@ public abstract class Living implements Equine, Caste private final ItemTracker armour = addTicker(new ItemTracker(this)); private final Transportation transportation = new Transportation<>(this); - protected Living(T entity, TrackedData effect) { + private final DataTrackerManager trackers; + protected final DataTracker tracker; + + protected final DataTracker.Entry carrierId; + + protected Living(T entity) { this.entity = entity; - this.effectDelegate = new EffectSync(this, effect); + this.trackers = Trackable.of(entity).getDataTrackers(); + this.tracker = trackers.getPrimaryTracker(); + this.effectDelegate = new EffectSync(this, Creature.EFFECT); this.sneakingHeuristic = addTicker(new Interactable(entity::isSneaking)); this.landedHeuristic = addTicker(new Interactable(entity::isOnGround)); this.jumpingHeuristic = addTicker(new Interactable(((LivingEntityDuck)entity)::isJumping)); + + carrierId = tracker.startTracking(TrackableDataType.of(PacketCodec.UUID), Util.NIL_UUID); } @Override public void initDataTracker() { - effectDelegate.initDataTracker(); - entity.getDataTracker().startTracking(Creature.GRAVITY, 1F); - entity.getDataTracker().startTracking(CARRIER_ID, Optional.empty()); + entity.getDataTracker().startTracking(Creature.EFFECT, new NbtCompound()); } public Q addTicker(Q tickable) { @@ -166,15 +178,16 @@ public abstract class Living implements Equine, Caste } public Optional getCarrierId() { - return entity.getDataTracker().get(CARRIER_ID); + UUID carrierId = tracker.get(this.carrierId); + return carrierId == Util.NIL_UUID ? Optional.empty() : Optional.of(carrierId); } public void setCarrier(UUID carrier) { - entity.getDataTracker().set(CARRIER_ID, Optional.ofNullable(carrier)); + tracker.set(this.carrierId, carrier == null ? Util.NIL_UUID : carrier); } public void setCarrier(Entity carrier) { - entity.getDataTracker().set(CARRIER_ID, Optional.ofNullable(carrier).map(Entity::getUuid)); + setCarrier(carrier == null ? Util.NIL_UUID : carrier.getUuid()); } @Nullable diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 92b1a909..649bb5d5 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.network.datasync.EffectSync; +import com.minelittlepony.unicopia.network.track.Trackable; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityDimensions; @@ -26,10 +27,9 @@ import net.minecraft.text.Text; import net.minecraft.world.World; public class CastSpellEntity extends LightEmittingEntity implements Caster, WeaklyOwned.Mutable, MagicImmune { - private static final TrackedData GRAVITY = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.FLOAT); private static final TrackedData EFFECT = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); - private final EntityPhysics physics = new EntityPhysics<>(this, GRAVITY); + private final EntityPhysics physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); private final EffectSync effectDelegate = new EffectSync(this, EFFECT); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java index 37009bb5..75fadc1c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java @@ -8,15 +8,15 @@ import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; import com.minelittlepony.unicopia.entity.mob.StormCloudEntity; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.SideShapeType; -import net.minecraft.entity.data.DataTracker; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.registry.tag.BlockTags; @@ -28,8 +28,6 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Acrobatics implements Tickable, NbtSerialisable { - static final TrackedData> HANGING_POSITION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS); - private int ticksHanging; private Direction attachDirection; @@ -38,14 +36,15 @@ public class Acrobatics implements Tickable, NbtSerialisable { private final Pony pony; private final PlayerEntity entity; - public Acrobatics(Pony pony) { - this.pony = pony; - this.entity = pony.asEntity(); - pony.addTicker(this::checkDislodge); - } + private final DataTracker tracker; + private final DataTracker.Entry> hangingPos; - public void initDataTracker() { - entity.getDataTracker().startTracking(HANGING_POSITION, Optional.empty()); + public Acrobatics(Pony pony, DataTracker tracker) { + this.pony = pony; + this.tracker = tracker; + this.entity = pony.asEntity(); + this.hangingPos = tracker.startTracking(TrackableDataType.of(PacketCodec.OPTIONAL_POS), Optional.empty()); + pony.addTicker(this::checkDislodge); } public boolean isImmobile() { @@ -147,7 +146,7 @@ public class Acrobatics implements Tickable, NbtSerialisable { } public Optional getHangingPosition() { - return entity.getDataTracker().get(HANGING_POSITION); + return tracker.get(hangingPos); } public boolean isHanging() { @@ -155,13 +154,13 @@ public class Acrobatics implements Tickable, NbtSerialisable { } public void stopHanging() { - entity.getDataTracker().set(HANGING_POSITION, Optional.empty()); + tracker.set(hangingPos, Optional.empty()); entity.calculateDimensions(); ticksHanging = 0; } public void startHanging(BlockPos pos) { - entity.getDataTracker().set(HANGING_POSITION, Optional.of(pos)); + tracker.set(hangingPos, Optional.of(pos)); entity.teleport(pos.getX() + 0.5, pos.getY() - 1, pos.getZ() + 0.5); entity.setVelocity(Vec3d.ZERO); entity.setSneaking(false); @@ -202,6 +201,6 @@ public class Acrobatics implements Tickable, NbtSerialisable { @Override public void fromNBT(NbtCompound compound) { ticksHanging = compound.getInt("ticksHanging"); - pony.asEntity().getDataTracker().set(HANGING_POSITION, NbtSerialisable.BLOCK_POS.readOptional("hangingPosition", compound)); + tracker.set(hangingPos, NbtSerialisable.BLOCK_POS.readOptional("hangingPosition", compound)); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java b/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java index 511e333d..ccb7a65c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java @@ -3,11 +3,13 @@ package com.minelittlepony.unicopia.entity.player; import java.util.HashMap; import java.util.Map; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; -import net.minecraft.entity.data.TrackedData; import net.minecraft.nbt.NbtCompound; import net.minecraft.util.math.MathHelper; @@ -23,14 +25,14 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl private final BarInst xp; private final BarInst charge; - public ManaContainer(Pony pony) { + public ManaContainer(Pony pony, DataTracker tracker) { this.pony = pony; - this.energy = addBar("energy", new BarInst(Pony.ENERGY, 100F, 0)); - this.exhaustion = addBar("exhaustion", new BarInst(Pony.EXHAUSTION, 100F, 0)); - this.exertion = addBar("exertion", new BarInst(Pony.EXERTION, 10F, 0)); - this.xp = addBar("xp", new BarInst(Pony.XP, 1F, 0)); - this.mana = addBar("mana", new XpCollectingBar(Pony.MANA, 100F, 1)); - this.charge = addBar("charge", new BarInst(Pony.CHARGE, 10F, 0) { + this.energy = addBar("energy", new BarInst(tracker, 100F, 0)); + this.exhaustion = addBar("exhaustion", new BarInst(tracker, 100F, 0)); + this.exertion = addBar("exertion", new BarInst(tracker, 10F, 0)); + this.xp = addBar("xp", new BarInst(tracker, 1F, 0)); + this.mana = addBar("mana", new XpCollectingBar(tracker, 100F, 1)); + this.charge = addBar("charge", new BarInst(tracker, 10F, 0) { @Override protected float applyLimits(float value) { return Math.max(0, value); @@ -38,10 +40,6 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl }); } - public void initDataTracker() { - bars.values().forEach(BarInst::initDataTracker); - } - protected BarInst addBar(String name, BarInst bar) { bars.put(name, bar); return bar; @@ -130,9 +128,8 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl } class XpCollectingBar extends BarInst { - - XpCollectingBar(TrackedData marker, float max, float initial) { - super(marker, max, initial); + XpCollectingBar(DataTracker tracker, float max, float initial) { + super(tracker, max, initial); } @Override @@ -156,29 +153,26 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl } class BarInst implements Bar, NbtSerialisable { - - private final TrackedData marker; + private final DataTracker tracker; + private final DataTracker.Entry marker; private final float max; private float trailingValue; private float prevTrailingValue; private float prevValue; - BarInst(TrackedData marker, float max, float initial) { - this.marker = marker; + BarInst(DataTracker tracker, float max, float initial) { + this.tracker = tracker; this.max = max; this.trailingValue = initial; this.prevTrailingValue = initial; this.prevValue = initial; - } - - public void initDataTracker() { - pony.asEntity().getDataTracker().startTracking(marker, max * trailingValue); + this.marker = tracker.startTracking(TrackableDataType.of(PacketCodec.FLOAT), max * trailingValue); } @Override public float get() { - return applyLimits(pony.asEntity().getDataTracker().get(marker)); + return applyLimits(tracker.get(marker)); } @Override @@ -197,7 +191,7 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl } private void load(float value) { - pony.asEntity().getDataTracker().set(marker, value); + tracker.set(marker, value); } protected float getInitial(float initial) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java index f883529a..edd6f65f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java @@ -1,8 +1,10 @@ package com.minelittlepony.unicopia.entity.player; import com.minelittlepony.unicopia.ability.magic.Levelled; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; -import net.minecraft.entity.data.TrackedData; import net.minecraft.sound.*; import net.minecraft.util.math.MathHelper; @@ -10,15 +12,17 @@ class PlayerLevelStore implements Levelled.LevelStore { private final Pony pony; - private final TrackedData dataEntry; + private final DataTracker tracker; + private final DataTracker.Entry dataEntry; private final boolean upgradeMana; private final SoundEvent levelUpSound; - PlayerLevelStore(Pony pony, TrackedData dataEntry, boolean upgradeMana, SoundEvent levelUpSound) { + PlayerLevelStore(Pony pony, DataTracker tracker, boolean upgradeMana, SoundEvent levelUpSound) { this.pony = pony; - this.dataEntry = dataEntry; + this.tracker = tracker; + this.dataEntry = tracker.startTracking(TrackableDataType.of(PacketCodec.INT), 0); this.upgradeMana = upgradeMana; this.levelUpSound = levelUpSound; } @@ -41,11 +45,11 @@ class PlayerLevelStore implements Levelled.LevelStore { @Override public int get() { - return pony.asEntity().getDataTracker().get(dataEntry); + return tracker.get(dataEntry); } @Override public void set(int level) { - pony.asEntity().getDataTracker().set(dataEntry, MathHelper.clamp(level, 0, getMax())); + tracker.set(dataEntry, MathHelper.clamp(level, 0, getMax())); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index cebc54c6..77ee72e0 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -25,6 +25,7 @@ import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.MsgPlayerFlightControlsInput; +import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.particle.*; import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; @@ -97,8 +98,8 @@ public class PlayerPhysics extends EntityPhysics implements Tickab private Lerp updraft = new Lerp(0); private Lerp windStrength = new Lerp(0); - public PlayerPhysics(Pony pony) { - super(pony.asEntity(), Creature.GRAVITY); + public PlayerPhysics(Pony pony, DataTracker tracker) { + super(pony.asEntity(), tracker); this.pony = pony; dimensions = new PlayerDimensions(pony, this); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 87a8d8d9..82033249 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -34,6 +34,8 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.util.*; import com.minelittlepony.unicopia.network.*; import com.minelittlepony.unicopia.network.datasync.EffectSync.UpdateCallback; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.server.world.UGameRules; import com.minelittlepony.common.util.animation.LinearInterpolator; import com.google.common.collect.Streams; @@ -46,9 +48,6 @@ import net.minecraft.entity.*; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageTypes; -import net.minecraft.entity.data.DataTracker; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.player.PlayerEntity; @@ -71,28 +70,14 @@ import net.minecraft.world.GameMode; import net.minecraft.world.GameRules; public class Pony extends Living implements Copyable, UpdateCallback { - private static final TrackedData RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING); - private static final TrackedData SUPPRESSED_RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING); - - static final TrackedData ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData EXHAUSTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData EXERTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData MANA = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData XP = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData CHARGE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData LEVEL = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER); - static final TrackedData CORRUPTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER); - static final int INITIAL_SUN_IMMUNITY = 20; - private static final TrackedData EFFECT = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); - private final AbilityDispatcher powers = new AbilityDispatcher(this); - private final PlayerPhysics gravity = addTicker(new PlayerPhysics(this)); + private final PlayerPhysics gravity = addTicker(new PlayerPhysics(this, tracker)); private final PlayerCharmTracker charms = new PlayerCharmTracker(this); private final PlayerCamera camera = new PlayerCamera(this); private final TraitDiscovery discoveries = new TraitDiscovery(this); - private final Acrobatics acrobatics = new Acrobatics(this); + private final Acrobatics acrobatics = new Acrobatics(this, tracker); private final CorruptionHandler corruptionHandler = new CorruptionHandler(this); private final Map advancementProgress = new HashMap<>(); @@ -121,11 +106,16 @@ public class Pony extends Living implements Copyable, Update private int animationMaxDuration; private int animationDuration; + private DataTracker.Entry race; + private DataTracker.Entry suppressedRace; + public Pony(PlayerEntity player) { - super(player, EFFECT); - this.levels = new PlayerLevelStore(this, LEVEL, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); - this.corruption = new PlayerLevelStore(this, CORRUPTION, false, USounds.ENTITY_PLAYER_CORRUPTION); - this.mana = addTicker(new ManaContainer(this)); + super(player); + race = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); + suppressedRace = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); + this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); + this.corruption = new PlayerLevelStore(this, tracker, false, USounds.ENTITY_PLAYER_CORRUPTION); + this.mana = addTicker(new ManaContainer(this, tracker)); addTicker(this::updateAnimations); addTicker(this::updateBatPonyAbilities); @@ -134,17 +124,6 @@ public class Pony extends Living implements Copyable, Update addTicker(corruptionHandler); } - @Override - public void initDataTracker() { - super.initDataTracker(); - acrobatics.initDataTracker(); - mana.initDataTracker(); - entity.getDataTracker().startTracking(LEVEL, 0); - entity.getDataTracker().startTracking(CORRUPTION, 0); - entity.getDataTracker().startTracking(RACE, Race.DEFAULT_ID); - entity.getDataTracker().startTracking(SUPPRESSED_RACE, Race.DEFAULT_ID); - } - public static void registerAttributes(DefaultAttributeContainer.Builder builder) { builder.add(UEntityAttributes.EXTRA_MINING_SPEED); builder.add(UEntityAttributes.ENTITY_GRAVITY_MODIFIER); @@ -218,7 +197,7 @@ public class Pony extends Living implements Copyable, Update */ @Override public Race getSpecies() { - return Race.fromName(entity.getDataTracker().get(RACE), Race.HUMAN); + return tracker.get(race); } /** @@ -242,7 +221,7 @@ public class Pony extends Living implements Copyable, Update public void setSpecies(Race race) { race = race.validate(entity); Race current = getSpecies(); - entity.getDataTracker().set(RACE, race.getId().toString()); + tracker.set(this.race, race); if (race != current) { clearSuppressedRace(); } @@ -255,7 +234,7 @@ public class Pony extends Living implements Copyable, Update } public void setSuppressedRace(Race race) { - entity.getDataTracker().set(SUPPRESSED_RACE, race.validate(entity).getId().toString()); + tracker.set(suppressedRace, race.validate(entity)); } public void clearSuppressedRace() { @@ -263,7 +242,7 @@ public class Pony extends Living implements Copyable, Update } public Race getSuppressedRace() { - return Race.fromName(entity.getDataTracker().get(SUPPRESSED_RACE), Race.UNSET); + return tracker.get(suppressedRace); } public TraitDiscovery getDiscoveries() { diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java index 13644fbb..39740a41 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java @@ -11,6 +11,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.entity.duck.LavaAffine; +import com.minelittlepony.unicopia.network.track.DataTrackerManager; +import com.minelittlepony.unicopia.network.track.Trackable; import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.magic.Caster; @@ -19,11 +21,11 @@ import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.duck.EntityDuck; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.MovementType; import net.minecraft.entity.Entity.PositionUpdater; import net.minecraft.entity.Entity.RemovalReason; +import net.minecraft.entity.EntityType; import net.minecraft.fluid.Fluid; import net.minecraft.item.ItemStack; import net.minecraft.registry.tag.TagKey; @@ -31,10 +33,12 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @Mixin(Entity.class) -abstract class MixinEntity implements EntityDuck { +abstract class MixinEntity implements EntityDuck, Trackable { @Nullable private transient Caster host; + private DataTrackerManager dataTrackerManager; + @Override @Nullable public Caster getHost() { @@ -46,6 +50,14 @@ abstract class MixinEntity implements EntityDuck { this.host = host; } + @Override + public DataTrackerManager getDataTrackers() { + if (dataTrackerManager == null) { + dataTrackerManager = new DataTrackerManager((Entity)(Object)this); + } + return dataTrackerManager; + } + @Override @Accessor("submergedFluidTag") public abstract Set> getSubmergedFluidTags(); @@ -104,6 +116,13 @@ abstract class MixinEntity implements EntityDuck { } } + @Inject(method = "tick()V", at = @At("RETURN")) + private void afterTick(CallbackInfo info) { + if (dataTrackerManager != null) { + dataTrackerManager.tick(); + } + } + @Inject(method = "updatePassengerPosition(Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/Entity$PositionUpdater;)V", at = @At("HEAD"), cancellable = true diff --git a/src/main/java/com/minelittlepony/unicopia/network/Channel.java b/src/main/java/com/minelittlepony/unicopia/network/Channel.java index 8e6bc8c2..e9f86d0d 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/Channel.java +++ b/src/main/java/com/minelittlepony/unicopia/network/Channel.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.network; import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.network.track.MsgTrackedValues; import com.minelittlepony.unicopia.server.world.UnicopiaWorldProperties; import com.minelittlepony.unicopia.server.world.ZapAppleStageStore; import com.sollace.fabwork.api.packets.*; @@ -31,6 +32,7 @@ public interface Channel { S2CPacketType SERVER_RESOURCES = SimpleNetworking.serverToClient(Unicopia.id("resources"), MsgServerResources::new); + S2CPacketType SERVER_TRACKED_ENTITY_DATA = SimpleNetworking.serverToClient(Unicopia.id("tracked_entity_date"), MsgTrackedValues::new); S2CPacketType SERVER_OTHER_PLAYER_CAPABILITIES = SimpleNetworking.serverToClient(Unicopia.id("other_player_capabilities"), MsgOtherPlayerCapabilities::new); S2CPacketType SERVER_PLAYER_ANIMATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("other_player_animation_change"), MsgPlayerAnimationChange::new); S2CPacketType SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java new file mode 100644 index 00000000..71116e23 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -0,0 +1,143 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +import org.jetbrains.annotations.Nullable; + +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.network.PacketByteBuf; + +public class DataTracker { + private final List> codecs = new ObjectArrayList<>(); + private final Int2ObjectOpenHashMap> loadCallbacks = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectOpenHashMap writethroughCallback = new Int2ObjectOpenHashMap<>(); + private IntSet dirtyIndices = new IntOpenHashSet(); + + private final DataTrackerManager manager; + private boolean initial = true; + + final int id; + + public DataTracker(DataTrackerManager manager, int id) { + this.manager = manager; + this.id = id; + } + + public Entry startTracking(TrackableDataType type, T initialValue) { + Entry entry = new Entry<>(codecs.size()); + codecs.add(new Pair<>(entry.id(), type, initialValue)); + return entry; + } + + public void onReceive(Entry entry, Consumer loadCallback) { + loadCallbacks.put(entry.id(), loadCallback); + } + + public void onBeforeSend(Entry entry, Runnable action) { + writethroughCallback.put(entry.id(), action); + } + + @SuppressWarnings("unchecked") + private Pair getPair(Entry entry) { + return (Pair)codecs.get(entry.id()); + } + + public T get(Entry entry) { + return getPair(entry).value; + } + + public void set(Entry entry, T value) { + if (manager.isClient) { + return; + } + + Pair pair = getPair(entry); + if (!Objects.equals(pair.value, value)) { + pair.value = value; + dirtyIndices.add(entry.id()); + } + } + + @Nullable + MsgTrackedValues.TrackerEntries getDirtyPairs() { + writethroughCallback.values().forEach(Runnable::run); + + if (initial) { + initial = false; + dirtyIndices = new IntOpenHashSet(); + return new MsgTrackedValues.TrackerEntries(id, true, codecs); + } + + if (dirtyIndices.isEmpty()) { + return null; + } + + IntSet toSend = dirtyIndices; + dirtyIndices = new IntOpenHashSet(); + List> pairs = new ArrayList<>(); + for (int i : toSend) { + pairs.add(codecs.get(i)); + } + return new MsgTrackedValues.TrackerEntries(id, false, pairs); + } + + @SuppressWarnings("unchecked") + void load(boolean wipe, List> values) { + if (wipe) { + codecs.clear(); + codecs.addAll(values); + for (var value : values) { + Consumer callback = loadCallbacks.get(value.id); + if (callback != null) { + ((Consumer)callback).accept(value.value); + } + } + } else { + values.forEach(value -> { + if (value.id >= 0 && value.id < codecs.size()) { + if (codecs.get(value.id).type == value.type) { + codecs.set(value.id, value); + Consumer callback = loadCallbacks.get(value.id); + if (callback != null) { + ((Consumer)callback).accept(value.value); + } + } + } + }); + } + } + + public void close() { + manager.closeTracker(id); + } + + public record Entry(int id) {} + static class Pair { + private final TrackableDataType type; + public final int id; + public T value; + + public Pair(int id, TrackableDataType type, T value) { + this.id = id; + this.type = type; + this.value = value; + } + + public Pair(PacketByteBuf buffer) { + this.id = buffer.readInt(); + this.type = TrackableDataType.of(buffer.readInt()); + this.value = type.read(buffer); + } + + public void write(PacketByteBuf buffer) { + buffer.writeInt(id); + type.write(buffer, value); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java new file mode 100644 index 00000000..e4e9e01e --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -0,0 +1,83 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.ArrayList; +import java.util.List; + +import com.minelittlepony.unicopia.network.Channel; +import com.minelittlepony.unicopia.util.Tickable; + +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.entity.Entity; + +public class DataTrackerManager implements Tickable { + private final Entity entity; + final boolean isClient; + private final Int2ObjectOpenHashMap trackers = new Int2ObjectOpenHashMap<>(); + + private IntSet discardedTrackers = new IntOpenHashSet(); + private int nextId = 0; + + private final DataTracker primaryTracker = checkoutTracker(); + + public DataTrackerManager(Entity entity) { + this.entity = entity; + this.isClient = entity.getWorld().isClient; + } + + public DataTracker getPrimaryTracker() { + return primaryTracker; + } + + public DataTracker checkoutTracker() { + DataTracker tracker = new DataTracker(this, nextId++); + trackers.put(tracker.id, tracker); + return tracker; + } + + void closeTracker(int id) { + if (id <= 0) { + return; + } + + trackers.remove(id); + if (!isClient) { + discardedTrackers.add(id); + } + } + + @Override + public void tick() { + if (isClient) { + return; + } + + List toTransmit = new ArrayList<>(); + + for (var entry : trackers.int2ObjectEntrySet()) { + MsgTrackedValues.TrackerEntries dirtyPairs = entry.getValue().getDirtyPairs(); + if (dirtyPairs != null) { + toTransmit.add(dirtyPairs); + } + } + + if (!toTransmit.isEmpty() || !discardedTrackers.isEmpty()) { + MsgTrackedValues packet = new MsgTrackedValues(entity.getId(), toTransmit, discardedTrackers.toIntArray()); + discardedTrackers = new IntOpenHashSet(); + Channel.SERVER_TRACKED_ENTITY_DATA.sendToSurroundingPlayers(packet, entity); + } + } + + void load(MsgTrackedValues packet) { + for (int id : packet.removedTrackers()) { + closeTracker(id); + } + for (var update : packet.updatedTrackers()) { + DataTracker tracker = trackers.get(update.id()); + if (tracker != null) { + tracker.load(update.wipe(), update.values()); + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java new file mode 100644 index 00000000..7f8d16e4 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java @@ -0,0 +1,46 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.ArrayList; +import java.util.List; +import com.sollace.fabwork.api.packets.HandledPacket; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; + +public record MsgTrackedValues( + int owner, + List updatedTrackers, + int[] removedTrackers +) implements HandledPacket { + public MsgTrackedValues(PacketByteBuf buffer) { + this(buffer.readInt(), buffer.readCollection(ArrayList::new, TrackerEntries::new), buffer.readIntArray()); + } + + @Override + public void toBuffer(PacketByteBuf buffer) { + buffer.writeInt(owner); + buffer.writeCollection(updatedTrackers, (buf, tracker) -> tracker.write(buf)); + buffer.writeIntArray(removedTrackers); + } + + @Override + public void handle(PlayerEntity sender) { + Entity entity = sender.getWorld().getEntityById(owner); + if (entity instanceof Trackable trackable) { + trackable.getDataTrackers().load(this); + } + } + + public record TrackerEntries(int id, boolean wipe, List> values) { + public TrackerEntries(PacketByteBuf buffer) { + this(buffer.readInt(), buffer.readBoolean(), buffer.readCollection(ArrayList::new, DataTracker.Pair::new)); + } + + public void write(PacketByteBuf buffer) { + buffer.writeInt(id); + buffer.writeBoolean(wipe); + buffer.writeCollection(values, (buf, pair) -> pair.write(buf)); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java b/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java new file mode 100644 index 00000000..5fdcd9a0 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java @@ -0,0 +1,12 @@ +package com.minelittlepony.unicopia.network.track; + +import net.minecraft.entity.Entity; + +public interface Trackable { + + DataTrackerManager getDataTrackers(); + + static Trackable of(Entity entity) { + return (Trackable)entity; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java new file mode 100644 index 00000000..6b4500a4 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java @@ -0,0 +1,38 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.Interner; +import com.google.common.collect.Interners; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; + +import net.minecraft.network.PacketByteBuf; + +public record TrackableDataType(int id, PacketCodec codec) { + private static final List> REGISTRY = new ArrayList<>(); + private static final Interner> INTERNER = Interners.newStrongInterner(); + + @SuppressWarnings("unchecked") + public static TrackableDataType of(int id) { + return (TrackableDataType)REGISTRY.get(id); + } + + public static TrackableDataType of(PacketCodec codec) { + @SuppressWarnings("unchecked") + TrackableDataType type = (TrackableDataType) INTERNER.intern(new TrackableDataType<>(REGISTRY.size(), codec)); + if (type.id() == REGISTRY.size()) { + REGISTRY.add(type); + } + return type; + } + + public T read(PacketByteBuf buffer) { + return codec().read(buffer); + } + + public void write(PacketByteBuf buffer, T value) { + buffer.writeInt(id()); + codec().write(buffer, value); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java index 1c1f9f44..daea0f24 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java @@ -19,6 +19,7 @@ import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.network.datasync.EffectSync; +import com.minelittlepony.unicopia.network.track.Trackable; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -31,13 +32,11 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class MagicBeamEntity extends MagicProjectileEntity implements Caster, MagicImmune { - private static final TrackedData GRAVITY = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.FLOAT); - private static final TrackedData HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN); private static final TrackedData EFFECT = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); + private static final TrackedData HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN); private final EffectSync effectDelegate = new EffectSync(this, EFFECT); - - private final EntityPhysics physics = new EntityPhysics<>(this, GRAVITY); + private final EntityPhysics physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); public MagicBeamEntity(EntityType type, World world) { super(type, world); @@ -55,10 +54,10 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster(PacketByteBuf.PacketReader reader, PacketByteBuf.PacketWriter writer) { + public static final PacketCodec BOOLEAN = new PacketCodec<>(PacketByteBuf::readBoolean, PacketByteBuf::writeBoolean); public static final PacketCodec FLOAT = new PacketCodec<>(PacketByteBuf::readFloat, PacketByteBuf::writeFloat); public static final PacketCodec INT = new PacketCodec<>(PacketByteBuf::readInt, PacketByteBuf::writeInt); public static final PacketCodec BYTE = new PacketCodec<>(PacketByteBuf::readByte, (b, v) -> b.writeByte(v)); public static final PacketCodec LONG = new PacketCodec<>(PacketByteBuf::readLong, PacketByteBuf::writeLong); public static final PacketCodec STRING = new PacketCodec<>(PacketByteBuf::readString, PacketByteBuf::writeString); + public static final PacketCodec UUID = new PacketCodec<>(PacketByteBuf::readUuid, PacketByteBuf::writeUuid); + public static final PacketCodec> OPTIONAL_UUID = UUID.asOptional(); public static final PacketCodec IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString); + public static final PacketCodec NBT = new PacketCodec<>(PacketByteBuf::readNbt, PacketByteBuf::writeNbt); + + public static final PacketCodec POS = new PacketCodec<>(PacketByteBuf::readBlockPos, PacketByteBuf::writeBlockPos); + public static final PacketCodec> OPTIONAL_POS = POS.asOptional(); + public static final PacketCodec ofRegistry(Registry registry) { return INT.xMap(registry::get, registry::getRawId); } From b9015c9220675e84e8e92f877a5d1f309c100671 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 21 May 2024 00:23:46 +0100 Subject: [PATCH 31/85] Add synchronization to keep it from messing up --- .../unicopia/network/track/DataTracker.java | 10 +++--- .../network/track/DataTrackerManager.java | 34 +++++++++++-------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index 71116e23..7aa6dc99 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -59,13 +59,15 @@ public class DataTracker { Pair pair = getPair(entry); if (!Objects.equals(pair.value, value)) { - pair.value = value; - dirtyIndices.add(entry.id()); + synchronized (this) { + pair.value = value; + dirtyIndices.add(entry.id()); + } } } @Nullable - MsgTrackedValues.TrackerEntries getDirtyPairs() { + synchronized MsgTrackedValues.TrackerEntries getDirtyPairs() { writethroughCallback.values().forEach(Runnable::run); if (initial) { @@ -88,7 +90,7 @@ public class DataTracker { } @SuppressWarnings("unchecked") - void load(boolean wipe, List> values) { + synchronized void load(boolean wipe, List> values) { if (wipe) { codecs.clear(); codecs.addAll(values); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java index e4e9e01e..10f7b83a 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -30,13 +30,13 @@ public class DataTrackerManager implements Tickable { return primaryTracker; } - public DataTracker checkoutTracker() { + public synchronized DataTracker checkoutTracker() { DataTracker tracker = new DataTracker(this, nextId++); trackers.put(tracker.id, tracker); return tracker; } - void closeTracker(int id) { + synchronized void closeTracker(int id) { if (id <= 0) { return; } @@ -53,31 +53,35 @@ public class DataTrackerManager implements Tickable { return; } - List toTransmit = new ArrayList<>(); + synchronized (this) { + List toTransmit = new ArrayList<>(); - for (var entry : trackers.int2ObjectEntrySet()) { - MsgTrackedValues.TrackerEntries dirtyPairs = entry.getValue().getDirtyPairs(); - if (dirtyPairs != null) { - toTransmit.add(dirtyPairs); + for (var entry : trackers.int2ObjectEntrySet()) { + MsgTrackedValues.TrackerEntries dirtyPairs = entry.getValue().getDirtyPairs(); + if (dirtyPairs != null) { + toTransmit.add(dirtyPairs); + } } - } - if (!toTransmit.isEmpty() || !discardedTrackers.isEmpty()) { - MsgTrackedValues packet = new MsgTrackedValues(entity.getId(), toTransmit, discardedTrackers.toIntArray()); - discardedTrackers = new IntOpenHashSet(); - Channel.SERVER_TRACKED_ENTITY_DATA.sendToSurroundingPlayers(packet, entity); + if (!toTransmit.isEmpty() || !discardedTrackers.isEmpty()) { + MsgTrackedValues packet = new MsgTrackedValues(entity.getId(), toTransmit, discardedTrackers.toIntArray()); + discardedTrackers = new IntOpenHashSet(); + Channel.SERVER_TRACKED_ENTITY_DATA.sendToSurroundingPlayers(packet, entity); + } } } - void load(MsgTrackedValues packet) { + synchronized void load(MsgTrackedValues packet) { for (int id : packet.removedTrackers()) { closeTracker(id); } for (var update : packet.updatedTrackers()) { DataTracker tracker = trackers.get(update.id()); - if (tracker != null) { - tracker.load(update.wipe(), update.values()); + if (tracker == null) { + tracker = new DataTracker(this, update.id()); + trackers.put(update.id(), tracker); } + tracker.load(update.wipe(), update.values()); } } } From 4bac633a235c9cbaf16aa2f7d034e9947565d4d2 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 21 May 2024 23:10:02 +0100 Subject: [PATCH 32/85] Remove the update argument when interacting with spell slots --- .../ability/ChangelingDisguiseAbility.java | 2 +- .../unicopia/ability/TimeChangeAbility.java | 4 +- .../ability/UnicornCastingAbility.java | 2 +- .../ability/UnicornDispellAbility.java | 2 +- .../ability/magic/SpellContainer.java | 20 +++++----- .../magic/spell/AbstractDisguiseSpell.java | 2 +- .../magic/spell/effect/BubbleSpell.java | 3 +- .../spell/effect/DisperseIllusionSpell.java | 2 +- .../magic/spell/effect/MindSwapSpell.java | 4 +- .../client/gui/DismissSpellScreen.java | 4 +- .../client/gui/SpellIconRenderer.java | 4 +- .../SpellbookProfilePageContent.java | 2 +- .../render/DisguisedArmsFeatureRenderer.java | 2 +- .../render/EntityReplacementManager.java | 2 +- .../client/render/HornFeatureRenderer.java | 4 +- .../entity/MagicBeamEntityRenderer.java | 2 +- .../spell/SpellEffectsRenderDispatcher.java | 4 +- .../unicopia/command/DisguiseCommand.java | 4 +- .../unicopia/entity/Creature.java | 2 +- .../unicopia/entity/Living.java | 8 ++-- .../entity/collision/EntityCollisions.java | 2 +- .../unicopia/entity/mob/CastSpellEntity.java | 6 +-- .../entity/player/CorruptionHandler.java | 2 +- .../unicopia/entity/player/PlayerCamera.java | 2 +- .../entity/player/PlayerDimensions.java | 2 +- .../unicopia/entity/player/PlayerPhysics.java | 2 +- .../unicopia/entity/player/Pony.java | 14 +++---- .../unicopia/item/EnchantedStaffItem.java | 2 +- .../unicopia/mixin/MixinLivingEntity.java | 2 +- .../client/MixinClientPlayNetworkHandler.java | 2 +- .../network/MsgCasterLookRequest.java | 2 +- .../unicopia/network/datasync/EffectSync.java | 37 ++++++++++--------- .../unicopia/projectile/MagicBeamEntity.java | 4 +- .../unicopia/server/world/Ether.java | 2 +- 34 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java index 6f3e2c60..dd6af2cc 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java @@ -51,7 +51,7 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility { player.getEntityWorld().playSound(null, player.getBlockPos(), USounds.ENTITY_PLAYER_CHANGELING_TRANSFORM, SoundCategory.PLAYERS, 1.4F, 0.4F); - Disguise currentDisguise = iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true) + Disguise currentDisguise = iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE) .orElseGet(() -> SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer, CastingMethod.INNATE)); if (currentDisguise.isOf(looked)) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java index b06df709..99e7d543 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java @@ -57,9 +57,7 @@ public class TimeChangeAbility implements Ability { return false; } - if (player.getSpellSlot().contains(SpellType.TIME_CONTROL)) { - player.getSpellSlot().removeWhere(SpellType.TIME_CONTROL, true); - } else { + if (!player.getSpellSlot().removeWhere(SpellType.TIME_CONTROL)) { SpellType.TIME_CONTROL.withTraits().apply(player, CastingMethod.INNATE).update(player, data.applyTo(player)); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index 44edde82..6542072f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -108,7 +108,7 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility { } boolean hasExact = !spell.isStackable() && player.getSpellSlot().contains(s -> !s.getTypeAndTraits().isStackable() && spell.test(s)); - boolean removed = !spell.isStackable() && player.getSpellSlot().removeWhere(s -> !s.getTypeAndTraits().isStackable() && s.findMatches(spell.type()).findAny().isPresent(), true); + boolean removed = !spell.isStackable() && player.getSpellSlot().removeWhere(s -> !s.getTypeAndTraits().isStackable() && s.findMatches(spell.type()).findAny().isPresent()); player.subtractEnergyCost(removed ? 2 : 4); if (!hasExact && !spell.isEmpty()) { Spell s = spell.apply(player, CastingMethod.DIRECT); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java index 4eb6f47a..61f4a3e8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java @@ -97,7 +97,7 @@ public class UnicornDispellAbility implements Ability { spell.setDead(); spell.tickDying(target); return Operation.ofBoolean(!spell.isDead()); - }, true); + }); }); return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java index e703911d..0cae9891 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java @@ -19,20 +19,20 @@ public interface SpellContainer { * Checks if any matching spells are active. */ default boolean contains(@Nullable SpellPredicate type) { - return get(type, true).isPresent(); + return get(type).isPresent(); } /** * Gets the active effect for this caster updating it if needed. */ - default Optional get(boolean update) { - return get(null, update); + default Optional get() { + return get(null); } /** * Gets the active effect for this caster updating it if needed. */ - Optional get(@Nullable SpellPredicate type, boolean update); + Optional get(@Nullable SpellPredicate type); /** * Sets the active effect. @@ -51,8 +51,8 @@ public interface SpellContainer { * * @return True if the collection was changed */ - default boolean removeIf(Predicate test, boolean update) { - return removeWhere(spell -> spell.findMatches(test).findFirst().isPresent(), update); + default boolean removeIf(Predicate test) { + return removeWhere(spell -> spell.findMatches(test).findFirst().isPresent()); } /** @@ -60,25 +60,25 @@ public interface SpellContainer { * * @return True if the collection was changed */ - boolean removeWhere(Predicate test, boolean update); + boolean removeWhere(Predicate test); /** * Iterates active spells and optionally removes matching ones. * * @return True if any matching spells remain active */ - boolean forEach(Function action, boolean update); + boolean forEach(Function action); /** * Gets all active effects for this caster updating it if needed. */ - Stream stream(boolean update); + Stream stream(); /** * Gets all active effects for this caster that match the given type updating it if needed. */ - Stream stream(@Nullable SpellPredicate type, boolean update); + Stream stream(@Nullable SpellPredicate type); /** * Removes all effects currently active in this slot. diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java index 1c34f82d..14a35e99 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java @@ -71,7 +71,7 @@ public abstract class AbstractDisguiseSpell extends AbstractSpell implements Dis public static Entity getAppearance(Entity e) { return e instanceof PlayerEntity ? Pony.of((PlayerEntity)e) .getSpellSlot() - .get(SpellPredicate.IS_DISGUISE, true) + .get(SpellPredicate.IS_DISGUISE) .map(AbstractDisguiseSpell::getDisguise) .map(EntityAppearance::getAppearance) .orElse(e) : e; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index db9f7d5e..2cc4dd51 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -71,8 +71,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, @Override public boolean apply(Caster source) { - if (getType().isOn(source)) { - source.getSpellSlot().removeWhere(getType(), true); + if (source.getSpellSlot().removeWhere(getType())) { return false; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java index 9affae3e..3d88d40f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java @@ -38,7 +38,7 @@ public class DisperseIllusionSpell extends AbstractAreaEffectSpell { } source.findAllSpellsInRange(range).forEach(e -> { - e.getSpellSlot().get(SpellPredicate.CAN_SUPPRESS, false) + e.getSpellSlot().get(SpellPredicate.CAN_SUPPRESS) .filter(spell -> spell.isVulnerable(source, this)) .ifPresent(spell -> { spell.onSuppressed(source, 1 + getTraits().get(Trait.STRENGTH)); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java index 4b2f9cb0..ed55f91b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java @@ -60,8 +60,8 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti LivingEntity master = caster.getMaster(); Caster other = Caster.of(e).get(); - other.getSpellSlot().removeIf(SpellType.MIMIC, true); - caster.getSpellSlot().removeIf(getType(), true); + other.getSpellSlot().removeIf(SpellType.MIMIC); + caster.getSpellSlot().removeIf(getType()); if (!isValidTarget(master) || !isValidTarget(e)) { master.damage(caster.asWorld().getDamageSources().magic(), Float.MAX_VALUE); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 8633b6f7..4910981f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -43,7 +43,7 @@ public class DismissSpellScreen extends GameGui { List placeableSpells = new ArrayList<>(); - for (Spell spell : pony.getSpellSlot().stream(true).filter(SpellPredicate.IS_VISIBLE).toList()) { + for (Spell spell : pony.getSpellSlot().stream().filter(SpellPredicate.IS_VISIBLE).toList()) { if (spell instanceof PlaceableSpell placeable) { if (placeable.getPosition().isPresent()) { @@ -147,7 +147,7 @@ public class DismissSpellScreen extends GameGui { public boolean mouseClicked(double mouseX, double mouseY, int button) { if (isMouseOver(relativeMouseX, relativeMouseY)) { remove(this); - pony.getSpellSlot().removeIf(spell -> spell == this.spell, true); + pony.getSpellSlot().removeIf(spell -> spell == this.spell); Channel.REMOVE_SPELL.sendToServer(new MsgRemoveSpell(spell)); playClickEffect(); return true; diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/SpellIconRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/gui/SpellIconRenderer.java index 77a54548..a113c369 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/SpellIconRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/SpellIconRenderer.java @@ -35,11 +35,11 @@ public interface SpellIconRenderer { DrawableUtil.drawArc(modelStack, radius, radius + 3, 0, DrawableUtil.TAU, color & 0xFFFFFF2F, false); DrawableUtil.drawArc(modelStack, radius + 3, radius + 4, 0, DrawableUtil.TAU, color & 0xFFFFFFAF, false); - pony.getSpellSlot().get(spell.and(SpellPredicate.IS_TIMED), false).map(TimedSpell::getTimer).ifPresent(timer -> { + pony.getSpellSlot().get(spell.and(SpellPredicate.IS_TIMED)).map(TimedSpell::getTimer).ifPresent(timer -> { DrawableUtil.drawArc(modelStack, radius, radius + 3, 0, DrawableUtil.TAU * timer.getPercentTimeRemaining(client.getTickDelta()), 0xFFFFFFFF, false); }); - long count = pony.getSpellSlot().stream(spell, false).count(); + long count = pony.getSpellSlot().stream(spell).count(); if (count > 1) { modelStack.push(); modelStack.translate(1, 1, 900); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java index f0829b23..f68d0790 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java @@ -105,7 +105,7 @@ public class SpellbookProfilePageContent implements SpellbookChapterList.Content int color = 0x10404000 | alpha; int xpColor = 0xAA0040FF | ((int)((0.3F + 0.7F * xpPercentage) * 0xFF) & 0xFF) << 16; int manaColor = 0xFF00F040; - if (pony.getSpellSlot().get(SpellPredicate.IS_CORRUPTING, false).isPresent()) { + if (pony.getSpellSlot().get(SpellPredicate.IS_CORRUPTING).isPresent()) { manaColor = ColorHelper.lerp(Math.abs(MathHelper.sin(pony.asEntity().age / 15F)), manaColor, 0xFF0030F0); } manaColor |= (int)((0.3F + 0.7F * alphaF) * 0x40) << 16; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/DisguisedArmsFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/DisguisedArmsFeatureRenderer.java index c130779c..6ace7501 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/DisguisedArmsFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/DisguisedArmsFeatureRenderer.java @@ -114,7 +114,7 @@ public class DisguisedArmsFeatureRenderer implements Acc } private Entity getAppearance(E entity) { - return Caster.of(entity).flatMap(caster -> caster.getSpellSlot().get(SpellPredicate.IS_DISGUISE, false)).map(Disguise.class::cast) + return Caster.of(entity).flatMap(caster -> caster.getSpellSlot().get(SpellPredicate.IS_DISGUISE)).map(Disguise.class::cast) .flatMap(Disguise::getAppearance) .map(EntityAppearance::getAppearance) .orElse(null); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/EntityReplacementManager.java b/src/main/java/com/minelittlepony/unicopia/client/render/EntityReplacementManager.java index c1a9d8c7..8b759a18 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/EntityReplacementManager.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/EntityReplacementManager.java @@ -51,7 +51,7 @@ class EntityReplacementManager implements Disguise { return Optional.of(this); } - return caster.getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).map(Disguise.class::cast); + return caster.getSpellSlot().get(SpellPredicate.IS_DISGUISE).map(Disguise.class::cast); } private List> getMobTypePool(EntityType type) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java index 786dee41..2b38a87f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java @@ -55,7 +55,9 @@ public class HornFeatureRenderer implements AccessoryFea return pony.getAbilities().getActiveStat() .flatMap(Stat::getActiveAbility) .map(ability -> ability.getColor(pony)) - .filter(i -> i != -1).or(() -> pony.getSpellSlot().get(SpellPredicate.IS_NOT_PLACED, false).map(spell -> spell.getTypeAndTraits().type().getColor())); + .filter(i -> i != -1).or(() -> pony.getSpellSlot() + .get(SpellPredicate.IS_NOT_PLACED) + .map(spell -> spell.getTypeAndTraits().type().getColor())); }).ifPresent(color -> { model.setState(true); model.render(stack, ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayers.getMagicColored((0x99 << 24) | color), false, false), lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/MagicBeamEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/MagicBeamEntityRenderer.java index 24d4a042..3310d883 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/MagicBeamEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/MagicBeamEntityRenderer.java @@ -56,7 +56,7 @@ public class MagicBeamEntityRenderer extends EntityRenderer { -entity.getPitch(tickDelta) * MathHelper.RADIANS_PER_DEGREE ); - RenderLayer layer = entity.getSpellSlot().get(true) + RenderLayer layer = entity.getSpellSlot().get() .map(spell -> (0x99 << 24) | spell.getTypeAndTraits().type().getColor()) .map(RenderLayers::getMagicColored) .orElseGet(RenderLayers::getMagicColored); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index 4c78034a..b2bcf87a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -90,7 +90,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader caster.getSpellSlot().forEach(spell -> { render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); return Operation.SKIP; - }, false); + }); if (client.getEntityRenderDispatcher().shouldRenderHitboxes() && !client.hasReducedDebugInfo() @@ -125,7 +125,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader caster.asEntity().getDisplayName().copy().append(" (" + Registries.ENTITY_TYPE.getId(caster.asEntity().getType()) + ")"), caster.getMaster() != null ? Text.literal("Master: ").append(caster.getMaster().getDisplayName()) : Text.empty() ), - caster.getSpellSlot().stream(SpellPredicate.ALL, false).flatMap(spell -> + caster.getSpellSlot().stream(SpellPredicate.ALL).flatMap(spell -> Stream.of( Text.literal("UUID: " + spell.getUuid()), Text.literal("|>Type: ").append(Text.literal(spell.getTypeAndTraits().type().getId().toString()).styled(s -> s.withColor(spell.getTypeAndTraits().type().getColor()))), diff --git a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java index 31306fad..d735c89a 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java @@ -80,7 +80,7 @@ public class DisguiseCommand { } Pony iplayer = Pony.of(player); - iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true) + iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE) .orElseGet(() -> SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer, CastingMethod.INNATE)) .setDisguise(entity); @@ -109,7 +109,7 @@ public class DisguiseCommand { static int reveal(ServerCommandSource source, PlayerEntity player) { Pony iplayer = Pony.of(player); - iplayer.getSpellSlot().removeIf(SpellPredicate.IS_DISGUISE, true); + iplayer.getSpellSlot().removeIf(SpellPredicate.IS_DISGUISE); if (source.getEntity() == player) { source.sendFeedback(() -> Text.translatable("commands.disguise.removed.self"), true); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index 46453917..51ad4fa5 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -311,7 +311,7 @@ public class Creature extends Living implements WeaklyOwned.Mutabl @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - getSpellSlot().get(true).ifPresent(effect -> { + getSpellSlot().get().ifPresent(effect -> { compound.put("effect", Spell.writeNbt(effect)); }); compound.put("master", getMasterReference().toNBT()); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 407608f1..58dc2e00 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -290,7 +290,7 @@ public abstract class Living implements Equine, Caste public boolean canBeSeenBy(Entity entity) { return !isInvisible() && getSpellSlot() - .get(SpellPredicate.IS_DISGUISE, true) + .get(SpellPredicate.IS_DISGUISE) .filter(spell -> spell.getDisguise().getAppearance() == entity) .isEmpty(); } @@ -424,7 +424,7 @@ public abstract class Living implements Equine, Caste } public Optional chooseClimbingPos() { - return getSpellSlot().get(SpellPredicate.IS_DISGUISE, false) + return getSpellSlot().get(SpellPredicate.IS_DISGUISE) .map(AbstractDisguiseSpell::getDisguise) .filter(EntityAppearance::canClimbWalls) .map(v -> entity.getBlockPos()); @@ -459,7 +459,7 @@ public abstract class Living implements Equine, Caste @Override public boolean onProjectileImpact(ProjectileEntity projectile) { - return getSpellSlot().get(true) + return getSpellSlot().get() .filter(effect -> !effect.isDead() && effect instanceof ProjectileImpactListener && ((ProjectileImpactListener)effect).onProjectileImpact(projectile)) @@ -469,7 +469,7 @@ public abstract class Living implements Equine, Caste public float onImpact(float distance, float damageMultiplier, DamageSource cause) { float fallDistance = landEvent.fire(getEffectiveFallDistance(distance)); - getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).ifPresent(spell -> { + getSpellSlot().get(SpellPredicate.IS_DISGUISE).ifPresent(spell -> { spell.getDisguise().onImpact(this, fallDistance, damageMultiplier, cause); }); return fallDistance; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/collision/EntityCollisions.java b/src/main/java/com/minelittlepony/unicopia/entity/collision/EntityCollisions.java index d2d65f3e..b4454d66 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/collision/EntityCollisions.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/collision/EntityCollisions.java @@ -44,7 +44,7 @@ public class EntityCollisions { ShapeContext ctx = entity == null ? ShapeContext.absent() : ShapeContext.of(entity); return collectCollisionBoxes(box, collector -> { world.getOtherEntities(entity, box.expand(50), e -> { - Caster.of(e).flatMap(c -> c.getSpellSlot().get(SpellPredicate.IS_DISGUISE, false)).ifPresent(p -> { + Caster.of(e).flatMap(c -> c.getSpellSlot().get(SpellPredicate.IS_DISGUISE)).ifPresent(p -> { p.getDisguise().getCollissionShapes(ctx, collector); }); if (e instanceof ComplexCollidable collidable) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 649bb5d5..0643087f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -77,7 +77,7 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster spell.getScale(1)).orElse(1F)); + return super.getDimensions(pose).scaled(getSpellSlot().get(SpellType.IS_PLACED).map(spell -> spell.getScale(1)).orElse(1F)); } @Override @@ -108,7 +108,7 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster { + getSpellSlot().get().ifPresent(effect -> { tag.put("effect", Spell.writeNbt(effect)); }); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/CorruptionHandler.java b/src/main/java/com/minelittlepony/unicopia/entity/player/CorruptionHandler.java index d3cbc40d..0ea3e639 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/CorruptionHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/CorruptionHandler.java @@ -22,7 +22,7 @@ public class CorruptionHandler implements Tickable { } public boolean hasCorruptingMagic() { - return pony.getSpellSlot().get(SpellPredicate.IS_CORRUPTING, false).isPresent() || UItems.ALICORN_AMULET.isApplicable(pony.asEntity()); + return pony.getSpellSlot().get(SpellPredicate.IS_CORRUPTING).isPresent() || UItems.ALICORN_AMULET.isApplicable(pony.asEntity()); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java index 61effece..792caec6 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java @@ -53,7 +53,7 @@ public class PlayerCamera extends MotionCompositor { public Optional calculateDistance(double distance) { return player.getSpellSlot() - .get(SpellPredicate.IS_DISGUISE, false) + .get(SpellPredicate.IS_DISGUISE) .map(AbstractDisguiseSpell::getDisguise) .flatMap(d -> d.getDistance(player)) .map(d -> distance * d); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java index a2e5a329..491a66fd 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java @@ -39,7 +39,7 @@ public final class PlayerDimensions { } Optional getPredicate() { - return pony.getSpellSlot().get(true) + return pony.getSpellSlot().get() .filter(effect -> !effect.isDead() && effect instanceof Provider) .map(effect -> (Provider)effect); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index 77ee72e0..a9be901e 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -210,7 +210,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab return FlightType.ARTIFICIAL; } - return pony.getSpellSlot().get(true) + return pony.getSpellSlot().get() .filter(effect -> !effect.isDead() && effect instanceof FlightType.Provider) .map(effect -> ((FlightType.Provider)effect).getFlightType()) .filter(FlightType::isPresent) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 82033249..2527bf47 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -479,7 +479,7 @@ public class Pony extends Living implements Copyable, Update Race intrinsicRace = getSpecies(); Race suppressedRace = getSuppressedRace(); compositeRace = MetamorphosisStatusEffect.getEffectiveRace(entity, getSpellSlot() - .get(SpellPredicate.IS_MIMIC, true) + .get(SpellPredicate.IS_MIMIC) .map(AbstractDisguiseSpell::getDisguise) .map(EntityAppearance::getAppearance) .flatMap(Pony::of) @@ -495,7 +495,7 @@ public class Pony extends Living implements Copyable, Update @Override public Optional chooseClimbingPos() { - if (getObservedSpecies() == Race.CHANGELING && getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).isEmpty()) { + if (getObservedSpecies() == Race.CHANGELING && getSpellSlot().get(SpellPredicate.IS_DISGUISE).isEmpty()) { if (acrobatics.isFaceClimbable(entity.getWorld(), entity.getBlockPos(), entity.getHorizontalFacing()) || acrobatics.canHangAt(entity.getBlockPos())) { return Optional.of(entity.getBlockPos()); } @@ -718,7 +718,7 @@ public class Pony extends Living implements Copyable, Update @Override protected float getEffectiveFallDistance(float distance) { - boolean extraProtection = getSpellSlot().get(SpellType.SHIELD, false).isPresent(); + boolean extraProtection = getSpellSlot().get(SpellType.SHIELD).isPresent(); if (!entity.isCreative() && !entity.isSpectator()) { @@ -745,7 +745,7 @@ public class Pony extends Living implements Copyable, Update if (getObservedSpecies() == Race.KIRIN && (stack.isIn(UTags.Items.COOLS_OFF_KIRINS) || PotionUtil.getPotion(stack) == Potions.WATER)) { getMagicalReserves().getCharge().multiply(0.5F); - getSpellSlot().get(SpellType.RAGE, false).ifPresent(RageAbilitySpell::setExtenguishing); + getSpellSlot().get(SpellType.RAGE).ifPresent(RageAbilitySpell::setExtenguishing); } } @@ -758,7 +758,7 @@ public class Pony extends Living implements Copyable, Update @Override public boolean subtractEnergyCost(double foodSubtract) { - if (getSpellSlot().get(SpellPredicate.IS_CORRUPTING, false).isPresent()) { + if (getSpellSlot().get(SpellPredicate.IS_CORRUPTING).isPresent()) { int corruptionTaken = (int)(foodSubtract * (AmuletSelectors.ALICORN_AMULET.test(entity) ? 0.9F : 0.5F)); foodSubtract -= corruptionTaken; getCorruption().add(corruptionTaken); @@ -888,13 +888,13 @@ public class Pony extends Living implements Copyable, Update Race oldSuppressedRace = oldPlayer.getSuppressedRace(); if (alive) { - oldPlayer.getSpellSlot().stream(true).forEach(getSpellSlot()::put); + oldPlayer.getSpellSlot().stream().forEach(getSpellSlot()::put); } else { if (forcedSwap) { oldSuppressedRace = Race.UNSET; Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(entity), "gui.unicopia.tribe_selection.respawn"), (ServerPlayerEntity)entity); } else { - oldPlayer.getSpellSlot().stream(true).filter(SpellPredicate.IS_PLACED).forEach(getSpellSlot()::put); + oldPlayer.getSpellSlot().stream().filter(SpellPredicate.IS_PLACED).forEach(getSpellSlot()::put); } // putting it here instead of adding another injection point into ServerPlayerEntity.copyFrom() diff --git a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java index 6d08b1f7..04868e0b 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java @@ -47,7 +47,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch public static SpellType getSpellType(Entity entity, boolean remove) { if (entity instanceof CastSpellEntity cast) { - return cast.getSpellSlot().get(c -> !SpellPredicate.IS_PLACED.test(c), true) + return cast.getSpellSlot().get(c -> !SpellPredicate.IS_PLACED.test(c)) .map(Spell::getTypeAndTraits) .map(CustomisedSpellType::type) .orElse(SpellType.empty()); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java index da1cff6a..45bfa819 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java @@ -108,7 +108,7 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ @Inject(method = "isPushable()Z", at = @At("HEAD"), cancellable = true) private void onIsPushable(CallbackInfoReturnable info) { Caster.of(this) - .flatMap(c -> c.getSpellSlot().get(SpellPredicate.IS_DISGUISE, false)) + .flatMap(c -> c.getSpellSlot().get(SpellPredicate.IS_DISGUISE)) .map(AbstractDisguiseSpell::getDisguise) .map(EntityAppearance::getAppearance) .filter(Entity::isPushable) diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinClientPlayNetworkHandler.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinClientPlayNetworkHandler.java index 06821d12..e8c1179b 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinClientPlayNetworkHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinClientPlayNetworkHandler.java @@ -24,7 +24,7 @@ abstract class MixinClientPlayNetworkHandler { Living living = Living.living(packet.getEntity(world)); if (living != null) { living.getSpellSlot() - .get(SpellPredicate.IS_DISGUISE, false) + .get(SpellPredicate.IS_DISGUISE) .map(Disguise::getDisguise) .map(EntityAppearance::getAppearance) .ifPresent(appearance -> { diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgCasterLookRequest.java b/src/main/java/com/minelittlepony/unicopia/network/MsgCasterLookRequest.java index d5be5999..5164e0f1 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgCasterLookRequest.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgCasterLookRequest.java @@ -50,7 +50,7 @@ public record MsgCasterLookRequest (UUID spellId) implements Packet { spell.setOrientation(rotation); }); diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java index c66cac4c..36fa7a65 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java +++ b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java @@ -66,7 +66,7 @@ public class EffectSync implements SpellContainer, NbtSerialisable { Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner, t); } return Operation.REMOVE; - }, owner.isClient()); + }); } catch (Exception e) { Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner.asEntity(), e); } @@ -80,12 +80,12 @@ public class EffectSync implements SpellContainer, NbtSerialisable { @Override public boolean contains(@Nullable SpellPredicate type) { - return read(type, true, false).findFirst().isPresent(); + return read(type).findFirst().isPresent(); } @Override - public Optional get(@Nullable SpellPredicate type, boolean update) { - return read(type, update, true).findFirst(); + public Optional get(@Nullable SpellPredicate type) { + return read(type).findFirst(); } @Override @@ -108,8 +108,8 @@ public class EffectSync implements SpellContainer, NbtSerialisable { } @Override - public boolean removeWhere(Predicate test, boolean update) { - return reduce(update, (initial, spell) -> { + public boolean removeWhere(Predicate test) { + return reduce((initial, spell) -> { if (!test.test(spell)) { return initial; } @@ -123,8 +123,8 @@ public class EffectSync implements SpellContainer, NbtSerialisable { } @Override - public boolean forEach(Function test, boolean update) { - return reduce(update, (initial, effect) -> { + public boolean forEach(Function test) { + return reduce((initial, effect) -> { Operation op = test.apply(effect); if (op == Operation.REMOVE) { spells.removeReference(effect); @@ -136,13 +136,13 @@ public class EffectSync implements SpellContainer, NbtSerialisable { } @Override - public Stream stream(boolean update) { - return stream(null, update); + public Stream stream() { + return stream(null); } @Override - public Stream stream(@Nullable SpellPredicate type, boolean update) { - return read(type, update, true); + public Stream stream(@Nullable SpellPredicate type) { + return read(type); } @Override @@ -158,10 +158,11 @@ public class EffectSync implements SpellContainer, NbtSerialisable { } @SuppressWarnings("unchecked") - private Stream read(@Nullable SpellPredicate type, boolean synchronize, boolean sendUpdate) { - if (synchronize && spells.fromNbt(owner.asEntity().getDataTracker().get(param)) && sendUpdate) { - write(); + private Stream read(@Nullable SpellPredicate type) { + if (owner.isClient()) { + spells.fromNbt(owner.asEntity().getDataTracker().get(param)); } + write(); if (type == null) { return (Stream)spells.getReferences(); @@ -169,9 +170,9 @@ public class EffectSync implements SpellContainer, NbtSerialisable { return (Stream)spells.getReferences().flatMap(s -> s.findMatches(type)); } - private boolean reduce(boolean update, Alteration alteration) { + private boolean reduce(Alteration alteration) { boolean initial = false; - for (Spell i : read(null, update, false).toList()) { + for (Spell i : read(null).toList()) { initial = alteration.apply(initial, i); } @@ -180,7 +181,7 @@ public class EffectSync implements SpellContainer, NbtSerialisable { } private void write() { - if (spells.isDirty()) { + if (spells.isDirty() && !owner.isClient()) { owner.asEntity().getDataTracker().set(param, spells.toNbt()); } } diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java index daea0f24..7d92a756 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java @@ -114,7 +114,7 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster { + getSpellSlot().get().ifPresent(effect -> { compound.put("effect", Spell.writeNbt(effect)); }); } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index 73ffa38d..10110d70 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -242,7 +242,7 @@ public class Ether extends PersistentState { spell = entity .getOrEmpty(world) .flatMap(Caster::of) - .flatMap(caster -> caster.getSpellSlot().get(s -> s.getUuid().equals(spellId), true)) + .flatMap(caster -> caster.getSpellSlot().get(s -> s.getUuid().equals(spellId))) .orElse(null); if (spell != null) { From c1bcaaa78e8167da2dec603f2867e8e7d4601475 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 21 May 2024 23:31:36 +0100 Subject: [PATCH 33/85] Properly fix casting --- .../unicopia/ability/UnicornCastingAbility.java | 10 +++++++--- .../unicopia/ability/magic/spell/effect/SpellType.java | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index 6542072f..64f70d7c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -107,10 +107,14 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility { } } - boolean hasExact = !spell.isStackable() && player.getSpellSlot().contains(s -> !s.getTypeAndTraits().isStackable() && spell.test(s)); - boolean removed = !spell.isStackable() && player.getSpellSlot().removeWhere(s -> !s.getTypeAndTraits().isStackable() && s.findMatches(spell.type()).findAny().isPresent()); + if (spell.isEmpty()) { + return false; + } + + boolean has = !spell.isStackable() && player.getSpellSlot().contains(spell); + boolean removed = !spell.isStackable() && player.getSpellSlot().removeWhere(spell.type()); player.subtractEnergyCost(removed ? 2 : 4); - if (!hasExact && !spell.isEmpty()) { + if (!has) { Spell s = spell.apply(player, CastingMethod.DIRECT); if (s == null) { player.spawnParticles(ParticleTypes.LARGE_SMOKE, 6); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index c73def7c..d3efed08 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -52,13 +52,13 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType FROST = register("frost", builder(IceSpell::new).color(0xEABBFF).shape(GemstoneItem.Shape.TRIANGLE).traits(IceSpell.DEFAULT_TRAITS)); public static final SpellType CHILLING_BREATH = register("chilling_breath", builder(ChillingBreathSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEAFF).shape(GemstoneItem.Shape.TRIANGLE).traits(ChillingBreathSpell.DEFAULT_TRAITS)); - public static final SpellType SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS)); + public static final SpellType SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).stackable().shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS)); public static final SpellType FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS)); public static final SpellType INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS)); public static final SpellType SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS)); public static final SpellType ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS)); public static final SpellType VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS)); - public static final SpellType DARK_VORTEX = register("dark_vortex", builder(DarkVortexSpell::new).affinity(Affinity.BAD).color(0xA33333).shape(GemstoneItem.Shape.VORTEX).traits(DarkVortexSpell.DEFAULT_TRAITS)); + public static final SpellType DARK_VORTEX = register("dark_vortex", builder(DarkVortexSpell::new).affinity(Affinity.BAD).color(0xA33333).stackable().shape(GemstoneItem.Shape.VORTEX).traits(DarkVortexSpell.DEFAULT_TRAITS)); public static final SpellType NECROMANCY = register("necromancy", builder(NecromancySpell::new).affinity(Affinity.BAD).color(0xFA3A3A).shape(GemstoneItem.Shape.SKULL)); public static final SpellType SIPHONING = register("siphoning", builder(SiphoningSpell::new).affinity(Affinity.NEUTRAL).color(0xFFA3AA).shape(GemstoneItem.Shape.LAMBDA)); public static final SpellType REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS)); @@ -68,11 +68,11 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS)); public static final SpellType FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS)); public static final SpellType LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS)); - public static final SpellType DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS)); + public static final SpellType DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).stackable().shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS)); public static final SpellType PORTAL = register("portal", builder(PortalSpell::new).color(0x99FFFF).shape(GemstoneItem.Shape.RING).traits(PortalSpell.DEFAULT_TRAITS)); public static final SpellType MIMIC = register("mimic", builder(MimicSpell::new).color(0xFFFF00).shape(GemstoneItem.Shape.ARROW)); public static final SpellType MIND_SWAP = register("mind_swap", builder(MindSwapSpell::new).affinity(Affinity.BAD).color(0xF9FF99).shape(GemstoneItem.Shape.WAVE)); - public static final SpellType HYDROPHOBIC = register("hydrophobic", SpellType.builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.ROCKET)); + public static final SpellType HYDROPHOBIC = register("hydrophobic", SpellType.builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).stackable().shape(GemstoneItem.Shape.ROCKET)); public static final SpellType BUBBLE = register("bubble", builder(BubbleSpell::new).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.DONUT).traits(BubbleSpell.DEFAULT_TRAITS)); public static final SpellType DISPEL_EVIL = register("dispel_evil", builder(DispellEvilSpell::new).color(0x00FF00).shape(GemstoneItem.Shape.CROSS).traits(DispellEvilSpell.DEFAULT_TRAITS)); From 771da650c425d7507b3b4a7a146557c1ec5485fc Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 20 May 2024 20:56:44 +0100 Subject: [PATCH 34/85] Implement a custom data tracker to sync values dynamically. Fixes #14 --- .../ability/magic/SpellContainer.java | 10 +- .../unicopia/entity/Creature.java | 3 - .../unicopia/entity/Equine.java | 2 - .../unicopia/entity/ItemImpl.java | 4 - .../unicopia/entity/Living.java | 9 +- .../unicopia/entity/mob/CastSpellEntity.java | 7 +- .../unicopia/mixin/MixinEntity.java | 9 -- .../unicopia/network/datasync/EffectSync.java | 111 ++++++------------ .../unicopia/projectile/MagicBeamEntity.java | 4 +- 9 files changed, 47 insertions(+), 112 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java index 0cae9891..bfb00b07 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java @@ -32,7 +32,9 @@ public interface SpellContainer { /** * Gets the active effect for this caster updating it if needed. */ - Optional get(@Nullable SpellPredicate type); + default Optional get(@Nullable SpellPredicate type) { + return stream(type).findFirst(); + } /** * Sets the active effect. @@ -73,10 +75,12 @@ public interface SpellContainer { /** * Gets all active effects for this caster updating it if needed. */ - Stream stream(); + default Stream stream() { + return stream(null); + } /** - * Gets all active effects for this caster that match the given type updating it if needed. + * Gets all active effects for this caster that match the given type. */ Stream stream(@Nullable SpellPredicate type); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index 51ad4fa5..810297d9 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -31,8 +31,6 @@ import net.minecraft.entity.SpawnGroup; import net.minecraft.entity.ai.goal.*; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.EntityAttributes; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.mob.*; import net.minecraft.entity.passive.*; import net.minecraft.entity.player.PlayerEntity; @@ -41,7 +39,6 @@ import net.minecraft.nbt.NbtElement; import net.minecraft.util.math.MathHelper; public class Creature extends Living implements WeaklyOwned.Mutable { - static final TrackedData EFFECT = net.minecraft.entity.data.DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); public static void boostrap() {} private final EntityPhysics physics; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Equine.java b/src/main/java/com/minelittlepony/unicopia/entity/Equine.java index 691bbfcf..a9cf3707 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Equine.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Equine.java @@ -19,8 +19,6 @@ public interface Equine extends NbtSerialisable, Tickable, Pro void setSpecies(Race race); - void initDataTracker(); - /** * Called at the beginning of an update cycle. */ diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java index 78b2c2e4..ae51c08c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java @@ -47,10 +47,6 @@ public class ItemImpl implements Equine { race = tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); } - @Override - public void initDataTracker() { - } - @Override public boolean onProjectileImpact(ProjectileEntity projectile) { return false; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 58dc2e00..d6f14bdb 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -76,8 +76,6 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public abstract class Living implements Equine, Caster, Transmittable { - //private static final TrackedData> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID); - protected final T entity; private final EffectSync effectDelegate; @@ -113,7 +111,7 @@ public abstract class Living implements Equine, Caste this.entity = entity; this.trackers = Trackable.of(entity).getDataTrackers(); this.tracker = trackers.getPrimaryTracker(); - this.effectDelegate = new EffectSync(this, Creature.EFFECT); + this.effectDelegate = new EffectSync(this, tracker); this.sneakingHeuristic = addTicker(new Interactable(entity::isSneaking)); this.landedHeuristic = addTicker(new Interactable(entity::isOnGround)); this.jumpingHeuristic = addTicker(new Interactable(((LivingEntityDuck)entity)::isJumping)); @@ -121,11 +119,6 @@ public abstract class Living implements Equine, Caste carrierId = tracker.startTracking(TrackableDataType.of(PacketCodec.UUID), Util.NIL_UUID); } - @Override - public void initDataTracker() { - entity.getDataTracker().startTracking(Creature.EFFECT, new NbtCompound()); - } - public Q addTicker(Q tickable) { tickers.add(Objects.requireNonNull(tickable, "tickable cannot be null")); return tickable; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 0643087f..ea3896c8 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -19,19 +19,15 @@ import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityPose; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.data.DataTracker; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.nbt.NbtCompound; import net.minecraft.text.Text; import net.minecraft.world.World; public class CastSpellEntity extends LightEmittingEntity implements Caster, WeaklyOwned.Mutable, MagicImmune { - private static final TrackedData EFFECT = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); private final EntityPhysics physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); - private final EffectSync effectDelegate = new EffectSync(this, EFFECT); + private final EffectSync effectDelegate = new EffectSync(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); private final EntityReference owner = new EntityReference<>(); @@ -45,7 +41,6 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster type, World world, CallbackInfo info) { - if (this instanceof Equine.Container c) { - c.get().initDataTracker(); - } - } - @Inject(method = "isFireImmune", at = @At("HEAD"), cancellable = true) private void onIsFireImmune(CallbackInfoReturnable info) { if (isLavaAffine() || (this instanceof Equine.Container c) && c.get().getCompositeRace().includes(Race.KIRIN)) { diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java index 36fa7a65..b2d8fb97 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java +++ b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java @@ -1,7 +1,7 @@ package com.minelittlepony.unicopia.network.datasync; -import java.util.Optional; import java.util.UUID; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -14,9 +14,11 @@ import com.minelittlepony.unicopia.ability.magic.SpellContainer; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.NbtSerialisable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; -import net.minecraft.entity.data.TrackedData; import net.minecraft.nbt.NbtCompound; /** @@ -32,19 +34,21 @@ public class EffectSync implements SpellContainer, NbtSerialisable { private final Caster owner; - private final TrackedData param; + private final DataTracker tracker; + private final DataTracker.Entry param; - @Nullable - private NbtCompound lastValue; - - public EffectSync(Caster owner, TrackedData param) { - spells = new NetworkedReferenceSet<>(Spell::getUuid, () -> new SpellNetworkedReference<>(owner)); + public EffectSync(Caster owner, DataTracker tracker) { this.owner = owner; - this.param = param; - } + this.tracker = tracker; + this.param = tracker.startTracking(TrackableDataType.of(PacketCodec.NBT), new NbtCompound()); + spells = new NetworkedReferenceSet<>(Spell::getUuid, () -> new SpellNetworkedReference<>(owner)); - public void initDataTracker() { - owner.asEntity().getDataTracker().startTracking(param, new NbtCompound()); + tracker.onBeforeSend(param, () -> { + if (spells.isDirty()) { + tracker.set(param, spells.toNbt()); + } + }); + tracker.onReceive(param, nbt -> spells.fromNbt(nbt)); } public boolean tick(Situation situation) { @@ -78,20 +82,9 @@ public class EffectSync implements SpellContainer, NbtSerialisable { return spells.containsReference(id) || spells.getReferences().anyMatch(s -> s.equalsOrContains(id)); } - @Override - public boolean contains(@Nullable SpellPredicate type) { - return read(type).findFirst().isPresent(); - } - - @Override - public Optional get(@Nullable SpellPredicate type) { - return read(type).findFirst(); - } - @Override public void put(@Nullable Spell effect) { spells.addReference(effect); - write(); if (owner instanceof UpdateCallback callback) { callback.onSpellSet(effect); } @@ -99,12 +92,7 @@ public class EffectSync implements SpellContainer, NbtSerialisable { @Override public void remove(UUID id) { - Spell spell = spells.getReference(id); - spell.setDead(); - spell.tickDying(owner); - if (spell.isDead()) { - spells.removeReference(id); - } + discard(spells.getReference(id)); } @Override @@ -113,13 +101,19 @@ public class EffectSync implements SpellContainer, NbtSerialisable { if (!test.test(spell)) { return initial; } + discard(spell); + return true; + }); + } + + private void discard(Spell spell) { + if (spell != null) { spell.setDead(); spell.tickDying(owner); if (spell.isDead()) { spells.removeReference(spell); } - return true; - }); + } } @Override @@ -135,55 +129,28 @@ public class EffectSync implements SpellContainer, NbtSerialisable { }); } - @Override - public Stream stream() { - return stream(null); - } - + @SuppressWarnings("unchecked") @Override public Stream stream(@Nullable SpellPredicate type) { - return read(type); - } - - @Override - public boolean clear() { - if (spells.clear()) { - write(); - if (owner instanceof UpdateCallback) { - ((UpdateCallback)owner).onSpellSet(null); - } - return true; - } - return false; - } - - @SuppressWarnings("unchecked") - private Stream read(@Nullable SpellPredicate type) { - if (owner.isClient()) { - spells.fromNbt(owner.asEntity().getDataTracker().get(param)); - } - write(); - if (type == null) { return (Stream)spells.getReferences(); } return (Stream)spells.getReferences().flatMap(s -> s.findMatches(type)); } - private boolean reduce(Alteration alteration) { - boolean initial = false; - for (Spell i : read(null).toList()) { - initial = alteration.apply(initial, i); + @Override + public boolean clear() { + if (spells.clear()) { + if (owner instanceof UpdateCallback c) { + c.onSpellSet(null); + } + return true; } - - write(); - return initial; + return false; } - private void write() { - if (spells.isDirty() && !owner.isClient()) { - owner.asEntity().getDataTracker().set(param, spells.toNbt()); - } + private boolean reduce(BiFunction alteration) { + return stream().toList().stream().reduce(false, alteration, (a, b) -> b); } @Override @@ -194,14 +161,10 @@ public class EffectSync implements SpellContainer, NbtSerialisable { @Override public void fromNBT(NbtCompound compound) { spells.fromNbt(compound.getCompound("spells")); - owner.asEntity().getDataTracker().set(param, spells.toNbt()); + tracker.set(param, spells.toNbt()); } public interface UpdateCallback { void onSpellSet(@Nullable Spell spell); } - - private interface Alteration { - boolean apply(boolean initial, Spell spell); - } } diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java index 7d92a756..28d0da3e 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java @@ -32,10 +32,9 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class MagicBeamEntity extends MagicProjectileEntity implements Caster, MagicImmune { - private static final TrackedData EFFECT = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); private static final TrackedData HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN); - private final EffectSync effectDelegate = new EffectSync(this, EFFECT); + private final EffectSync effectDelegate = new EffectSync(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); private final EntityPhysics physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); public MagicBeamEntity(EntityType type, World world) { @@ -55,7 +54,6 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster Date: Tue, 21 May 2024 23:33:40 +0100 Subject: [PATCH 35/85] Sync each spell individually --- .../ability/UnicornDispellAbility.java | 7 +- .../unicopia/ability/magic/Caster.java | 2 +- .../ability/magic/MultiSpellSlot.java | 131 ++++++++++++++ .../ability/magic/SingleSpellSlot.java | 68 +++++++ .../ability/magic/SpellInventory.java | 75 ++++++++ .../{SpellContainer.java => SpellSlots.java} | 102 ++++++----- .../magic/spell/AbstractDelegatingSpell.java | 89 ++++----- .../ability/magic/spell/PlaceableSpell.java | 43 ++--- .../unicopia/ability/magic/spell/Spell.java | 7 +- .../ability/magic/spell/SpellReference.java | 15 ++ .../ability/magic/spell/ThrowableSpell.java | 53 +++--- .../client/gui/DismissSpellScreen.java | 5 +- .../render/spell/PlacedSpellRenderer.java | 3 +- .../spell/SpellEffectsRenderDispatcher.java | 4 +- .../unicopia/entity/Creature.java | 2 +- .../unicopia/entity/EntityPhysics.java | 6 +- .../unicopia/entity/ItemImpl.java | 2 +- .../unicopia/entity/ItemPhysics.java | 6 +- .../unicopia/entity/Living.java | 18 +- .../unicopia/entity/mob/CastSpellEntity.java | 24 +-- .../unicopia/entity/player/PlayerPhysics.java | 2 +- .../unicopia/entity/player/Pony.java | 13 +- .../unicopia/mixin/MixinMilkBucketItem.java | 4 +- .../unicopia/network/datasync/EffectSync.java | 170 ------------------ .../network/datasync/NetworkedReference.java | 19 -- .../datasync/NetworkedReferenceSet.java | 153 ---------------- .../datasync/SpellNetworkedReference.java | 48 ----- .../unicopia/network/track/DataTracker.java | 90 +++++----- .../network/track/DataTrackerManager.java | 68 ++++--- .../network/track/MsgTrackedValues.java | 35 +++- .../unicopia/network/track/ObjectTracker.java | 144 +++++++++++++++ .../network/track/TrackableObject.java | 24 +++ .../unicopia/projectile/MagicBeamEntity.java | 29 ++- 33 files changed, 762 insertions(+), 699 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/SpellInventory.java rename src/main/java/com/minelittlepony/unicopia/ability/magic/{SpellContainer.java => SpellSlots.java} (56%) delete mode 100644 src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java delete mode 100644 src/main/java/com/minelittlepony/unicopia/network/datasync/NetworkedReference.java delete mode 100644 src/main/java/com/minelittlepony/unicopia/network/datasync/NetworkedReferenceSet.java delete mode 100644 src/main/java/com/minelittlepony/unicopia/network/datasync/SpellNetworkedReference.java create mode 100644 src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java create mode 100644 src/main/java/com/minelittlepony/unicopia/network/track/TrackableObject.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java index 61f4a3e8..36c603c2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java @@ -7,7 +7,6 @@ import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.entity.player.Pony; @@ -93,11 +92,7 @@ public class UnicornDispellAbility implements Ability { public boolean apply(Pony player, Pos data) { player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE); Caster.stream(VecHelper.findInRange(player.asEntity(), player.asWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> { - target.getSpellSlot().forEach(spell -> { - spell.setDead(); - spell.tickDying(target); - return Operation.ofBoolean(!spell.isDead()); - }); + target.getSpellSlot().clear(false); }); return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java index dc6f4ec3..86c225f1 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java @@ -40,7 +40,7 @@ public interface Caster extends Physics getPhysics(); - SpellContainer getSpellSlot(); + SpellSlots getSpellSlot(); /** * Removes the desired amount of mana or health from this caster in exchange for a spell's benefits. diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java new file mode 100644 index 00000000..c9763388 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java @@ -0,0 +1,131 @@ +package com.minelittlepony.unicopia.ability.magic; + +import java.util.UUID; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellReference; +import com.minelittlepony.unicopia.network.track.ObjectTracker; +import com.minelittlepony.unicopia.network.track.Trackable; +import com.minelittlepony.unicopia.network.track.TrackableObject; +import com.minelittlepony.unicopia.util.NbtSerialisable; +import net.minecraft.nbt.NbtCompound; + +/** + * Container for multiple spells + * + * @param The owning entity + */ +class MultiSpellSlot implements SpellSlots, NbtSerialisable { + private final Caster owner; + private final ObjectTracker> tracker; + + public MultiSpellSlot(Caster owner) { + this.owner = owner; + this.tracker = Trackable.of(owner.asEntity()).getDataTrackers().checkoutTracker(() -> new Entry<>(owner)); + } + + public ObjectTracker getTracker() { + return tracker; + } + + @Override + public boolean contains(UUID id) { + return tracker.contains(id) + || tracker.values().stream().anyMatch(s -> s.spell.equalsOrContains(id)); + } + + @Override + public void put(@Nullable Spell effect) { + if (effect != null) { + tracker.add(new Entry<>(owner, effect)); + } + } + + @Override + public void remove(UUID id, boolean force) { + tracker.remove(id, force); + } + + @Override + public Stream stream(@Nullable SpellPredicate type) { + return tracker.values().stream().flatMap(s -> s.spell.findMatches(type)); + } + + @Override + public boolean clear(boolean force) { + return tracker.clear(force); + } + + @Override + public void toNBT(NbtCompound compound) { + compound.put("spells", tracker.toNBT()); + } + + @Override + public void fromNBT(NbtCompound compound) { + tracker.fromNBT(compound.getCompound("spells")); + } + + static final class Entry implements TrackableObject { + private final Caster owner; + final SpellReference spell = new SpellReference<>(); + private Status status = Status.NEW; + + public Entry(Caster owner) { + this.owner = owner; + } + public Entry(Caster owner, T spell) { + this.owner = owner; + this.spell.set(spell); + if (owner instanceof UpdateCallback callback) { + callback.onSpellAdded(spell); + } + } + + @Override + public void discard(boolean immediate) { + if (immediate) { + spell.set(null, owner); + } else { + Spell s = spell.get(); + if (s != null) { + s.setDead(); + s.tickDying(owner); + } + } + } + + @Override + public UUID getUuid() { + return spell.get().getUuid(); + } + + @Override + public Status getStatus() { + try { + if (spell.get() == null) { + return Status.REMOVED; + } + if (spell.hasDirtySpell()) { + return Status.UPDATED; + } + return status; + } finally { + status = Status.DEFAULT; + } + } + + @Override + public NbtCompound toTrackedNbt() { + return spell.toNBT(); + } + + @Override + public void readTrackedNbt(NbtCompound compound) { + spell.fromNBT(compound); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java new file mode 100644 index 00000000..b1ba5633 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java @@ -0,0 +1,68 @@ +package com.minelittlepony.unicopia.ability.magic; + +import java.util.UUID; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.network.track.Trackable; +import com.minelittlepony.unicopia.util.NbtSerialisable; +import net.minecraft.nbt.NbtCompound; + +/** + * Container for a single spell + * + * @param The owning entity + */ +class SingleSpellSlot implements SpellSlots, NbtSerialisable { + private final Caster owner; + private final MultiSpellSlot.Entry entry; + + public SingleSpellSlot(Caster owner) { + this.owner = owner; + this.entry = new MultiSpellSlot.Entry<>(owner); + Trackable.of(owner.asEntity()).getDataTrackers().getPrimaryTracker().startTracking(entry); + } + + @Override + public boolean contains(UUID id) { + return entry.spell.equalsOrContains(id); + } + + @Override + public void put(@Nullable Spell effect) { + entry.spell.set(effect, owner); + } + + @Override + public void remove(UUID id, boolean force) { + if (contains(id)) { + entry.discard(force); + } + } + + @Override + public Stream stream(@Nullable SpellPredicate type) { + return entry.spell.findMatches(type); + } + + @Override + public boolean clear(boolean force) { + if (entry.spell.get() != null) { + entry.discard(force); + return true; + } + return false; + } + + @Override + public void toNBT(NbtCompound compound) { + compound.put("effect", entry.toTrackedNbt()); + } + + @Override + public void fromNBT(NbtCompound compound) { + entry.readTrackedNbt(compound.getCompound("effect")); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellInventory.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellInventory.java new file mode 100644 index 00000000..c5fdfc19 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellInventory.java @@ -0,0 +1,75 @@ +package com.minelittlepony.unicopia.ability.magic; + +import java.util.function.Function; + +import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.Spell; + +public class SpellInventory { + + private final Caster owner; + private final SpellSlots slots; + + public SpellInventory(Caster owner, SpellSlots slots) { + this.owner = owner; + this.slots = slots; + } + + public SpellSlots getSlots() { + return slots; + } + + public boolean tick(Situation situation) { + return tick(spell -> { + if (spell.isDying()) { + spell.tickDying(owner); + return Operation.ofBoolean(!spell.isDead()); + } + return Operation.ofBoolean(spell.tick(owner, situation)); + }); + } + + public boolean tick(Function tickAction) { + try { + return forEach(spell -> { + try { + return tickAction.apply(spell); + } catch (Throwable t) { + Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner, t); + } + return Operation.REMOVE; + }); + } catch (Exception e) { + Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner.asEntity(), e); + } + return false; + } + + /** + * Iterates active spells and optionally removes matching ones. + * + * @return True if any matching spells remain active + */ + public boolean forEach(Function test) { + return slots.reduce((initial, spell) -> { + Operation op = test.apply(spell); + if (op == Operation.REMOVE) { + slots.remove(spell.getUuid(), true); + } else { + initial |= op != Operation.SKIP; + } + return initial; + }); + } + + public enum Operation { + SKIP, + KEEP, + REMOVE; + + public static Operation ofBoolean(boolean result) { + return result ? KEEP : REMOVE; + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellSlots.java similarity index 56% rename from src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java rename to src/main/java/com/minelittlepony/unicopia/ability/magic/SpellSlots.java index bfb00b07..97d30882 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellContainer.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellSlots.java @@ -2,19 +2,56 @@ package com.minelittlepony.unicopia.ability.magic; import java.util.Optional; import java.util.UUID; -import java.util.function.Function; -import java.util.function.Predicate; +import java.util.function.BiFunction; import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.util.NbtSerialisable; + +public interface SpellSlots extends NbtSerialisable { + static SpellInventory ofUnbounded(Caster caster) { + return new SpellInventory(caster, new MultiSpellSlot(caster)); + } + + static SpellInventory ofSingle(Caster caster) { + return new SpellInventory(caster, new SingleSpellSlot(caster)); + } + + /** + * Gets all active effects for this caster that match the given type. + */ + Stream stream(@Nullable SpellPredicate type); + + /** + * Sets the active effect. + */ + void put(@Nullable Spell effect); + + /** + * Removes all effects currently active in this slot. + */ + boolean clear(boolean force); + + /** + * Cleanly removes a spell from this spell container. + * + * @param spellid ID of the spell to remove. + */ + void remove(UUID spellid, boolean force); -public interface SpellContainer { /** * Checks if a spell with the given uuid is present. */ boolean contains(UUID id); + /** + * Gets the active effect for this caster + */ + default Optional get() { + return get(null); + } + /** * Checks if any matching spells are active. */ @@ -22,13 +59,6 @@ public interface SpellContainer { return get(type).isPresent(); } - /** - * Gets the active effect for this caster updating it if needed. - */ - default Optional get() { - return get(null); - } - /** * Gets the active effect for this caster updating it if needed. */ @@ -37,23 +67,27 @@ public interface SpellContainer { } /** - * Sets the active effect. + * Removes all effects currently active in this slot. */ - void put(@Nullable Spell effect); + default boolean clear() { + return clear(false); + } /** * Cleanly removes a spell from this spell container. * * @param spellid ID of the spell to remove. */ - void remove(UUID spellid); + default void remove(UUID spellid) { + remove(spellid, false); + } /** * Removes all active effects that match or contain a matching effect. * * @return True if the collection was changed */ - default boolean removeIf(Predicate test) { + default boolean removeIf(SpellPredicate test) { return removeWhere(spell -> spell.findMatches(test).findFirst().isPresent()); } @@ -62,15 +96,15 @@ public interface SpellContainer { * * @return True if the collection was changed */ - boolean removeWhere(Predicate test); - - /** - * Iterates active spells and optionally removes matching ones. - * - * @return True if any matching spells remain active - */ - boolean forEach(Function action); - + default boolean removeWhere(SpellPredicate test) { + return reduce((initial, spell) -> { + if (test.test(spell)) { + remove(spell.getUuid()); + return true; + } + return initial; + }); + } /** * Gets all active effects for this caster updating it if needed. @@ -79,23 +113,11 @@ public interface SpellContainer { return stream(null); } - /** - * Gets all active effects for this caster that match the given type. - */ - Stream stream(@Nullable SpellPredicate type); + default boolean reduce(BiFunction alteration) { + return stream().reduce(false, alteration, (a, b) -> b); + } - /** - * Removes all effects currently active in this slot. - */ - boolean clear(); - - public enum Operation { - SKIP, - KEEP, - REMOVE; - - public static Operation ofBoolean(boolean result) { - return result ? KEEP : REMOVE; - } + public interface UpdateCallback { + void onSpellAdded(Spell spell); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index c27fb13c..70cbef36 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -1,22 +1,14 @@ package com.minelittlepony.unicopia.ability.magic.spell; import java.util.*; -import java.util.function.Function; -import java.util.function.Predicate; import java.util.stream.Stream; import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; -import com.minelittlepony.unicopia.projectile.ProjectileDelegate; - import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.EntityHitResult; - -public abstract class AbstractDelegatingSpell implements Spell, - ProjectileDelegate.ConfigurationListener, ProjectileDelegate.BlockHitListener, ProjectileDelegate.EntityHitListener { +public abstract class AbstractDelegatingSpell implements Spell { private boolean dirty; private boolean hidden; private boolean destroyed; @@ -24,21 +16,24 @@ public abstract class AbstractDelegatingSpell implements Spell, private UUID uuid = UUID.randomUUID(); private final CustomisedSpellType type; + protected final SpellReference delegate = new SpellReference<>(); public AbstractDelegatingSpell(CustomisedSpellType type) { this.type = type; } - public abstract Collection getDelegates(); - - @Override - public boolean equalsOrContains(UUID id) { - return Spell.super.equalsOrContains(id) || getDelegates().stream().anyMatch(s -> s.equalsOrContains(id)); + public final Spell getDelegate() { + return delegate.get(); } @Override - public Stream findMatches(Predicate predicate) { - return Stream.concat(Spell.super.findMatches(predicate), getDelegates().stream().flatMap(s -> s.findMatches(predicate))); + public boolean equalsOrContains(UUID id) { + return Spell.super.equalsOrContains(id) || delegate.equalsOrContains(id); + } + + @Override + public Stream findMatches(SpellPredicate predicate) { + return Stream.concat(Spell.super.findMatches(predicate), delegate.findMatches(predicate)); } @Override @@ -53,7 +48,10 @@ public abstract class AbstractDelegatingSpell implements Spell, @Override public void setDead() { - getDelegates().forEach(Spell::setDead); + Spell spell = delegate.get(); + if (spell != null) { + spell.setDead(); + } } @Override @@ -62,7 +60,7 @@ public abstract class AbstractDelegatingSpell implements Spell, @Override public boolean isDead() { - return getDelegates().isEmpty() || getDelegates().stream().allMatch(Spell::isDead); + return delegate.get() == null || delegate.get().isDead(); } @Override @@ -72,7 +70,7 @@ public abstract class AbstractDelegatingSpell implements Spell, @Override public boolean isDirty() { - return dirty || getDelegates().stream().anyMatch(Spell::isDirty); + return dirty || (delegate.get() instanceof Spell p && p.isDirty()); } @Override @@ -82,7 +80,7 @@ public abstract class AbstractDelegatingSpell implements Spell, @Override public boolean isHidden() { - return hidden || getDelegates().stream().allMatch(Spell::isHidden); + return hidden || (delegate.get() instanceof Spell p && p.isHidden()); } @Override @@ -101,40 +99,28 @@ public abstract class AbstractDelegatingSpell implements Spell, } protected void onDestroyed(Caster caster) { - getDelegates().forEach(a -> a.destroy(caster)); + if (delegate.get() instanceof Spell s) { + s.destroy(caster); + } } @Override public boolean tick(Caster source, Situation situation) { - return execute(getDelegates().stream(), a -> { - if (a.isDying()) { - a.tickDying(source); - return !a.isDead(); + if (delegate.get() instanceof Spell s) { + if (s.isDying()) { + s.tickDying(source); + return !s.isDead(); } - return a.tick(source, situation); - }); - } - - @Override - public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) { - getDelegates(BlockHitListener.PREDICATE).forEach(a -> a.onImpact(projectile, hit)); - } - - @Override - public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { - getDelegates(EntityHitListener.PREDICATE).forEach(a -> a.onImpact(projectile, hit)); - } - - @Override - public void configureProjectile(MagicProjectileEntity projectile, Caster caster) { - getDelegates(ConfigurationListener.PREDICATE).forEach(a -> a.configureProjectile(projectile, caster)); + return s.tick(source, situation) && !isDead(); + } + return !isDead(); } @Override public void toNBT(NbtCompound compound) { compound.putUuid("uuid", uuid); compound.putBoolean("hidden", hidden); - saveDelegates(compound); + compound.put("spell", delegate.toNBT()); } @Override @@ -144,18 +130,11 @@ public abstract class AbstractDelegatingSpell implements Spell, if (compound.contains("uuid")) { uuid = compound.getUuid("uuid"); } - loadDelegates(compound); + delegate.fromNBT(compound.getCompound("spell")); } - protected abstract void loadDelegates(NbtCompound compound); - - protected abstract void saveDelegates(NbtCompound compound); - - protected Stream getDelegates(Function cast) { - return getDelegates().stream().map(cast).filter(Objects::nonNull); - } - - protected static boolean execute(Stream spells, Function action) { - return spells.reduce(false, (u, a) -> action.apply(a), (a, b) -> a || b); + @Override + public final String toString() { + return "Delegate{" + getTypeAndTraits() + "}[uuid=" + uuid + ", destroyed=" + destroyed + ", hidden=" + hidden + "][spell=" + delegate.get() + "]"; } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index ab724eaa..652009c1 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -29,6 +29,11 @@ import net.minecraft.world.World; *

* The spell's effects are still powered by the casting player, so if the player dies or leaves the area, their * spell loses affect until they return. + *

+ * When cast two copies of this spell are created. One is attached to the player and is the controlling spell, + * the other is attached to a cast spell entity and placed in the world. + * + * TODO: Split this up into separate classes. */ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedSpell { /** @@ -48,11 +53,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS */ private final EntityReference castEntity = new EntityReference<>(); - /** - * The spell being cast - */ - private final SpellReference spell = new SpellReference<>(); - public float pitch; public float yaw; @@ -70,7 +70,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS } public PlaceableSpell setSpell(Spell spell) { - this.spell.set(spell); + delegate.set(spell); return this; } @@ -101,14 +101,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS return dead && deathTicks <= 0 && super.isDead(); } - @Override - public Collection getDelegates() { - Spell spell = this.spell.get(); - return spell == null ? List.of() : List.of(spell); - } - @Override public boolean tick(Caster source, Situation situation) { + System.out.println("Placed Tick: " + source + " " + source.isClient() + " " + situation); if (situation == Situation.BODY) { if (!source.isClient()) { if (dimension == null) { @@ -163,8 +158,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS CastSpellEntity entity = UEntities.CAST_SPELL.create(source.asWorld()); Vec3d pos = getPosition().orElse(position.orElse(source.asEntity().getPos())); entity.updatePositionAndAngles(pos.x, pos.y, pos.z, source.asEntity().getYaw(), source.asEntity().getPitch()); - PlaceableSpell copy = spell.get().toPlaceable(); - if (spell.get() instanceof PlacementDelegate delegate) { + PlaceableSpell copy = delegate.get().toPlaceable(); + if (delegate.get() instanceof PlacementDelegate delegate) { delegate.onPlaced(source, copy, entity); } entity.getSpellSlot().put(copy); @@ -181,8 +176,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS public void setOrientation(float pitch, float yaw) { this.pitch = -90 - pitch; this.yaw = -yaw; - getDelegates(spell -> spell instanceof OrientedSpell o ? o : null) - .forEach(spell -> spell.setOrientation(pitch, yaw)); + if (delegate.get() instanceof OrientedSpell o) { + o.setOrientation(pitch, yaw); + } setDirty(); } @@ -192,8 +188,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS castEntity.ifPresent(source.asWorld(), entity -> { entity.updatePositionAndAngles(position.x, position.y, position.z, entity.getYaw(), entity.getPitch()); }); - getDelegates(spell -> spell instanceof PlaceableSpell o ? o : null) - .forEach(spell -> spell.setPosition(source, position)); + if (delegate.get() instanceof PlaceableSpell o) { + o.setPosition(source, position); + } setDirty(); } @@ -271,16 +268,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS } } - @Override - protected void loadDelegates(NbtCompound compound) { - spell.fromNBT(compound.getCompound("spell")); - } - - @Override - protected void saveDelegates(NbtCompound compound) { - compound.put("spell", spell.toNBT()); - } - @Override public PlaceableSpell toPlaceable() { return this; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index 30a93dd2..4258b079 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -1,7 +1,6 @@ package com.minelittlepony.unicopia.ability.magic.spell; import java.util.UUID; -import java.util.function.Predicate; import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; @@ -11,6 +10,7 @@ import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.util.NbtSerialisable; @@ -53,8 +53,9 @@ public interface Spell extends NbtSerialisable, Affine { /** * Returns an optional containing the spell that matched the given predicate. */ - default Stream findMatches(Predicate predicate) { - return predicate.test(this) ? Stream.of(this) : Stream.empty(); + @SuppressWarnings("unchecked") + default Stream findMatches(SpellPredicate predicate) { + return predicate == null || predicate.test(this) ? Stream.of((T)this) : Stream.empty(); } /** diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java index c222de90..6c3d22e9 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java @@ -1,9 +1,13 @@ package com.minelittlepony.unicopia.ability.magic.spell; import java.util.Objects; +import java.util.UUID; +import java.util.stream.Stream; + import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.util.NbtSerialisable; import net.minecraft.nbt.NbtCompound; @@ -40,6 +44,17 @@ public final class SpellReference implements NbtSerialisable { return true; } + public boolean equalsOrContains(UUID id) { + @Nullable T spell = get(); + return spell != null && spell.equalsOrContains(id); + } + + @SuppressWarnings("unchecked") + public Stream findMatches(SpellPredicate predicate) { + @Nullable T spell = get(); + return spell != null ? (predicate == null ? Stream.of((V)spell) : spell.findMatches(predicate)) : Stream.empty(); + } + @Override public void toNBT(NbtCompound compound) { if (spell != null && !spell.isDead()) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java index 3e60cba0..b823cf6f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java @@ -1,34 +1,30 @@ package com.minelittlepony.unicopia.ability.magic.spell; -import java.util.Collection; -import java.util.List; import java.util.Optional; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.projectile.MagicBeamEntity; -import net.minecraft.nbt.NbtCompound; +import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; +import com.minelittlepony.unicopia.projectile.ProjectileDelegate; + +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; import net.minecraft.world.World; -public final class ThrowableSpell extends AbstractDelegatingSpell { - - private final SpellReference spell = new SpellReference<>(); +public final class ThrowableSpell extends AbstractDelegatingSpell implements + ProjectileDelegate.ConfigurationListener, ProjectileDelegate.BlockHitListener, ProjectileDelegate.EntityHitListener { public ThrowableSpell(CustomisedSpellType type) { super(type); } public ThrowableSpell setSpell(Spell spell) { - this.spell.set(spell); + delegate.set(spell); return this; } - @Override - public Collection getDelegates() { - return List.of(spell.get()); - } - @Override public boolean apply(Caster source) { return throwProjectile(source).isPresent(); @@ -57,7 +53,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell { return Optional.empty(); } - return Optional.ofNullable(spell.get().prepareForCast(caster, CastingMethod.STORED)).map(s -> { + return Optional.ofNullable(delegate.get().prepareForCast(caster, CastingMethod.STORED)).map(s -> { MagicBeamEntity projectile = new MagicBeamEntity(world, caster.asEntity(), divergance, s); configureProjectile(projectile, caster); @@ -67,16 +63,6 @@ public final class ThrowableSpell extends AbstractDelegatingSpell { }); } - @Override - protected void loadDelegates(NbtCompound compound) { - spell.fromNBT(compound.getCompound("spell")); - } - - @Override - protected void saveDelegates(NbtCompound compound) { - compound.put("spell", spell.toNBT()); - } - @Override public ThrowableSpell toThrowable() { return this; @@ -90,4 +76,25 @@ public final class ThrowableSpell extends AbstractDelegatingSpell { @Override public void setHidden(boolean hidden) { } + + @Override + public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) { + if (delegate.get() instanceof BlockHitListener listener) { + listener.onImpact(projectile, hit); + } + } + + @Override + public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { + if (delegate.get() instanceof EntityHitListener listener) { + listener.onImpact(projectile, hit); + } + } + + @Override + public void configureProjectile(MagicProjectileEntity projectile, Caster caster) { + if (delegate.get() instanceof ConfigurationListener listener) { + listener.configureProjectile(projectile, caster); + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 4910981f..85028253 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -137,10 +137,7 @@ public class DismissSpellScreen extends GameGui { } private Spell getActualSpell() { - if (spell instanceof AbstractDelegatingSpell) { - return ((AbstractDelegatingSpell)spell).getDelegates().stream().findFirst().orElse(spell); - } - return spell; + return spell instanceof AbstractDelegatingSpell s && s.getDelegate() instanceof Spell p ? p : spell; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java index ee08654d..f0676140 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java @@ -34,8 +34,9 @@ public class PlacedSpellRenderer extends SpellRenderer { matrices.push(); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-castSpell.getYaw())); + Spell delegate = spell.getDelegate(); - for (Spell delegate : spell.getDelegates()) { + if (delegate != null) { renderAmbientEffects(matrices, vertices, spell, delegate, caster, light, animationProgress, tickDelta); matrices.push(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index b2bcf87a..423a8888 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; @@ -87,9 +86,8 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader return; } - caster.getSpellSlot().forEach(spell -> { + caster.getSpellSlot().stream().forEach(spell -> { render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); - return Operation.SKIP; }); if (client.getEntityRenderDispatcher().shouldRenderHitboxes() diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index 810297d9..bd0929c6 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -69,7 +69,7 @@ public class Creature extends Living implements WeaklyOwned.Mutabl public Creature(LivingEntity entity) { super(entity); - physics = new EntityPhysics<>(entity, tracker); + physics = new EntityPhysics<>(entity); addTicker(physics); addTicker(this::updateConsumption); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java index 2aba94c8..b08ce4cd 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.entity; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.Trackable; import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.Tickable; @@ -27,10 +28,9 @@ public class EntityPhysics implements Physics, Copyable gravity; - public EntityPhysics(T entity, DataTracker tracker) { + public EntityPhysics(T entity) { this.entity = entity; - this.tracker = tracker; - //this.gravity = gravity; + this.tracker = Trackable.of(entity).getDataTrackers().getPrimaryTracker(); gravity = tracker.startTracking(TrackableDataType.of(PacketCodec.FLOAT), 1F); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java index ae51c08c..a4c30f52 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java @@ -42,7 +42,7 @@ public class ItemImpl implements Equine { this.entity = owner; this.trackers = Trackable.of(entity).getDataTrackers(); this.tracker = trackers.getPrimaryTracker(); - this.physics = new ItemPhysics(owner, tracker); + this.physics = new ItemPhysics(owner); race = tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java index 04b5425d..77af67da 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java @@ -1,12 +1,10 @@ package com.minelittlepony.unicopia.entity; -import com.minelittlepony.unicopia.network.track.DataTracker; - import net.minecraft.entity.ItemEntity; class ItemPhysics extends EntityPhysics { - public ItemPhysics(ItemEntity entity, DataTracker tracker) { - super(entity, tracker); + public ItemPhysics(ItemEntity entity) { + super(entity); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index d6f14bdb..029922b9 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -12,7 +12,8 @@ import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Ability; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.SpellContainer; +import com.minelittlepony.unicopia.ability.magic.SpellInventory; +import com.minelittlepony.unicopia.ability.magic.SpellSlots; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; @@ -30,7 +31,6 @@ import com.minelittlepony.unicopia.input.Interactable; import com.minelittlepony.unicopia.item.GlassesItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; -import com.minelittlepony.unicopia.network.datasync.EffectSync; import com.minelittlepony.unicopia.network.datasync.Transmittable; import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.network.track.DataTrackerManager; @@ -78,7 +78,7 @@ import net.minecraft.util.math.Vec3d; public abstract class Living implements Equine, Caster, Transmittable { protected final T entity; - private final EffectSync effectDelegate; + private final SpellInventory spells; private final Interactable sneakingHeuristic; private final Interactable landedHeuristic; @@ -111,7 +111,7 @@ public abstract class Living implements Equine, Caste this.entity = entity; this.trackers = Trackable.of(entity).getDataTrackers(); this.tracker = trackers.getPrimaryTracker(); - this.effectDelegate = new EffectSync(this, tracker); + this.spells = SpellSlots.ofUnbounded(this); this.sneakingHeuristic = addTicker(new Interactable(entity::isSneaking)); this.landedHeuristic = addTicker(new Interactable(entity::isOnGround)); this.jumpingHeuristic = addTicker(new Interactable(((LivingEntityDuck)entity)::isJumping)); @@ -149,8 +149,8 @@ public abstract class Living implements Equine, Caste } @Override - public SpellContainer getSpellSlot() { - return effectDelegate; + public SpellSlots getSpellSlot() { + return spells.getSlots(); } public Enchantments getEnchants() { @@ -216,7 +216,7 @@ public abstract class Living implements Equine, Caste @Override public void tick() { tickers.forEach(Tickable::tick); - effectDelegate.tick(Situation.BODY); + spells.tick(Situation.BODY); if (!(entity instanceof PlayerEntity)) { if (!entity.hasVehicle() && getCarrierId().isPresent() && !asWorld().isClient && entity.age % 10 == 0) { @@ -486,14 +486,14 @@ public abstract class Living implements Equine, Caste @Override public void toNBT(NbtCompound compound) { enchants.toNBT(compound); - effectDelegate.toNBT(compound); + spells.getSlots().toNBT(compound); toSyncronisedNbt(compound); } @Override public void fromNBT(NbtCompound compound) { enchants.fromNBT(compound); - effectDelegate.fromNBT(compound); + spells.getSlots().fromNBT(compound); fromSynchronizedNbt(compound); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index ea3896c8..b5ec2dd4 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -3,7 +3,8 @@ package com.minelittlepony.unicopia.entity.mob; import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Levelled; -import com.minelittlepony.unicopia.ability.magic.SpellContainer; +import com.minelittlepony.unicopia.ability.magic.SpellInventory; +import com.minelittlepony.unicopia.ability.magic.SpellSlots; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; @@ -11,9 +12,6 @@ import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.entity.Physics; -import com.minelittlepony.unicopia.network.datasync.EffectSync; -import com.minelittlepony.unicopia.network.track.Trackable; - import net.minecraft.entity.Entity; import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityPose; @@ -25,9 +23,9 @@ import net.minecraft.world.World; public class CastSpellEntity extends LightEmittingEntity implements Caster, WeaklyOwned.Mutable, MagicImmune { - private final EntityPhysics physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); + private final EntityPhysics physics = new EntityPhysics<>(this); - private final EffectSync effectDelegate = new EffectSync(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); + private final SpellInventory spells = SpellSlots.ofSingle(this); private final EntityReference owner = new EntityReference<>(); @@ -65,7 +63,7 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster { - tag.put("effect", Spell.writeNbt(effect)); - }); + spells.getSlots().toNBT(tag); } @Override @@ -147,9 +143,7 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster implements Tickab private Lerp windStrength = new Lerp(0); public PlayerPhysics(Pony pony, DataTracker tracker) { - super(pony.asEntity(), tracker); + super(pony.asEntity()); this.pony = pony; dimensions = new PlayerDimensions(pony, this); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 2527bf47..b819834e 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.client.render.PlayerPoser.AnimationInstance; import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.*; import com.minelittlepony.unicopia.ability.magic.*; +import com.minelittlepony.unicopia.ability.magic.SpellSlots.UpdateCallback; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.RageAbilitySpell; @@ -33,7 +34,6 @@ import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.util.*; import com.minelittlepony.unicopia.network.*; -import com.minelittlepony.unicopia.network.datasync.EffectSync.UpdateCallback; import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.server.world.UGameRules; @@ -929,14 +929,11 @@ public class Pony extends Living implements Copyable, Update } @Override - public void onSpellSet(@Nullable Spell spell) { - if (spell != null) { - if (spell.getAffinity() == Affinity.BAD && entity.getWorld().random.nextInt(20) == 0) { - getCorruption().add(entity.getRandom().nextBetween(1, 10)); - } - getCorruption().add(((int)spell.getTypeAndTraits().traits().getCorruption() * 10) + spell.getTypeAndTraits().type().getAffinity().getCorruption()); - setDirty(); + public void onSpellAdded(Spell spell) { + if (spell.getAffinity() == Affinity.BAD && entity.getWorld().random.nextInt(20) == 0) { + getCorruption().add(entity.getRandom().nextBetween(1, 10)); } + getCorruption().add(((int)spell.getTypeAndTraits().traits().getCorruption() * 10) + spell.getTypeAndTraits().type().getAffinity().getCorruption()); } public boolean isClientPlayer() { diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinMilkBucketItem.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinMilkBucketItem.java index 7c9bd778..9bf38549 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinMilkBucketItem.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinMilkBucketItem.java @@ -6,7 +6,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.SpellContainer; +import com.minelittlepony.unicopia.ability.magic.SpellSlots; import net.minecraft.entity.LivingEntity; import net.minecraft.item.Item; @@ -20,6 +20,6 @@ abstract class MixinMilkBucketItem extends Item { @Inject(method = "finishUsing", at = @At("HEAD"), cancellable = true) private void finishUsing(ItemStack stack, World world, LivingEntity entity, CallbackInfoReturnable info) { - Caster.of(entity).map(Caster::getSpellSlot).ifPresent(SpellContainer::clear); + Caster.of(entity).map(Caster::getSpellSlot).ifPresent(SpellSlots::clear); } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java deleted file mode 100644 index b2d8fb97..00000000 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.minelittlepony.unicopia.network.datasync; - -import java.util.UUID; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import org.jetbrains.annotations.Nullable; - -import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.SpellContainer; -import com.minelittlepony.unicopia.ability.magic.SpellPredicate; -import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; -import com.minelittlepony.unicopia.network.track.DataTracker; -import com.minelittlepony.unicopia.network.track.TrackableDataType; -import com.minelittlepony.unicopia.util.NbtSerialisable; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; - -import net.minecraft.nbt.NbtCompound; - -/** - * Synchronisation class for spells. - * Since we can't have our own serializers, we have to intelligently - * determine whether to update it from an nbt tag. - * - * @param The owning entity - */ -public class EffectSync implements SpellContainer, NbtSerialisable { - - private final NetworkedReferenceSet spells; - - private final Caster owner; - - private final DataTracker tracker; - private final DataTracker.Entry param; - - public EffectSync(Caster owner, DataTracker tracker) { - this.owner = owner; - this.tracker = tracker; - this.param = tracker.startTracking(TrackableDataType.of(PacketCodec.NBT), new NbtCompound()); - spells = new NetworkedReferenceSet<>(Spell::getUuid, () -> new SpellNetworkedReference<>(owner)); - - tracker.onBeforeSend(param, () -> { - if (spells.isDirty()) { - tracker.set(param, spells.toNbt()); - } - }); - tracker.onReceive(param, nbt -> spells.fromNbt(nbt)); - } - - public boolean tick(Situation situation) { - return tick(spell -> { - if (spell.isDying()) { - spell.tickDying(owner); - return Operation.ofBoolean(!spell.isDead()); - } - return Operation.ofBoolean(spell.tick(owner, situation)); - }); - } - - public boolean tick(Function tickAction) { - try { - return forEach(spell -> { - try { - return tickAction.apply(spell); - } catch (Throwable t) { - Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner, t); - } - return Operation.REMOVE; - }); - } catch (Exception e) { - Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner.asEntity(), e); - } - return false; - } - - @Override - public boolean contains(UUID id) { - return spells.containsReference(id) || spells.getReferences().anyMatch(s -> s.equalsOrContains(id)); - } - - @Override - public void put(@Nullable Spell effect) { - spells.addReference(effect); - if (owner instanceof UpdateCallback callback) { - callback.onSpellSet(effect); - } - } - - @Override - public void remove(UUID id) { - discard(spells.getReference(id)); - } - - @Override - public boolean removeWhere(Predicate test) { - return reduce((initial, spell) -> { - if (!test.test(spell)) { - return initial; - } - discard(spell); - return true; - }); - } - - private void discard(Spell spell) { - if (spell != null) { - spell.setDead(); - spell.tickDying(owner); - if (spell.isDead()) { - spells.removeReference(spell); - } - } - } - - @Override - public boolean forEach(Function test) { - return reduce((initial, effect) -> { - Operation op = test.apply(effect); - if (op == Operation.REMOVE) { - spells.removeReference(effect); - } else { - initial |= op != Operation.SKIP; - } - return initial; - }); - } - - @SuppressWarnings("unchecked") - @Override - public Stream stream(@Nullable SpellPredicate type) { - if (type == null) { - return (Stream)spells.getReferences(); - } - return (Stream)spells.getReferences().flatMap(s -> s.findMatches(type)); - } - - @Override - public boolean clear() { - if (spells.clear()) { - if (owner instanceof UpdateCallback c) { - c.onSpellSet(null); - } - return true; - } - return false; - } - - private boolean reduce(BiFunction alteration) { - return stream().toList().stream().reduce(false, alteration, (a, b) -> b); - } - - @Override - public void toNBT(NbtCompound compound) { - compound.put("spells", spells.toNbt()); - } - - @Override - public void fromNBT(NbtCompound compound) { - spells.fromNbt(compound.getCompound("spells")); - tracker.set(param, spells.toNbt()); - } - - public interface UpdateCallback { - void onSpellSet(@Nullable Spell spell); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/NetworkedReference.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/NetworkedReference.java deleted file mode 100644 index cb1a42d3..00000000 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/NetworkedReference.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.minelittlepony.unicopia.network.datasync; - -import java.util.Optional; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.nbt.NbtCompound; - -public interface NetworkedReference { - Optional getReference(); - - void updateReference(@Nullable T newValue); - - boolean fromNbt(NbtCompound comp); - - NbtCompound toNbt(); - - boolean isDirty(); -} diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/NetworkedReferenceSet.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/NetworkedReferenceSet.java deleted file mode 100644 index 90582e52..00000000 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/NetworkedReferenceSet.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.minelittlepony.unicopia.network.datasync; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Stream; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; -import net.minecraft.nbt.NbtList; -import net.minecraft.nbt.NbtString; - -public class NetworkedReferenceSet { - - private final List ids = new ArrayList<>(); - - private final Map> values = new HashMap<>(); - - private final Function uuidConverter; - private final Supplier> factory; - - private boolean dirty; - private boolean reading; - - public NetworkedReferenceSet(Function uuidConverter, Supplier> factory) { - this.uuidConverter = uuidConverter; - this.factory = factory; - } - - public synchronized boolean containsReference(UUID id) { - return ids.contains(id); - } - - public synchronized Stream getReferences() { - return ids.stream().map(id -> values.get(id)) - .filter(Objects::nonNull) - .map(a -> a.getReference()) - .filter(Optional::isPresent) - .map(Optional::get); - } - - public synchronized boolean clear() { - dirty |= !ids.isEmpty() || !values.isEmpty(); - ids.clear(); - try { - reading = true; - for (NetworkedReference reference : values.values()) { - reference.updateReference(null); - } - } finally { - reading = false; - values.clear(); - } - return dirty; - } - - public void addReference(@Nullable T newValue) { - if (newValue != null) { - addReference(uuidConverter.apply(newValue)).updateReference(newValue); - } - } - - private synchronized NetworkedReference addReference(UUID newValue) { - return values.computeIfAbsent(newValue, id -> { - dirty = true; - ids.remove(id); - ids.add(0, id); - return factory.get(); - }); - } - - public void removeReference(@Nullable T oldValue) { - if (oldValue != null) { - removeReference(uuidConverter.apply(oldValue)); - } - } - - @Nullable - synchronized T getReference(UUID id) { - NetworkedReference i = values.get(id); - return i == null ? null : i.getReference().orElse(null); - } - - synchronized void removeReference(UUID id) { - dirty |= ids.remove(id); - NetworkedReference i = values.remove(id); - if (i != null) { - dirty = true; - try { - reading = true; - i.updateReference(null); - } finally { - reading = false; - } - } - } - - public boolean fromNbt(NbtCompound comp) { - if (reading) { - return false; - } - reading = true; - try { - List incoming = new ArrayList<>(); - comp.getList("keys", NbtElement.STRING_TYPE).forEach(key -> { - incoming.add(UUID.fromString(key.asString())); - }); - - ids.stream().filter(id -> !incoming.contains(id)).toList().forEach(this::removeReference); - - boolean[] send = new boolean[1]; - incoming.forEach(key -> { - NetworkedReference i = addReference(key); - send[0] |= i.fromNbt(comp.getCompound(key.toString())); - if (i.getReference().isEmpty()) { - removeReference(key); - } - }); - dirty = send[0]; - return send[0]; - } finally { - reading = false; - } - } - - public synchronized NbtCompound toNbt() { - NbtCompound tag = new NbtCompound(); - NbtList ids = new NbtList(); - this.ids.forEach(id -> { - String sid = id.toString(); - NetworkedReference ref = values.get(id); - if (ref != null) { - ids.add(NbtString.of(sid)); - tag.put(sid, values.get(id).toNbt()); - } - }); - tag.put("keys", ids); - dirty = false; - return tag; - } - - public synchronized boolean isDirty() { - return dirty || values.values().stream().anyMatch(NetworkedReference::isDirty); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/SpellNetworkedReference.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/SpellNetworkedReference.java deleted file mode 100644 index fbc8ba3b..00000000 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/SpellNetworkedReference.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.minelittlepony.unicopia.network.datasync; - -import java.util.Optional; -import org.jetbrains.annotations.Nullable; - -import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; -import com.minelittlepony.unicopia.ability.magic.spell.SpellReference; - -import net.minecraft.nbt.NbtCompound; - -public class SpellNetworkedReference implements NetworkedReference { - private final SpellReference currentValue = new SpellReference<>(); - private final Caster owner; - private boolean dirty; - - public SpellNetworkedReference(Caster owner) { - this.owner = owner; - } - - @Override - public Optional getReference() { - return Optional.ofNullable(currentValue.get()); - } - - @Override - public void updateReference(@Nullable T newValue) { - dirty |= currentValue.set(newValue, owner); - } - - @Override - public boolean fromNbt(NbtCompound comp) { - dirty = false; - currentValue.fromNBT(comp, owner.isClient()); - return isDirty(); - } - - @Override - public NbtCompound toNbt() { - dirty = false; - return currentValue.toNBT(); - } - - @Override - public boolean isDirty() { - return !owner.isClient() && (dirty || currentValue.hasDirtySpell()); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index 7aa6dc99..1c86e164 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -3,21 +3,22 @@ package com.minelittlepony.unicopia.network.track; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.function.Consumer; - import org.jetbrains.annotations.Nullable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; public class DataTracker { private final List> codecs = new ObjectArrayList<>(); - private final Int2ObjectOpenHashMap> loadCallbacks = new Int2ObjectOpenHashMap<>(); - private final Int2ObjectOpenHashMap writethroughCallback = new Int2ObjectOpenHashMap<>(); private IntSet dirtyIndices = new IntOpenHashSet(); + private Int2ObjectMap persistentObjects = new Int2ObjectOpenHashMap<>(); private final DataTrackerManager manager; private boolean initial = true; @@ -29,20 +30,18 @@ public class DataTracker { this.id = id; } + public Entry startTracking(T value) { + Entry entry = startTracking(TrackableDataType.of(PacketCodec.NBT), value.toTrackedNbt()); + persistentObjects.put(entry.id(), value); + return entry; + } + public Entry startTracking(TrackableDataType type, T initialValue) { Entry entry = new Entry<>(codecs.size()); codecs.add(new Pair<>(entry.id(), type, initialValue)); return entry; } - public void onReceive(Entry entry, Consumer loadCallback) { - loadCallbacks.put(entry.id(), loadCallback); - } - - public void onBeforeSend(Entry entry, Runnable action) { - writethroughCallback.put(entry.id(), action); - } - @SuppressWarnings("unchecked") private Pair getPair(Entry entry) { return (Pair)codecs.get(entry.id()); @@ -66,59 +65,58 @@ public class DataTracker { } } + @SuppressWarnings("unchecked") @Nullable - synchronized MsgTrackedValues.TrackerEntries getDirtyPairs() { - writethroughCallback.values().forEach(Runnable::run); + synchronized void getDirtyPairs(List output) { + for (var entry : persistentObjects.int2ObjectEntrySet()) { + int key = entry.getIntKey(); + TrackableObject.Status status = entry.getValue().getStatus(); + if (status == TrackableObject.Status.NEW || status == TrackableObject.Status.UPDATED) { + ((Pair)codecs.get(key)).value = entry.getValue().toTrackedNbt(); + dirtyIndices.add(key); + } + } if (initial) { initial = false; dirtyIndices = new IntOpenHashSet(); - return new MsgTrackedValues.TrackerEntries(id, true, codecs); + output.add(new MsgTrackedValues.TrackerEntries(id, true, codecs)); + } else if (!dirtyIndices.isEmpty()) { + IntSet toSend = dirtyIndices; + dirtyIndices = new IntOpenHashSet(); + List> pairs = new ArrayList<>(); + for (int i : toSend) { + pairs.add(codecs.get(i)); + } + output.add(new MsgTrackedValues.TrackerEntries(id, false, pairs)); } - - if (dirtyIndices.isEmpty()) { - return null; - } - - IntSet toSend = dirtyIndices; - dirtyIndices = new IntOpenHashSet(); - List> pairs = new ArrayList<>(); - for (int i : toSend) { - pairs.add(codecs.get(i)); - } - return new MsgTrackedValues.TrackerEntries(id, false, pairs); } - @SuppressWarnings("unchecked") - synchronized void load(boolean wipe, List> values) { - if (wipe) { + synchronized void load(MsgTrackedValues.TrackerEntries values) { + if (values.wipe()) { codecs.clear(); - codecs.addAll(values); - for (var value : values) { - Consumer callback = loadCallbacks.get(value.id); - if (callback != null) { - ((Consumer)callback).accept(value.value); + codecs.addAll(values.values()); + for (var entry : persistentObjects.int2ObjectEntrySet()) { + Pair pair = codecs.get(entry.getIntKey()); + if (pair != null) { + entry.getValue().readTrackedNbt((NbtCompound)pair.value); } } } else { - values.forEach(value -> { + for (var value : values.values()) { if (value.id >= 0 && value.id < codecs.size()) { if (codecs.get(value.id).type == value.type) { codecs.set(value.id, value); - Consumer callback = loadCallbacks.get(value.id); - if (callback != null) { - ((Consumer)callback).accept(value.value); + TrackableObject o = persistentObjects.get(value.id); + if (o != null) { + o.readTrackedNbt((NbtCompound)value.value); } } } - }); + } } } - public void close() { - manager.closeTracker(id); - } - public record Entry(int id) {} static class Pair { private final TrackableDataType type; @@ -142,4 +140,8 @@ public class DataTracker { type.write(buffer, value); } } + + public interface Updater { + void update(T t); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java index 10f7b83a..4f945917 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -2,22 +2,19 @@ package com.minelittlepony.unicopia.network.track; import java.util.ArrayList; import java.util.List; +import java.util.function.Supplier; import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.util.Tickable; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.entity.Entity; public class DataTrackerManager implements Tickable { private final Entity entity; final boolean isClient; - private final Int2ObjectOpenHashMap trackers = new Int2ObjectOpenHashMap<>(); - - private IntSet discardedTrackers = new IntOpenHashSet(); - private int nextId = 0; + private final List trackers = new ObjectArrayList<>(); + private final List> objectTrackers = new ObjectArrayList<>(); private final DataTracker primaryTracker = checkoutTracker(); @@ -31,20 +28,15 @@ public class DataTrackerManager implements Tickable { } public synchronized DataTracker checkoutTracker() { - DataTracker tracker = new DataTracker(this, nextId++); - trackers.put(tracker.id, tracker); + DataTracker tracker = new DataTracker(this, trackers.size()); + trackers.add(tracker); return tracker; } - synchronized void closeTracker(int id) { - if (id <= 0) { - return; - } - - trackers.remove(id); - if (!isClient) { - discardedTrackers.add(id); - } + public synchronized ObjectTracker checkoutTracker(Supplier objFunction) { + ObjectTracker tracker = new ObjectTracker<>(objectTrackers.size(), objFunction); + objectTrackers.add(tracker); + return tracker; } @Override @@ -53,35 +45,41 @@ public class DataTrackerManager implements Tickable { return; } - synchronized (this) { - List toTransmit = new ArrayList<>(); + List toTransmit = new ArrayList<>(); + List objToTransmit = new ArrayList<>(); - for (var entry : trackers.int2ObjectEntrySet()) { - MsgTrackedValues.TrackerEntries dirtyPairs = entry.getValue().getDirtyPairs(); - if (dirtyPairs != null) { - toTransmit.add(dirtyPairs); - } + synchronized (this) { + for (var entry : trackers) { + entry.getDirtyPairs(toTransmit); } - if (!toTransmit.isEmpty() || !discardedTrackers.isEmpty()) { - MsgTrackedValues packet = new MsgTrackedValues(entity.getId(), toTransmit, discardedTrackers.toIntArray()); - discardedTrackers = new IntOpenHashSet(); + for (var entry : objectTrackers) { + entry.getDirtyPairs(objToTransmit); + } + + if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) { + MsgTrackedValues packet = new MsgTrackedValues( + entity.getId(), + objToTransmit, + toTransmit + ); Channel.SERVER_TRACKED_ENTITY_DATA.sendToSurroundingPlayers(packet, entity); } } } synchronized void load(MsgTrackedValues packet) { - for (int id : packet.removedTrackers()) { - closeTracker(id); - } for (var update : packet.updatedTrackers()) { DataTracker tracker = trackers.get(update.id()); - if (tracker == null) { - tracker = new DataTracker(this, update.id()); - trackers.put(update.id(), tracker); + if (tracker != null) { + tracker.load(update); + } + } + for (var update : packet.updatedObjects()) { + ObjectTracker tracker = objectTrackers.get(update.id()); + if (tracker != null) { + tracker.load(update); } - tracker.load(update.wipe(), update.values()); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java index 7f8d16e4..2a2800fb 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java @@ -1,27 +1,38 @@ package com.minelittlepony.unicopia.network.track; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + import com.sollace.fabwork.api.packets.HandledPacket; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; public record MsgTrackedValues( int owner, - List updatedTrackers, - int[] removedTrackers + List updatedObjects, + List updatedTrackers ) implements HandledPacket { public MsgTrackedValues(PacketByteBuf buffer) { - this(buffer.readInt(), buffer.readCollection(ArrayList::new, TrackerEntries::new), buffer.readIntArray()); + this( + buffer.readInt(), + buffer.readCollection(ArrayList::new, TrackerObjects::new), + buffer.readCollection(ArrayList::new, TrackerEntries::new) + ); } @Override public void toBuffer(PacketByteBuf buffer) { buffer.writeInt(owner); + buffer.writeCollection(updatedObjects, (buf, obj) -> obj.write(buf)); buffer.writeCollection(updatedTrackers, (buf, tracker) -> tracker.write(buf)); - buffer.writeIntArray(removedTrackers); } @Override @@ -32,6 +43,22 @@ public record MsgTrackedValues( } } + public record TrackerObjects(int id, Set removedValues, Map values) { + public TrackerObjects(PacketByteBuf buffer) { + this( + buffer.readInt(), + buffer.readCollection(HashSet::new, PacketByteBuf::readUuid), + buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketByteBuf::readNbt) + ); + } + + public void write(PacketByteBuf buffer) { + buffer.writeInt(id); + buffer.writeCollection(removedValues, PacketByteBuf::writeUuid); + buffer.writeMap(values, PacketByteBuf::writeUuid, PacketByteBuf::writeNbt); + } + } + public record TrackerEntries(int id, boolean wipe, List> values) { public TrackerEntries(PacketByteBuf buffer) { this(buffer.readInt(), buffer.readBoolean(), buffer.readCollection(ArrayList::new, DataTracker.Pair::new)); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java new file mode 100644 index 00000000..b4d00151 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java @@ -0,0 +1,144 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.util.NbtSerialisable; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.Util; + +public class ObjectTracker implements NbtSerialisable { + private final Map trackedObjects = new Object2ObjectOpenHashMap<>(); + private volatile Map quickAccess = Map.of(); + + private final int id; + private final Supplier constructor; + + public ObjectTracker(int id, Supplier constructor) { + this.id = id; + this.constructor = constructor; + } + + public Set keySet() { + return quickAccess.keySet(); + } + + public Collection values() { + return quickAccess.values(); + } + + @Nullable + public T get(UUID id) { + return quickAccess.get(id); + } + + @Nullable + public T remove(UUID id, boolean immediate) { + T entry = quickAccess.get(id); + if (entry != null) { + entry.discard(immediate); + } + return entry; + } + + public boolean contains(UUID id) { + return quickAccess.containsKey(id); + } + + public boolean isEmpty() { + return quickAccess.isEmpty(); + } + + public boolean clear(boolean immediate) { + if (isEmpty()) { + return false; + } + values().forEach(value -> value.discard(immediate)); + return true; + } + + public synchronized void add(T obj) { + trackedObjects.put(obj.getUuid(), obj); + quickAccess = Map.copyOf(trackedObjects); + } + + synchronized void getDirtyPairs(List output) { + if (!trackedObjects.isEmpty()) { + Map trackableCompounds = new HashMap<>(); + Set removedTrackableObjects = new HashSet<>(); + trackedObjects.entrySet().removeIf(object -> { + TrackableObject.Status status = object.getValue().getStatus(); + if (status == TrackableObject.Status.REMOVED) { + removedTrackableObjects.add(object.getKey()); + } else if (status != TrackableObject.Status.DEFAULT) { + trackableCompounds.put(object.getKey(), object.getValue().toTrackedNbt()); + } + return status == TrackableObject.Status.REMOVED; + }); + quickAccess = Map.copyOf(trackedObjects); + + if (!trackableCompounds.isEmpty() || !removedTrackableObjects.isEmpty()) { + output.add(new MsgTrackedValues.TrackerObjects(id, removedTrackableObjects, trackableCompounds)); + } + } + } + + synchronized void load(MsgTrackedValues.TrackerObjects objects) { + objects.removedValues().forEach(removedId -> { + T o = trackedObjects.remove(removedId); + if (o != null) { + o.discard(true); + } + }); + objects.values().forEach((id, nbt) -> { + T o = trackedObjects.get(id); + if (o == null) { + o = constructor.get(); + trackedObjects.put(id, o); + } + o.readTrackedNbt(nbt); + }); + quickAccess = Map.copyOf(trackedObjects); + } + + @Override + public synchronized void toNBT(NbtCompound compound) { + quickAccess.forEach((id, value) -> { + compound.put(id.toString(), value.toTrackedNbt()); + }); + } + + @Override + public void fromNBT(NbtCompound compound) { + Map values = new Object2ObjectOpenHashMap<>(); + compound.getKeys().forEach(key -> { + try { + UUID id = UUID.fromString(key); + if (id != null && !Util.NIL_UUID.equals(id)) { + NbtCompound nbt = compound.getCompound(key); + T entry = constructor.get(); + entry.readTrackedNbt(nbt); + values.put(id, entry); + } + } catch (Throwable t) { + Unicopia.LOGGER.warn("Exception loading tracked object", t); + } + }); + synchronized (this) { + trackedObjects.clear(); + trackedObjects.putAll(values); + quickAccess = Map.copyOf(trackedObjects); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableObject.java b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableObject.java new file mode 100644 index 00000000..40439f93 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableObject.java @@ -0,0 +1,24 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.UUID; + +import net.minecraft.nbt.NbtCompound; + +public interface TrackableObject { + UUID getUuid(); + + Status getStatus(); + + NbtCompound toTrackedNbt(); + + void readTrackedNbt(NbtCompound compound); + + void discard(boolean immediate); + + public enum Status { + DEFAULT, + NEW, + UPDATED, + REMOVED + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java index 28d0da3e..fa3c7d82 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java @@ -9,8 +9,9 @@ import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Levelled; -import com.minelittlepony.unicopia.ability.magic.SpellContainer; -import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; +import com.minelittlepony.unicopia.ability.magic.SpellInventory; +import com.minelittlepony.unicopia.ability.magic.SpellInventory.Operation; +import com.minelittlepony.unicopia.ability.magic.SpellSlots; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.block.state.StatePredicate; @@ -18,9 +19,6 @@ import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.entity.mob.UEntities; -import com.minelittlepony.unicopia.network.datasync.EffectSync; -import com.minelittlepony.unicopia.network.track.Trackable; - import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.data.DataTracker; @@ -34,8 +32,8 @@ import net.minecraft.world.World; public class MagicBeamEntity extends MagicProjectileEntity implements Caster, MagicImmune { private static final TrackedData HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN); - private final EffectSync effectDelegate = new EffectSync(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); - private final EntityPhysics physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); + private final SpellInventory spells = SpellSlots.ofSingle(this); + private final EntityPhysics physics = new EntityPhysics<>(this); public MagicBeamEntity(EntityType type, World world) { super(type, world); @@ -61,10 +59,9 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster void forEachDelegates(Consumer consumer, Function predicate) { - effectDelegate.tick(spell -> { + spells.tick(spell -> { Optional.ofNullable(predicate.apply(spell)).ifPresent(consumer); return Operation.SKIP; }); @@ -151,9 +148,7 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster { - compound.put("effect", Spell.writeNbt(effect)); - }); + spells.getSlots().toNBT(compound); } } From 2f0adac61608aec20509b94747e53e94463434bc Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 22 May 2024 00:16:12 +0100 Subject: [PATCH 36/85] Synchronize initial data to the client when an entity starts being tracked --- .../mixin/server/MixinEntityTrackerEntry.java | 29 +++++++++++++++ .../unicopia/network/track/DataTracker.java | 31 ++++++++++------ .../network/track/DataTrackerManager.java | 36 ++++++++++++++----- .../unicopia/network/track/ObjectTracker.java | 11 ++++++ .../unicopia/network/track/Trackable.java | 1 - src/main/resources/unicopia.mixin.json | 1 + 6 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/server/MixinEntityTrackerEntry.java diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinEntityTrackerEntry.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinEntityTrackerEntry.java new file mode 100644 index 00000000..a33344ad --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinEntityTrackerEntry.java @@ -0,0 +1,29 @@ +package com.minelittlepony.unicopia.mixin.server; + +import java.util.function.Consumer; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.minelittlepony.unicopia.network.track.Trackable; + +import net.minecraft.entity.Entity; +import net.minecraft.network.listener.ClientPlayPacketListener; +import net.minecraft.network.packet.Packet; +import net.minecraft.server.network.EntityTrackerEntry; +import net.minecraft.server.network.ServerPlayerEntity; + +@Mixin(EntityTrackerEntry.class) +abstract class MixinEntityTrackerEntry { + @Shadow + private @Final Entity entity; + + @Inject(method = "sendPackets", at = @At("RETURN")) + private void onSendPackets(ServerPlayerEntity player, Consumer> sender, CallbackInfo info) { + Trackable.of(entity).getDataTrackers().sendInitial(player, sender); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index 1c86e164..b730d475 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -66,8 +66,7 @@ public class DataTracker { } @SuppressWarnings("unchecked") - @Nullable - synchronized void getDirtyPairs(List output) { + private void updateTrackables() { for (var entry : persistentObjects.int2ObjectEntrySet()) { int key = entry.getIntKey(); TrackableObject.Status status = entry.getValue().getStatus(); @@ -76,19 +75,31 @@ public class DataTracker { dirtyIndices.add(key); } } + } + synchronized void getInitialPairs(List output) { + updateTrackables(); + output.add(new MsgTrackedValues.TrackerEntries(id, true, codecs)); + } + + @Nullable + synchronized void getDirtyPairs(List output) { if (initial) { initial = false; dirtyIndices = new IntOpenHashSet(); - output.add(new MsgTrackedValues.TrackerEntries(id, true, codecs)); - } else if (!dirtyIndices.isEmpty()) { - IntSet toSend = dirtyIndices; - dirtyIndices = new IntOpenHashSet(); - List> pairs = new ArrayList<>(); - for (int i : toSend) { - pairs.add(codecs.get(i)); + getInitialPairs(output); + } else { + updateTrackables(); + + if (!dirtyIndices.isEmpty()) { + IntSet toSend = dirtyIndices; + dirtyIndices = new IntOpenHashSet(); + List> pairs = new ArrayList<>(); + for (int i : toSend) { + pairs.add(codecs.get(i)); + } + output.add(new MsgTrackedValues.TrackerEntries(id, false, pairs)); } - output.add(new MsgTrackedValues.TrackerEntries(id, false, pairs)); } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java index 4f945917..f2da876c 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.network.track; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import java.util.function.Supplier; import com.minelittlepony.unicopia.network.Channel; @@ -9,6 +10,9 @@ import com.minelittlepony.unicopia.util.Tickable; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.entity.Entity; +import net.minecraft.network.listener.ClientPlayPacketListener; +import net.minecraft.network.packet.Packet; +import net.minecraft.server.network.ServerPlayerEntity; public class DataTrackerManager implements Tickable { private final Entity entity; @@ -45,17 +49,12 @@ public class DataTrackerManager implements Tickable { return; } - List toTransmit = new ArrayList<>(); - List objToTransmit = new ArrayList<>(); - synchronized (this) { - for (var entry : trackers) { - entry.getDirtyPairs(toTransmit); - } + List toTransmit = new ArrayList<>(); + List objToTransmit = new ArrayList<>(); - for (var entry : objectTrackers) { - entry.getDirtyPairs(objToTransmit); - } + for (var entry : trackers) entry.getDirtyPairs(toTransmit); + for (var entry : objectTrackers) entry.getDirtyPairs(objToTransmit); if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) { MsgTrackedValues packet = new MsgTrackedValues( @@ -68,6 +67,25 @@ public class DataTrackerManager implements Tickable { } } + public synchronized void sendInitial(ServerPlayerEntity player, Consumer> sender) { + synchronized (this) { + List toTransmit = new ArrayList<>(); + List objToTransmit = new ArrayList<>(); + + for (var entry : trackers) entry.getInitialPairs(toTransmit); + for (var entry : objectTrackers) entry.getInitialPairs(objToTransmit); + + if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) { + MsgTrackedValues packet = new MsgTrackedValues( + entity.getId(), + objToTransmit, + toTransmit + ); + sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(packet)); + } + } + } + synchronized void load(MsgTrackedValues packet) { for (var update : packet.updatedTrackers()) { DataTracker tracker = trackers.get(update.id()); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java index b4d00151..384fc589 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java @@ -73,6 +73,17 @@ public class ObjectTracker implements NbtSerialisable quickAccess = Map.copyOf(trackedObjects); } + synchronized void getInitialPairs(List output) { + if (!trackedObjects.isEmpty()) { + Map trackableCompounds = new HashMap<>(); + quickAccess.entrySet().forEach(object -> { + trackableCompounds.put(object.getKey(), object.getValue().toTrackedNbt()); + }); + + output.add(new MsgTrackedValues.TrackerObjects(id, Set.of(), trackableCompounds)); + } + } + synchronized void getDirtyPairs(List output) { if (!trackedObjects.isEmpty()) { Map trackableCompounds = new HashMap<>(); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java b/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java index 5fdcd9a0..6c232740 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java @@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.network.track; import net.minecraft.entity.Entity; public interface Trackable { - DataTrackerManager getDataTrackers(); static Trackable of(Entity entity) { diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index 5de80517..17bd2121 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -51,6 +51,7 @@ "MixinWardenEntity", "MixinWorld", "PointOfInterestTypesAccessor", + "server.MixinEntityTrackerEntry", "server.MixinPlayerManager", "server.MixinServerPlayerEntity", "server.MixinServerPlayNetworkHandler", From d824d5d701ad861618b4ff0ad78467836e6dda66 Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 22 May 2024 00:17:55 +0100 Subject: [PATCH 37/85] Fix warning --- src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java index 586af371..87e78a7a 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java @@ -25,7 +25,6 @@ import net.minecraft.entity.ItemEntity; import net.minecraft.entity.MovementType; import net.minecraft.entity.Entity.PositionUpdater; import net.minecraft.entity.Entity.RemovalReason; -import net.minecraft.entity.EntityType; import net.minecraft.fluid.Fluid; import net.minecraft.item.ItemStack; import net.minecraft.registry.tag.TagKey; From 9e2135fde38b1ac906e800b52a62368850631807 Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 22 May 2024 01:04:12 +0100 Subject: [PATCH 38/85] Clean up player capabilities networking --- .../ability/magic/spell/PlaceableSpell.java | 1 - .../unicopia/entity/Living.java | 6 +-- .../unicopia/entity/player/Pony.java | 53 +++++++++---------- .../unicopia/mixin/MixinEntity.java | 7 --- .../mixin/server/MixinEntityTrackerEntry.java | 9 +++- .../unicopia/network/Channel.java | 3 +- .../network/MsgOtherPlayerCapabilities.java | 26 --------- .../network/MsgPlayerCapabilities.java | 24 +++------ .../network/track/DataTrackerManager.java | 48 +++++++++++++---- .../unicopia/network/track/ObjectTracker.java | 8 ++- 10 files changed, 88 insertions(+), 97 deletions(-) delete mode 100644 src/main/java/com/minelittlepony/unicopia/network/MsgOtherPlayerCapabilities.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index 652009c1..3738f171 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -103,7 +103,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public boolean tick(Caster source, Situation situation) { - System.out.println("Placed Tick: " + source + " " + source.isClient() + " " + situation); if (situation == Situation.BODY) { if (!source.isClient()) { if (dimension == null) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 029922b9..45d15e84 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -102,7 +102,7 @@ public abstract class Living implements Equine, Caste private final ItemTracker armour = addTicker(new ItemTracker(this)); private final Transportation transportation = new Transportation<>(this); - private final DataTrackerManager trackers; + protected final DataTrackerManager trackers; protected final DataTracker tracker; protected final DataTracker.Entry carrierId; @@ -487,6 +487,7 @@ public abstract class Living implements Equine, Caste public void toNBT(NbtCompound compound) { enchants.toNBT(compound); spells.getSlots().toNBT(compound); + getCarrierId().ifPresent(id -> compound.putUuid("carrier", id)); toSyncronisedNbt(compound); } @@ -494,19 +495,18 @@ public abstract class Living implements Equine, Caste public void fromNBT(NbtCompound compound) { enchants.fromNBT(compound); spells.getSlots().fromNBT(compound); + setCarrier(compound.containsUuid("carrier") ? compound.getUuid("carrier") : null); fromSynchronizedNbt(compound); } @Override public void toSyncronisedNbt(NbtCompound compound) { compound.put("armour", armour.toNBT()); - getCarrierId().ifPresent(id -> compound.putUuid("carrier", id)); } @Override public void fromSynchronizedNbt(NbtCompound compound) { armour.fromNBT(compound.getCompound("armour")); - setCarrier(compound.containsUuid("carrier") ? compound.getUuid("carrier") : null); } public void updateVelocity() { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index b819834e..3546231d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -111,6 +111,12 @@ public class Pony extends Living implements Copyable, Update public Pony(PlayerEntity player) { super(player); + trackers.addPacketEmitter((sender, initial) -> { + if (initial || dirty) { + dirty = false; + sender.accept(Channel.SERVER_PLAYER_CAPABILITIES.toPacket(new MsgPlayerCapabilities(this))); + } + }); race = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); suppressedRace = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); @@ -314,19 +320,6 @@ public class Pony extends Living implements Copyable, Update dirty = true; } - private void sendCapabilities() { - if (!dirty) { - return; - } - dirty = false; - - if (entity instanceof ServerPlayerEntity) { - MsgOtherPlayerCapabilities packet = new MsgOtherPlayerCapabilities(this); - Channel.SERVER_PLAYER_CAPABILITIES.sendToPlayer(packet, (ServerPlayerEntity)entity); - Channel.SERVER_OTHER_PLAYER_CAPABILITIES.sendToSurroundingPlayers(packet, entity); - } - } - public AbilityDispatcher getAbilities() { return powers; } @@ -582,8 +575,6 @@ public class Pony extends Living implements Copyable, Update setSpecies(newRace); } } - - sendCapabilities(); } @Override @@ -825,10 +816,28 @@ public class Pony extends Living implements Copyable, Update } @Override - public void toSyncronisedNbt(NbtCompound compound) { - super.toSyncronisedNbt(compound); + public void toNBT(NbtCompound compound) { compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString()); compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString()); + compound.put("mana", mana.toNBT()); + compound.putInt("levels", levels.get()); + compound.putInt("corruption", corruption.get()); + super.toNBT(compound); + } + + @Override + public void fromNBT(NbtCompound compound) { + setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN)); + setSuppressedRace(Race.fromName(compound.getString("suppressedSpecies"), Race.UNSET)); + levels.set(compound.getInt("levels")); + corruption.set(compound.getInt("corruption")); + mana.fromNBT(compound.getCompound("mana")); + super.fromNBT(compound); + } + + @Override + public void toSyncronisedNbt(NbtCompound compound) { + super.toSyncronisedNbt(compound); compound.putFloat("magicExhaustion", magicExhaustion); compound.putInt("ticksInSun", ticksInSun); compound.putBoolean("hasShades", hasShades); @@ -837,12 +846,8 @@ public class Pony extends Living implements Copyable, Update compound.put("gravity", gravity.toNBT()); compound.put("charms", charms.toNBT()); compound.put("discoveries", discoveries.toNBT()); - compound.put("mana", mana.toNBT()); - compound.putInt("levels", levels.get()); - compound.putInt("corruption", corruption.get()); compound.putInt("ticksInvulnerable", ticksInvulnerable); compound.putInt("ticksMetamorphising", ticksMetamorphising); - NbtCompound progress = new NbtCompound(); advancementProgress.forEach((key, count) -> { progress.putInt(key, count); @@ -853,22 +858,16 @@ public class Pony extends Living implements Copyable, Update @Override public void fromSynchronizedNbt(NbtCompound compound) { super.fromSynchronizedNbt(compound); - setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN)); - setSuppressedRace(Race.fromName(compound.getString("suppressedSpecies"), Race.UNSET)); powers.fromNBT(compound.getCompound("powers")); gravity.fromNBT(compound.getCompound("gravity")); charms.fromNBT(compound.getCompound("charms")); discoveries.fromNBT(compound.getCompound("discoveries")); - levels.set(compound.getInt("levels")); - corruption.set(compound.getInt("corruption")); - mana.fromNBT(compound.getCompound("mana")); acrobatics.fromNBT(compound.getCompound("acrobatics")); magicExhaustion = compound.getFloat("magicExhaustion"); ticksInvulnerable = compound.getInt("ticksInvulnerable"); ticksInSun = compound.getInt("ticksInSun"); hasShades = compound.getBoolean("hasShades"); ticksMetamorphising = compound.getInt("ticksMetamorphising"); - NbtCompound progress = compound.getCompound("advancementProgress"); advancementProgress.clear(); for (String key : progress.getKeys()) { diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java index 87e78a7a..41927ec9 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java @@ -106,13 +106,6 @@ abstract class MixinEntity implements EntityDuck, Trackable { } } - @Inject(method = "tick()V", at = @At("RETURN")) - private void afterTick(CallbackInfo info) { - if (dataTrackerManager != null) { - dataTrackerManager.tick(); - } - } - @Inject(method = "updatePassengerPosition(Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/Entity$PositionUpdater;)V", at = @At("HEAD"), cancellable = true diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinEntityTrackerEntry.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinEntityTrackerEntry.java index a33344ad..d25a3e57 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinEntityTrackerEntry.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinEntityTrackerEntry.java @@ -21,9 +21,16 @@ import net.minecraft.server.network.ServerPlayerEntity; abstract class MixinEntityTrackerEntry { @Shadow private @Final Entity entity; + @Shadow + abstract void sendSyncPacket(Packet packet); + + @Inject(method = "tick()V", at = @At("TAIL")) + private void unicopia_onTick(CallbackInfo info) { + Trackable.of(entity).getDataTrackers().tick(this::sendSyncPacket); + } @Inject(method = "sendPackets", at = @At("RETURN")) - private void onSendPackets(ServerPlayerEntity player, Consumer> sender, CallbackInfo info) { + private void unicopia_onSendPackets(ServerPlayerEntity player, Consumer> sender, CallbackInfo info) { Trackable.of(entity).getDataTrackers().sendInitial(player, sender); } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/Channel.java b/src/main/java/com/minelittlepony/unicopia/network/Channel.java index e9f86d0d..f7464deb 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/Channel.java +++ b/src/main/java/com/minelittlepony/unicopia/network/Channel.java @@ -33,8 +33,7 @@ public interface Channel { S2CPacketType SERVER_RESOURCES = SimpleNetworking.serverToClient(Unicopia.id("resources"), MsgServerResources::new); S2CPacketType SERVER_TRACKED_ENTITY_DATA = SimpleNetworking.serverToClient(Unicopia.id("tracked_entity_date"), MsgTrackedValues::new); - S2CPacketType SERVER_OTHER_PLAYER_CAPABILITIES = SimpleNetworking.serverToClient(Unicopia.id("other_player_capabilities"), MsgOtherPlayerCapabilities::new); - S2CPacketType SERVER_PLAYER_ANIMATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("other_player_animation_change"), MsgPlayerAnimationChange::new); + S2CPacketType SERVER_PLAYER_ANIMATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("player_animation_change"), MsgPlayerAnimationChange::new); S2CPacketType SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new); S2CPacketType CONFIGURATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("config"), MsgConfigurationChange::new); S2CPacketType SERVER_ZAP_STAGE = SimpleNetworking.serverToClient(Unicopia.id("zap_stage"), MsgZapAppleStage::new); diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgOtherPlayerCapabilities.java b/src/main/java/com/minelittlepony/unicopia/network/MsgOtherPlayerCapabilities.java deleted file mode 100644 index d0492f07..00000000 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgOtherPlayerCapabilities.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.minelittlepony.unicopia.network; - -import com.minelittlepony.unicopia.entity.player.Pony; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; - -/** - * Sent by the server to update other player's capabilities. - */ -public class MsgOtherPlayerCapabilities extends MsgPlayerCapabilities { - - MsgOtherPlayerCapabilities(PacketByteBuf buffer) { - super(buffer); - } - - public MsgOtherPlayerCapabilities(Pony player) { - super(player); - } - - @Override - protected Pony getRecipient(PlayerEntity sender) { - return Pony.of(MinecraftClient.getInstance().world.getPlayerByUuid(playerId)); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java index a665b194..5c390078 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java @@ -3,9 +3,6 @@ package com.minelittlepony.unicopia.network; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.UUID; - -import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.entity.player.Pony; import com.sollace.fabwork.api.packets.HandledPacket; @@ -23,12 +20,12 @@ import net.minecraft.nbt.NbtIo; */ public class MsgPlayerCapabilities implements HandledPacket { - protected final UUID playerId; + protected final int playerId; private final NbtCompound compoundTag; MsgPlayerCapabilities(PacketByteBuf buffer) { - playerId = buffer.readUuid(); + playerId = buffer.readInt(); try (InputStream in = new ByteBufInputStream(buffer)) { compoundTag = NbtIo.readCompressed(in); } catch (IOException e) { @@ -37,14 +34,14 @@ public class MsgPlayerCapabilities implements HandledPacket { } public MsgPlayerCapabilities(Pony player) { - playerId = player.asEntity().getUuid(); + playerId = player.asEntity().getId(); compoundTag = new NbtCompound(); player.toSyncronisedNbt(compoundTag); } @Override public void toBuffer(PacketByteBuf buffer) { - buffer.writeUuid(playerId); + buffer.writeInt(playerId); try (OutputStream out = new ByteBufOutputStream(buffer)) { NbtIo.writeCompressed(compoundTag, out); } catch (IOException e) { @@ -53,16 +50,9 @@ public class MsgPlayerCapabilities implements HandledPacket { @Override public void handle(PlayerEntity sender) { - Pony player = getRecipient(sender); - if (player == null) { - Unicopia.LOGGER.warn("Skipping capabilities for unknown player " + playerId.toString()); - return; + Pony player = Pony.of(sender.getWorld().getEntityById(playerId)).orElse(null); + if (player != null) { + player.fromSynchronizedNbt(compoundTag); } - - player.fromSynchronizedNbt(compoundTag); - } - - protected Pony getRecipient(PlayerEntity sender) { - return Pony.of(sender); } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java index f2da876c..f2058a78 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -5,29 +5,39 @@ import java.util.List; import java.util.function.Consumer; import java.util.function.Supplier; -import com.minelittlepony.unicopia.network.Channel; -import com.minelittlepony.unicopia.util.Tickable; +import org.jetbrains.annotations.Nullable; +import com.minelittlepony.unicopia.network.Channel; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.entity.Entity; import net.minecraft.network.listener.ClientPlayPacketListener; import net.minecraft.network.packet.Packet; import net.minecraft.server.network.ServerPlayerEntity; -public class DataTrackerManager implements Tickable { +public class DataTrackerManager { private final Entity entity; final boolean isClient; private final List trackers = new ObjectArrayList<>(); private final List> objectTrackers = new ObjectArrayList<>(); - private final DataTracker primaryTracker = checkoutTracker(); + private final List packetEmitters = new ObjectArrayList<>(); + + @Nullable + private DataTracker primaryTracker; public DataTrackerManager(Entity entity) { this.entity = entity; this.isClient = entity.getWorld().isClient; } + public synchronized void addPacketEmitter(PacketEmitter packetEmitter) { + packetEmitters.add(packetEmitter); + } + public DataTracker getPrimaryTracker() { + if (primaryTracker == null) { + primaryTracker = checkoutTracker(); + } return primaryTracker; } @@ -43,13 +53,16 @@ public class DataTrackerManager implements Tickable { return tracker; } - @Override - public void tick() { - if (isClient) { - return; - } - + public void tick(Consumer> sender) { synchronized (this) { + for (var emitter : packetEmitters) { + emitter.sendPackets(sender, false); + } + + if (trackers.isEmpty() && objectTrackers.isEmpty()) { + return; + } + List toTransmit = new ArrayList<>(); List objToTransmit = new ArrayList<>(); @@ -62,13 +75,22 @@ public class DataTrackerManager implements Tickable { objToTransmit, toTransmit ); - Channel.SERVER_TRACKED_ENTITY_DATA.sendToSurroundingPlayers(packet, entity); + sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(packet)); } } } + @SuppressWarnings({ "rawtypes", "unchecked" }) public synchronized void sendInitial(ServerPlayerEntity player, Consumer> sender) { synchronized (this) { + for (var emitter : packetEmitters) { + emitter.sendPackets((Consumer)sender, true); + } + + if (trackers.isEmpty() && objectTrackers.isEmpty()) { + return; + } + List toTransmit = new ArrayList<>(); List objToTransmit = new ArrayList<>(); @@ -100,4 +122,8 @@ public class DataTrackerManager implements Tickable { } } } + + public interface PacketEmitter { + void sendPackets(Consumer> consumer, boolean initial); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java index 384fc589..b6e3ec57 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java @@ -135,7 +135,11 @@ public class ObjectTracker implements NbtSerialisable Map values = new Object2ObjectOpenHashMap<>(); compound.getKeys().forEach(key -> { try { - UUID id = UUID.fromString(key); + UUID id = Util.NIL_UUID; + try { + id = UUID.fromString(key); + } catch (Throwable ignore) {} + if (id != null && !Util.NIL_UUID.equals(id)) { NbtCompound nbt = compound.getCompound(key); T entry = constructor.get(); @@ -143,7 +147,7 @@ public class ObjectTracker implements NbtSerialisable values.put(id, entry); } } catch (Throwable t) { - Unicopia.LOGGER.warn("Exception loading tracked object", t); + Unicopia.LOGGER.warn("Exception loading tracked object: {}", t.getMessage()); } }); synchronized (this) { From ca361049f5e9ef89adf5e848c7f48dd924396e54 Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 22 May 2024 13:25:32 +0100 Subject: [PATCH 39/85] Surface spell attributes to the user in gemstone tooltips --- .../spell/effect/CustomisedSpellType.java | 30 +++++++++++++++++++ .../magic/spell/effect/ShieldSpell.java | 25 ++++++++++++++++ .../ability/magic/spell/effect/SpellType.java | 23 +++++++++++--- .../client/gui/DismissSpellScreen.java | 4 +-- .../unicopia/entity/effect/EffectUtils.java | 10 +++++++ .../unicopia/item/GemstoneItem.java | 18 +---------- .../resources/assets/unicopia/lang/en_us.json | 6 ++++ 7 files changed, 92 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java index bd0e73e8..9a62d4db 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java @@ -1,15 +1,24 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.ArrayList; +import java.util.List; + import org.jetbrains.annotations.Nullable; +import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; +import com.minelittlepony.unicopia.client.TextHelper; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.TypedActionResult; public record CustomisedSpellType ( @@ -70,6 +79,27 @@ public record CustomisedSpellType ( return traits.applyTo(type.getDefualtStack()); } + public void appendTooltip(List lines) { + MutableText lore = Text.translatable(type().getTranslationKey() + ".lore").formatted(type().getAffinity().getColor()); + + if (!InteractionManager.getInstance().getClientSpecies().canCast()) { + lore = lore.formatted(Formatting.OBFUSCATED); + } + lines.addAll(TextHelper.wrap(lore, 180).toList()); + float corruption = ((int)traits().getCorruption() * 10) + type().getAffinity().getCorruption(); + List modifiers = new ArrayList<>(); + type.getTooltip().accept(this, modifiers); + if (corruption != 0) { + modifiers.add(EffectUtils.formatModifierChange("affinity.unicopia.corruption", corruption, true)); + } + if (!modifiers.isEmpty()) { + lines.add(Text.empty()); + lines.add(Text.translatable("affinity.unicopia.when_cast").formatted(Formatting.GRAY)); + lines.addAll(modifiers); + } + + } + public TypedActionResult> toAction() { return isEmpty() ? TypedActionResult.fail(this) : TypedActionResult.pass(this); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java index 23ceb121..da5e5dc2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java @@ -1,5 +1,6 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; import java.util.Optional; import com.minelittlepony.unicopia.Affinity; @@ -12,6 +13,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect; @@ -33,6 +35,8 @@ import net.minecraft.entity.passive.PassiveEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity; import net.minecraft.entity.vehicle.BoatEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -44,6 +48,27 @@ public class ShieldSpell extends AbstractSpell { .with(Trait.AIR, 9) .build(); + static void appendTooltip(CustomisedSpellType type, List tooltip) { + float addedRange = type.traits().get(Trait.POWER); + if (addedRange != 0) { + tooltip.add(EffectUtils.formatModifierChange("spell.unicopia.shield.additional_range", addedRange, false)); + } + if (type.traits().get(Trait.LIFE) > 0) { + tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.permit.passive")).formatted(Formatting.GRAY)); + } + if (type.traits().get(Trait.BLOOD) > 0) { + tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.permit.hostile")).formatted(Formatting.GRAY)); + } + if (type.traits().get(Trait.ICE) > 0) { + tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.permit.player")).formatted(Formatting.GRAY)); + } + if (type.traits().get(Trait.GENEROSITY) > 0) { + tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.caston.location")).formatted(Formatting.GRAY)); + } else { + tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.caston.person")).formatted(Formatting.GRAY)); + } + } + protected final TargetSelecter targetSelecter = new TargetSelecter(this).setFilter(this::isValidTarget); private final Lerp radius = new Lerp(0); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index d3efed08..6bbf0219 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; +import java.util.function.BiConsumer; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.Affinity; @@ -34,7 +36,7 @@ import net.minecraft.server.command.ServerCommandSource; public final class SpellType implements Affine, SpellPredicate { public static final Identifier EMPTY_ID = Unicopia.id("none"); - public static final SpellType EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, false, GemstoneItem.Shape.ROUND, SpellTraits.EMPTY, t -> null); + public static final SpellType EMPTY_KEY = builder(t -> null).affinity(Affinity.NEUTRAL).color(0xFFFFFF).unobtainable().build(EMPTY_ID); public static final Registry> REGISTRY = RegistryUtils.createSimple(Unicopia.id("spells")); public static final RegistryKey>> REGISTRY_KEY = REGISTRY.getKey(); @@ -55,7 +57,7 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).stackable().shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS)); public static final SpellType FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS)); public static final SpellType INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS)); - public static final SpellType SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS)); + public static final SpellType SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS).tooltip(ShieldSpell::appendTooltip)); public static final SpellType ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS)); public static final SpellType VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS)); public static final SpellType DARK_VORTEX = register("dark_vortex", builder(DarkVortexSpell::new).affinity(Affinity.BAD).color(0xA33333).stackable().shape(GemstoneItem.Shape.VORTEX).traits(DarkVortexSpell.DEFAULT_TRAITS)); @@ -95,12 +97,15 @@ public final class SpellType implements Affine, SpellPredicate< private final ItemStack defaultStack; - private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, boolean stackable, GemstoneItem.Shape shape, SpellTraits traits, Factory factory) { + private final BiConsumer, List> tooltipFunction; + + private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, boolean stackable, GemstoneItem.Shape shape, SpellTraits traits, BiConsumer, List> tooltipFunction, Factory factory) { this.id = id; this.affinity = affinity; this.color = color; this.obtainable = obtainable; this.shape = shape; + this.tooltipFunction = tooltipFunction; this.factory = factory; this.traits = traits; this.stackable = stackable; @@ -167,6 +172,10 @@ public final class SpellType implements Affine, SpellPredicate< return factory; } + public BiConsumer, List> getTooltip() { + return tooltipFunction; + } + @Override public boolean test(@Nullable Spell spell) { return spell != null && spell.getTypeAndTraits().type() == this; @@ -228,6 +237,7 @@ public final class SpellType implements Affine, SpellPredicate< private boolean stackable = false; private GemstoneItem.Shape shape = GemstoneItem.Shape.ROUND; private SpellTraits traits = SpellTraits.EMPTY; + private BiConsumer, List> tooltipFunction = (t, l) -> {}; Builder(Factory factory) { this.factory = factory; @@ -263,8 +273,13 @@ public final class SpellType implements Affine, SpellPredicate< return this; } + public Builder tooltip(BiConsumer, List> tooltipFunction) { + this.tooltipFunction = tooltipFunction; + return this; + } + public SpellType build(Identifier id) { - return new SpellType<>(id, affinity, color, obtainable, stackable, shape, traits, factory); + return new SpellType<>(id, affinity, color, obtainable, stackable, shape, traits, tooltipFunction, factory); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 85028253..873f7d10 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -9,7 +9,6 @@ import com.minelittlepony.common.client.gui.GameGui; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.*; -import com.minelittlepony.unicopia.client.TextHelper; import com.minelittlepony.unicopia.client.render.model.SphereModel; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.UItems; @@ -191,9 +190,8 @@ public class DismissSpellScreen extends GameGui { tooltip.add(Text.translatable("gui.unicopia.dispell_screen.spell_type", name)); type.traits().appendTooltip(tooltip); tooltip.add(ScreenTexts.EMPTY); - tooltip.add(Text.translatable("gui.unicopia.dispell_screen.affinity", affinity.getDisplayName())); + type.appendTooltip(tooltip); tooltip.add(ScreenTexts.EMPTY); - tooltip.addAll(TextHelper.wrap(Text.translatable(type.type().getTranslationKey() + ".lore").formatted(affinity.getColor()), 180).toList()); if (spell instanceof TimedSpell timed) { tooltip.add(ScreenTexts.EMPTY); tooltip.add(Text.translatable("gui.unicopia.dispell_screen.time_left", StringHelper.formatTicks(timed.getTimer().getTicksRemaining()))); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java index 208ccf04..f60e6876 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java @@ -3,6 +3,9 @@ package com.minelittlepony.unicopia.entity.effect; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.effect.StatusEffect; import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.item.ItemStack; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; public interface EffectUtils { static boolean isPoisoned(LivingEntity entity) { @@ -46,4 +49,11 @@ public interface EffectUtils { } return false; } + + static Text formatModifierChange(String modifierName, float change, boolean isDetrimental) { + return Text.translatable("attribute.modifier." + (change > 0 ? "plus" : "take") + ".addition", + ItemStack.MODIFIER_FORMAT.format(Math.abs(change)), + Text.translatable(modifierName) + ).formatted((isDetrimental ? change : -change) < 0 ? Formatting.DARK_GREEN : Formatting.RED); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java index 3ccf6cae..c554972c 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java @@ -8,7 +8,6 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; -import com.minelittlepony.unicopia.client.TextHelper; import com.minelittlepony.unicopia.entity.player.PlayerCharmTracker; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.group.MultiItem; @@ -17,9 +16,7 @@ import net.minecraft.client.item.TooltipContext; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import net.minecraft.util.Hand; import net.minecraft.util.TypedActionResult; import net.minecraft.world.World; @@ -80,20 +77,7 @@ public class GemstoneItem extends Item implements MultiItem, EnchantableItem { super.appendTooltip(stack, world, lines, tooltipContext); if (EnchantableItem.isEnchanted(stack)) { - CustomisedSpellType type = getSpellEffect(stack); - - MutableText line = Text.translatable(type.type().getTranslationKey() + ".lore").formatted(type.type().getAffinity().getColor()); - - if (!InteractionManager.getInstance().getClientSpecies().canCast()) { - line = line.formatted(Formatting.OBFUSCATED); - } - lines.addAll(TextHelper.wrap(line, 180).toList()); - lines.add(Text.empty()); - float corruption = ((int)type.traits().getCorruption() * 10) + type.type().getAffinity().getCorruption(); - if (corruption != 0) { - lines.add(Text.translatable("affinity.unicopia.when_cast").formatted(Formatting.GRAY)); - lines.add(Text.translatable("affinity.unicopia.corruption", corruption > 0 ? "+" : "-", ItemStack.MODIFIER_FORMAT.format(Math.abs(corruption))).formatted(corruption < 0 ? Formatting.DARK_GREEN : Formatting.RED)); - } + getSpellEffect(stack).appendTooltip(lines); } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index fa43ed75..91ec6e3c 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -548,6 +548,12 @@ "spell.unicopia.fire_bolt": "Fire Bolt", "spell.unicopia.fire_bolt.lore": "Produces several burning projectiles", "spell.unicopia.shield": "Protection", + "spell.unicopia.shield.additional_range": "Additional Range", + "spell.unicopia.shield.permit.passive": "Permits Passive Mobs", + "spell.unicopia.shield.permit.hostile": "Permits Hostile Mobs", + "spell.unicopia.shield.permit.player": " Permits Other Players", + "spell.unicopia.shield.caston.location": "Applies to location", + "spell.unicopia.shield.caston.person": "Applies to self", "spell.unicopia.shield.lore": "Casts a protective shield around the user", "spell.unicopia.bubble": "Bubble", "spell.unicopia.bubble.lore": "Traps any creature it hits in a soap bubble", From e23cbcdd1c88e7ca7de06ad4846701d058e57ebb Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 22 May 2024 13:58:20 +0100 Subject: [PATCH 40/85] Fixed placed and projectile spells not syncing their level correctly. Also fixes placed shields not rendering --- .../unicopia/ability/magic/Levelled.java | 22 +++++---- .../unicopia/entity/Creature.java | 4 +- .../unicopia/entity/EntityReference.java | 4 +- .../unicopia/entity/mob/CastSpellEntity.java | 37 ++++++++++++--- .../unicopia/projectile/MagicBeamEntity.java | 46 +++++++++++++++++-- .../projectile/MagicProjectileEntity.java | 6 +-- 6 files changed, 94 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/Levelled.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/Levelled.java index c3094400..2ea5d1e4 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/Levelled.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/Levelled.java @@ -1,33 +1,32 @@ package com.minelittlepony.unicopia.ability.magic; +import java.util.function.IntConsumer; import java.util.function.IntSupplier; import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.math.MathHelper; /** * Object with levelling capabilities. */ public interface Levelled { - LevelStore EMPTY = fixed(0); + LevelStore ZERO = of(0, 1); - static LevelStore fixed(int level) { - return of(() -> level); - } - - static LevelStore of(IntSupplier supplier) { + static LevelStore of(IntSupplier getter, IntConsumer setter, IntSupplier max) { return new LevelStore() { @Override public int get() { - return supplier.getAsInt(); + return getter.getAsInt(); } @Override public void set(int level) { + setter.accept(level); } @Override public int getMax() { - return get(); + return max.getAsInt(); } }; } @@ -37,7 +36,9 @@ public interface Levelled { } static LevelStore fromNbt(NbtCompound compound) { - return of(compound.getInt("value"), compound.getInt("max")); + int max = Math.max(1, compound.getInt("max")); + int value = MathHelper.clamp(compound.getInt("value"), 0, max); + return of(value, max); } static LevelStore of(int level, int max) { @@ -70,6 +71,9 @@ public interface Levelled { void set(int level); default float getScaled(float max) { + if (getMax() == 0) { + return max; + } return ((float)get() / getMax()) * max; } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index bd0929c6..eb7e27b9 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -279,12 +279,12 @@ public class Creature extends Living implements WeaklyOwned.Mutabl @Override public LevelStore getLevel() { - return Levelled.EMPTY; + return Levelled.ZERO; } @Override public LevelStore getCorruption() { - return Levelled.EMPTY; + return Levelled.ZERO; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java index c401c1ce..49fa886e 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java @@ -134,8 +134,8 @@ public class EntityReference implements NbtSerialisable { entity.getPos(), entity.getId(), entity instanceof PlayerEntity, !entity.isAlive(), - Caster.of(entity).map(Caster::getLevel).map(Levelled::copyOf).orElse(Levelled.EMPTY), - Caster.of(entity).map(Caster::getCorruption).map(Levelled::copyOf).orElse(Levelled.EMPTY) + Caster.of(entity).map(Caster::getLevel).map(Levelled::copyOf).orElse(Levelled.ZERO), + Caster.of(entity).map(Caster::getCorruption).map(Levelled::copyOf).orElse(Levelled.ZERO) ); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index b5ec2dd4..9c7312df 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -17,11 +17,18 @@ import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityPose; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.data.DataTracker; +import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.nbt.NbtCompound; import net.minecraft.text.Text; import net.minecraft.world.World; public class CastSpellEntity extends LightEmittingEntity implements Caster, WeaklyOwned.Mutable, MagicImmune { + private static final TrackedData LEVEL = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData MAX_LEVEL = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData CORRUPTION = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData MAX_CORRUPTION = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.INTEGER); private final EntityPhysics physics = new EntityPhysics<>(this); @@ -29,8 +36,16 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster owner = new EntityReference<>(); - private LevelStore level = Levelled.EMPTY; - private LevelStore corruption = Levelled.EMPTY; + private final LevelStore level = Levelled.of( + () -> dataTracker.get(LEVEL), + l -> dataTracker.set(LEVEL, l), + () -> dataTracker.get(MAX_LEVEL) + ); + private final LevelStore corruption = Levelled.of( + () -> dataTracker.get(CORRUPTION), + l -> dataTracker.set(CORRUPTION, l), + () -> dataTracker.get(MAX_CORRUPTION) + ); public CastSpellEntity(EntityType type, World world) { super(type, world); @@ -39,6 +54,10 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster caster) { - this.level = Levelled.copyOf(caster.getLevel()); - this.corruption = Levelled.copyOf(caster.getCorruption()); + dataTracker.set(LEVEL, caster.getLevel().get()); + dataTracker.set(MAX_LEVEL, caster.getLevel().getMax()); + dataTracker.set(CORRUPTION, caster.getCorruption().get()); + dataTracker.set(MAX_CORRUPTION, caster.getCorruption().getMax()); setMaster(caster); } @@ -144,7 +165,11 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster, MagicImmune { private static final TrackedData HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN); + private static final TrackedData LEVEL = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData MAX_LEVEL = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData CORRUPTION = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData MAX_CORRUPTION = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.INTEGER); private final SpellInventory spells = SpellSlots.ofSingle(this); private final EntityPhysics physics = new EntityPhysics<>(this); + private final LevelStore level = Levelled.of( + () -> dataTracker.get(LEVEL), + l -> dataTracker.set(LEVEL, l), + () -> dataTracker.get(MAX_LEVEL) + ); + private final LevelStore corruption = Levelled.of( + () -> dataTracker.get(CORRUPTION), + l -> dataTracker.set(CORRUPTION, l), + () -> dataTracker.get(MAX_CORRUPTION) + ); + public MagicBeamEntity(EntityType type, World world) { super(type, world); } @@ -51,7 +68,11 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster { + dataTracker.set(LEVEL, caster.getLevel().get()); + dataTracker.set(MAX_LEVEL, caster.getLevel().getMax()); + dataTracker.set(CORRUPTION, caster.getCorruption().get()); + dataTracker.set(MAX_CORRUPTION, caster.getCorruption().getMax()); + }); + } + @Override public LevelStore getLevel() { - return getMasterReference().getTarget().map(target -> target.level()).orElse(Levelled.EMPTY); + return level; } @Override public LevelStore getCorruption() { - return getMasterReference().getTarget().map(target -> target.corruption()).orElse(Levelled.EMPTY); + return corruption; } @Override @@ -149,11 +181,19 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster Date: Wed, 22 May 2024 15:25:35 +0100 Subject: [PATCH 41/85] Cleanup and sync placed spell owners --- .../com/minelittlepony/unicopia/Race.java | 4 +- .../unicopia/entity/Creature.java | 29 +++++------- .../unicopia/entity/EntityPhysics.java | 7 ++- .../unicopia/entity/EntityReference.java | 40 +++++++++++++++-- .../unicopia/entity/ItemImpl.java | 7 ++- .../unicopia/entity/Living.java | 7 ++- .../unicopia/entity/mob/CastSpellEntity.java | 3 ++ .../unicopia/entity/player/Acrobatics.java | 14 +++--- .../unicopia/entity/player/ManaContainer.java | 10 ++--- .../entity/player/PlayerLevelStore.java | 10 ++--- .../unicopia/entity/player/Pony.java | 13 +++--- .../unicopia/network/track/DataTracker.java | 22 ++++++---- .../network/track/TrackableDataType.java | 44 ++++++++++++------- 13 files changed, 119 insertions(+), 91 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/Race.java b/src/main/java/com/minelittlepony/unicopia/Race.java index 2380c241..84994481 100644 --- a/src/main/java/com/minelittlepony/unicopia/Race.java +++ b/src/main/java/com/minelittlepony/unicopia/Race.java @@ -10,8 +10,8 @@ import com.google.common.base.Strings; import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Ability; import com.minelittlepony.unicopia.ability.magic.Affine; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.RegistryUtils; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; @@ -45,7 +45,7 @@ public record Race ( public static final String DEFAULT_ID = "unicopia:unset"; public static final Registry REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID); public static final Registry COMMAND_REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race/grantable"), DEFAULT_ID); - public static final PacketCodec PACKET_CODEC = PacketCodec.ofRegistry(REGISTRY); + public static final TrackableDataType TRACKABLE_TYPE = TrackableDataType.RACE; public static final RegistryKey> REGISTRY_KEY = REGISTRY.getKey(); private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("commands.race.fail", id)); private static final Function COMPOSITES = Util.memoize(race -> new Composite(race, null, null)); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index eb7e27b9..c319f104 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -23,7 +23,6 @@ import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.network.track.TrackableDataType; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; @@ -62,7 +61,6 @@ public class Creature extends Living implements WeaklyOwned.Mutabl .isEmpty(); }); - protected final DataTracker.Entry master; protected final DataTracker.Entry eating; protected final DataTracker.Entry discorded; protected final DataTracker.Entry smitten; @@ -73,16 +71,15 @@ public class Creature extends Living implements WeaklyOwned.Mutabl addTicker(physics); addTicker(this::updateConsumption); - master = tracker.startTracking(TrackableDataType.of(PacketCodec.NBT), owner.toNBT()); - eating = tracker.startTracking(TrackableDataType.of(PacketCodec.INT), 0); - discorded = tracker.startTracking(TrackableDataType.of(PacketCodec.BOOLEAN), false); - smitten = tracker.startTracking(TrackableDataType.of(PacketCodec.BOOLEAN), false); + tracker.startTracking(owner); + eating = tracker.startTracking(TrackableDataType.INT, 0); + discorded = tracker.startTracking(TrackableDataType.BOOLEAN, false); + smitten = tracker.startTracking(TrackableDataType.BOOLEAN, false); } @Override public void setMaster(LivingEntity owner) { this.owner.set(owner); - tracker.set(master, this.owner.toNBT()); if (owner != null) { targets.ifPresent(this::initMinionAi); } @@ -93,20 +90,20 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } public boolean isDiscorded() { - return tracker.get(this.discorded); + return discorded.get(); } public boolean isSmitten() { - return tracker.get(this.smitten); + return smitten.get(); } public void setSmitten(boolean smitten) { smittenTicks = smitten ? 20 : 0; - tracker.set(this.smitten, smitten); + this.smitten.set(smitten); } public void setDiscorded(boolean discorded) { - tracker.set(this.discorded, discorded); + this.discorded.set(discorded); discordedChanged = true; } @@ -118,9 +115,6 @@ public class Creature extends Living implements WeaklyOwned.Mutabl @Override public EntityReference getMasterReference() { - if (master != null) { - owner.fromNBT(tracker.get(master)); - } return owner; } @@ -232,10 +226,10 @@ public class Creature extends Living implements WeaklyOwned.Mutabl private void updateConsumption() { if (isClient()) { - eatTimer = tracker.get(eating); + eatTimer = eating.get(); } else if (eatMuffinGoal != null) { eatTimer = eatMuffinGoal.getTimer(); - tracker.set(eating, eatTimer); + eating.set(eatTimer); } } @@ -324,9 +318,6 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } if (compound.contains("master", NbtElement.COMPOUND_TYPE)) { owner.fromNBT(compound.getCompound("master")); - if (master != null) { - tracker.set(master, owner.toNBT()); - } if (owner.isSet()) { targets.ifPresent(this::initMinionAi); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java index b08ce4cd..c50d740f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java @@ -6,7 +6,6 @@ import com.minelittlepony.unicopia.network.track.Trackable; import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.Tickable; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; import net.minecraft.block.BlockState; import net.minecraft.block.FenceGateBlock; @@ -31,7 +30,7 @@ public class EntityPhysics implements Physics, Copyable implements Physics, Copyable The type of the entity this reference points to. */ -public class EntityReference implements NbtSerialisable { +public class EntityReference implements NbtSerialisable, TrackableObject { private static final Serializer SERIALIZER = Serializer.of(EntityReference::new); @SuppressWarnings("unchecked") @@ -42,6 +43,8 @@ public class EntityReference implements NbtSerialisable { private WeakReference directReference = new WeakReference<>(null); + private boolean dirty = true; + public EntityReference() {} public EntityReference(T entity) { @@ -61,13 +64,14 @@ public class EntityReference implements NbtSerialisable { public boolean set(@Nullable T entity) { this.directReference = new WeakReference<>(entity); this.reference = entity == null ? null : new EntityValues<>(entity); + this.dirty = true; return entity != null; } public Optional> getTarget() { T value = directReference.get(); if (value != null) { - set(value); + this.reference = new EntityValues<>(value); } return Optional.ofNullable(reference); } @@ -113,11 +117,41 @@ public class EntityReference implements NbtSerialisable { @Override public void fromNBT(NbtCompound tag) { this.reference = tag.contains("uuid") ? new EntityValues<>(tag) : null; + this.dirty = true; } @Override public int hashCode() { - return getTarget().map(EntityValues::uuid).orElse(Util.NIL_UUID).hashCode(); + return getUuid().hashCode(); + } + + @Override + public UUID getUuid() { + return getTarget().map(EntityValues::uuid).orElse(Util.NIL_UUID); + } + + @Override + public Status getStatus() { + if (dirty) { + dirty = false; + return Status.UPDATED; + } + return Status.DEFAULT; + } + + @Override + public NbtCompound toTrackedNbt() { + return toNBT(); + } + + @Override + public void readTrackedNbt(NbtCompound compound) { + fromNBT(compound); + } + + @Override + public void discard(boolean immediate) { + set(null); } public record EntityValues( diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java index a4c30f52..ce04e0d9 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java @@ -8,7 +8,6 @@ import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment; import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.network.track.DataTrackerManager; import com.minelittlepony.unicopia.network.track.Trackable; -import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.UParticles; @@ -44,7 +43,7 @@ public class ItemImpl implements Equine { this.tracker = trackers.getPrimaryTracker(); this.physics = new ItemPhysics(owner); - race = tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); + race = tracker.startTracking(Race.TRACKABLE_TYPE, Race.HUMAN); } @Override @@ -141,12 +140,12 @@ public class ItemImpl implements Equine { @Override public Race getSpecies() { - return tracker.get(race); + return race.get(); } @Override public void setSpecies(Race race) { - tracker.set(this.race, race); + this.race.set(race); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 45d15e84..0ea9bc46 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -40,7 +40,6 @@ import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.projectile.ProjectileImpactListener; import com.minelittlepony.unicopia.server.world.DragonBreathStore; import com.minelittlepony.unicopia.util.*; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; import net.fabricmc.fabric.api.util.TriState; @@ -116,7 +115,7 @@ public abstract class Living implements Equine, Caste this.landedHeuristic = addTicker(new Interactable(entity::isOnGround)); this.jumpingHeuristic = addTicker(new Interactable(((LivingEntityDuck)entity)::isJumping)); - carrierId = tracker.startTracking(TrackableDataType.of(PacketCodec.UUID), Util.NIL_UUID); + carrierId = tracker.startTracking(TrackableDataType.UUID, Util.NIL_UUID); } public Q addTicker(Q tickable) { @@ -171,12 +170,12 @@ public abstract class Living implements Equine, Caste } public Optional getCarrierId() { - UUID carrierId = tracker.get(this.carrierId); + UUID carrierId = this.carrierId.get(); return carrierId == Util.NIL_UUID ? Optional.empty() : Optional.of(carrierId); } public void setCarrier(UUID carrier) { - tracker.set(this.carrierId, carrier == null ? Util.NIL_UUID : carrier); + carrierId.set(carrier == null ? Util.NIL_UUID : carrier); } public void setCarrier(Entity carrier) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 9c7312df..01cbf06b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -12,6 +12,8 @@ import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.entity.Physics; +import com.minelittlepony.unicopia.network.track.Trackable; + import net.minecraft.entity.Entity; import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityPose; @@ -50,6 +52,7 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster type, World world) { super(type, world); ignoreCameraFrustum = true; + Trackable.of(this).getDataTrackers().getPrimaryTracker().startTracking(owner); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java index 75fadc1c..2afbc3ca 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java @@ -12,8 +12,6 @@ import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; - import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.SideShapeType; @@ -36,14 +34,12 @@ public class Acrobatics implements Tickable, NbtSerialisable { private final Pony pony; private final PlayerEntity entity; - private final DataTracker tracker; private final DataTracker.Entry> hangingPos; public Acrobatics(Pony pony, DataTracker tracker) { this.pony = pony; - this.tracker = tracker; this.entity = pony.asEntity(); - this.hangingPos = tracker.startTracking(TrackableDataType.of(PacketCodec.OPTIONAL_POS), Optional.empty()); + this.hangingPos = tracker.startTracking(TrackableDataType.OPTIONAL_POS, Optional.empty()); pony.addTicker(this::checkDislodge); } @@ -146,7 +142,7 @@ public class Acrobatics implements Tickable, NbtSerialisable { } public Optional getHangingPosition() { - return tracker.get(hangingPos); + return hangingPos.get(); } public boolean isHanging() { @@ -154,13 +150,13 @@ public class Acrobatics implements Tickable, NbtSerialisable { } public void stopHanging() { - tracker.set(hangingPos, Optional.empty()); + hangingPos.set(Optional.empty()); entity.calculateDimensions(); ticksHanging = 0; } public void startHanging(BlockPos pos) { - tracker.set(hangingPos, Optional.of(pos)); + hangingPos.set(Optional.of(pos)); entity.teleport(pos.getX() + 0.5, pos.getY() - 1, pos.getZ() + 0.5); entity.setVelocity(Vec3d.ZERO); entity.setSneaking(false); @@ -201,6 +197,6 @@ public class Acrobatics implements Tickable, NbtSerialisable { @Override public void fromNBT(NbtCompound compound) { ticksHanging = compound.getInt("ticksHanging"); - tracker.set(hangingPos, NbtSerialisable.BLOCK_POS.readOptional("hangingPosition", compound)); + hangingPos.set(NbtSerialisable.BLOCK_POS.readOptional("hangingPosition", compound)); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java b/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java index ccb7a65c..15bcf34f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java @@ -8,8 +8,6 @@ import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; - import net.minecraft.nbt.NbtCompound; import net.minecraft.util.math.MathHelper; @@ -153,7 +151,6 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl } class BarInst implements Bar, NbtSerialisable { - private final DataTracker tracker; private final DataTracker.Entry marker; private final float max; @@ -162,17 +159,16 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl private float prevValue; BarInst(DataTracker tracker, float max, float initial) { - this.tracker = tracker; this.max = max; this.trailingValue = initial; this.prevTrailingValue = initial; this.prevValue = initial; - this.marker = tracker.startTracking(TrackableDataType.of(PacketCodec.FLOAT), max * trailingValue); + this.marker = tracker.startTracking(TrackableDataType.FLOAT, max * trailingValue); } @Override public float get() { - return applyLimits(tracker.get(marker)); + return applyLimits(marker.get()); } @Override @@ -191,7 +187,7 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl } private void load(float value) { - tracker.set(marker, value); + marker.set(value); } protected float getInitial(float initial) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java index edd6f65f..decc9b12 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java @@ -3,8 +3,6 @@ package com.minelittlepony.unicopia.entity.player; import com.minelittlepony.unicopia.ability.magic.Levelled; import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.network.track.TrackableDataType; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; - import net.minecraft.sound.*; import net.minecraft.util.math.MathHelper; @@ -12,7 +10,6 @@ class PlayerLevelStore implements Levelled.LevelStore { private final Pony pony; - private final DataTracker tracker; private final DataTracker.Entry dataEntry; private final boolean upgradeMana; @@ -21,8 +18,7 @@ class PlayerLevelStore implements Levelled.LevelStore { PlayerLevelStore(Pony pony, DataTracker tracker, boolean upgradeMana, SoundEvent levelUpSound) { this.pony = pony; - this.tracker = tracker; - this.dataEntry = tracker.startTracking(TrackableDataType.of(PacketCodec.INT), 0); + this.dataEntry = tracker.startTracking(TrackableDataType.INT, 0); this.upgradeMana = upgradeMana; this.levelUpSound = levelUpSound; } @@ -45,11 +41,11 @@ class PlayerLevelStore implements Levelled.LevelStore { @Override public int get() { - return tracker.get(dataEntry); + return dataEntry.get(); } @Override public void set(int level) { - tracker.set(dataEntry, MathHelper.clamp(level, 0, getMax())); + dataEntry.set(MathHelper.clamp(level, 0, getMax())); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 3546231d..d9e270ba 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -35,7 +35,6 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.util.*; import com.minelittlepony.unicopia.network.*; import com.minelittlepony.unicopia.network.track.DataTracker; -import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.server.world.UGameRules; import com.minelittlepony.common.util.animation.LinearInterpolator; import com.google.common.collect.Streams; @@ -117,8 +116,8 @@ public class Pony extends Living implements Copyable, Update sender.accept(Channel.SERVER_PLAYER_CAPABILITIES.toPacket(new MsgPlayerCapabilities(this))); } }); - race = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); - suppressedRace = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); + race = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.HUMAN); + suppressedRace = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.HUMAN); this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); this.corruption = new PlayerLevelStore(this, tracker, false, USounds.ENTITY_PLAYER_CORRUPTION); this.mana = addTicker(new ManaContainer(this, tracker)); @@ -203,7 +202,7 @@ public class Pony extends Living implements Copyable, Update */ @Override public Race getSpecies() { - return tracker.get(race); + return race.get(); } /** @@ -227,7 +226,7 @@ public class Pony extends Living implements Copyable, Update public void setSpecies(Race race) { race = race.validate(entity); Race current = getSpecies(); - tracker.set(this.race, race); + this.race.set(race); if (race != current) { clearSuppressedRace(); } @@ -240,7 +239,7 @@ public class Pony extends Living implements Copyable, Update } public void setSuppressedRace(Race race) { - tracker.set(suppressedRace, race.validate(entity)); + suppressedRace.set(race.validate(entity)); } public void clearSuppressedRace() { @@ -248,7 +247,7 @@ public class Pony extends Living implements Copyable, Update } public Race getSuppressedRace() { - return tracker.get(suppressedRace); + return suppressedRace.get(); } public TraitDiscovery getDiscoveries() { diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index b730d475..517dccd9 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -5,8 +5,6 @@ import java.util.List; import java.util.Objects; import org.jetbrains.annotations.Nullable; -import com.minelittlepony.unicopia.util.serialization.PacketCodec; - import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; @@ -31,13 +29,13 @@ public class DataTracker { } public Entry startTracking(T value) { - Entry entry = startTracking(TrackableDataType.of(PacketCodec.NBT), value.toTrackedNbt()); + Entry entry = startTracking(TrackableDataType.NBT, value.toTrackedNbt()); persistentObjects.put(entry.id(), value); return entry; } public Entry startTracking(TrackableDataType type, T initialValue) { - Entry entry = new Entry<>(codecs.size()); + Entry entry = new Entry<>(this, codecs.size()); codecs.add(new Pair<>(entry.id(), type, initialValue)); return entry; } @@ -47,11 +45,11 @@ public class DataTracker { return (Pair)codecs.get(entry.id()); } - public T get(Entry entry) { + private T get(Entry entry) { return getPair(entry).value; } - public void set(Entry entry, T value) { + private void set(Entry entry, T value) { if (manager.isClient) { return; } @@ -128,7 +126,15 @@ public class DataTracker { } } - public record Entry(int id) {} + public record Entry(DataTracker tracker, int id) { + public T get() { + return tracker.get(this); + } + + public void set(T t) { + tracker.set(this, t); + } + } static class Pair { private final TrackableDataType type; public final int id; @@ -142,7 +148,7 @@ public class DataTracker { public Pair(PacketByteBuf buffer) { this.id = buffer.readInt(); - this.type = TrackableDataType.of(buffer.readInt()); + this.type = TrackableDataType.of(buffer); this.value = type.read(buffer); } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java index 6b4500a4..620edcca 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java @@ -1,30 +1,40 @@ package com.minelittlepony.unicopia.network.track; -import java.util.ArrayList; -import java.util.List; - -import com.google.common.collect.Interner; -import com.google.common.collect.Interners; +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.util.serialization.PacketCodec; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; public record TrackableDataType(int id, PacketCodec codec) { - private static final List> REGISTRY = new ArrayList<>(); - private static final Interner> INTERNER = Interners.newStrongInterner(); + private static final Int2ObjectMap> REGISTRY = new Int2ObjectOpenHashMap<>(); + + public static final TrackableDataType INT = of(new Identifier("integer"), PacketCodec.INT); + public static final TrackableDataType FLOAT = of(new Identifier("float"), PacketCodec.FLOAT); + public static final TrackableDataType BOOLEAN = of(new Identifier("boolean"), PacketCodec.BOOLEAN); + public static final TrackableDataType UUID = of(new Identifier("uuid"), PacketCodec.UUID); + public static final TrackableDataType NBT = of(new Identifier("nbt"), PacketCodec.NBT); + + public static final TrackableDataType> OPTIONAL_POS = of(new Identifier("optional_pos"), PacketCodec.OPTIONAL_POS); + public static final TrackableDataType RACE = TrackableDataType.of(Unicopia.id("race"), PacketCodec.ofRegistry(Race.REGISTRY)); @SuppressWarnings("unchecked") - public static TrackableDataType of(int id) { - return (TrackableDataType)REGISTRY.get(id); + public static TrackableDataType of(PacketByteBuf buffer) { + int id = buffer.readInt(); + return Objects.requireNonNull((TrackableDataType)REGISTRY.get(id), "Unknown trackable data type id: " + id); } - public static TrackableDataType of(PacketCodec codec) { - @SuppressWarnings("unchecked") - TrackableDataType type = (TrackableDataType) INTERNER.intern(new TrackableDataType<>(REGISTRY.size(), codec)); - if (type.id() == REGISTRY.size()) { - REGISTRY.add(type); - } - return type; + @SuppressWarnings("unchecked") + public static TrackableDataType of(Identifier typeName, PacketCodec codec) { + return (TrackableDataType)REGISTRY.computeIfAbsent(typeName.hashCode(), t -> new TrackableDataType<>(t, codec)); } public T read(PacketByteBuf buffer) { @@ -32,7 +42,7 @@ public record TrackableDataType(int id, PacketCodec codec) { } public void write(PacketByteBuf buffer, T value) { - buffer.writeInt(id()); + buffer.writeInt(id); codec().write(buffer, value); } } From 575c1f74382898e559211ae6f3a7d5aba1ca262c Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 22 May 2024 21:21:08 +0100 Subject: [PATCH 42/85] Fixed placed spells not playing their death animations and/or getting stuck and impossible to remove --- .../ability/magic/spell/AbstractDelegatingSpell.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index 70cbef36..5ad87443 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -48,24 +48,26 @@ public abstract class AbstractDelegatingSpell implements Spell { @Override public void setDead() { - Spell spell = delegate.get(); - if (spell != null) { - spell.setDead(); + if (delegate.get() instanceof Spell p) { + p.setDead(); } } @Override public void tickDying(Caster caster) { + if (delegate.get() instanceof Spell p) { + p.tickDying(caster); + } } @Override public boolean isDead() { - return delegate.get() == null || delegate.get().isDead(); + return !(delegate.get() instanceof Spell p) || p.isDead(); } @Override public boolean isDying() { - return false; + return delegate.get() instanceof Spell p && p.isDying(); } @Override From 77de42dd09d93511c4ae1a07a22affdc49aa7dc4 Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 22 May 2024 21:21:34 +0100 Subject: [PATCH 43/85] Split the placed spell into separate types --- .../ability/magic/spell/OrientedSpell.java | 7 +- .../ability/magic/spell/PlaceableSpell.java | 230 +++++------------- .../magic/spell/PlacementControlSpell.java | 165 +++++++++++++ .../unicopia/ability/magic/spell/Spell.java | 4 +- .../magic/spell/effect/PortalSpell.java | 22 +- .../ability/magic/spell/effect/SpellType.java | 2 + .../client/gui/DismissSpellScreen.java | 4 +- .../render/spell/PlacedSpellRenderer.java | 10 +- .../unicopia/command/CastCommand.java | 8 +- .../unicopia/entity/mob/CastSpellEntity.java | 10 +- .../network/MsgCasterLookRequest.java | 7 +- .../unicopia/server/world/Ether.java | 2 +- .../unicopia/util/NbtSerialisable.java | 1 - 13 files changed, 261 insertions(+), 211 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/OrientedSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/OrientedSpell.java index 38d35171..59a05850 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/OrientedSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/OrientedSpell.java @@ -1,11 +1,12 @@ package com.minelittlepony.unicopia.ability.magic.spell; import com.minelittlepony.unicopia.ability.data.Rot; +import com.minelittlepony.unicopia.ability.magic.Caster; public interface OrientedSpell extends Spell { - void setOrientation(float pitch, float yaw); + void setOrientation(Caster caster, float pitch, float yaw); - default void setOrientation(Rot rotation) { - setOrientation(rotation.pitch(), rotation.yaw()); + default void setOrientation(Caster caster, Rot rotation) { + setOrientation(caster, rotation.pitch(), rotation.yaw()); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index 3738f171..83c56ddf 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -1,28 +1,16 @@ package com.minelittlepony.unicopia.ability.magic.spell; -import java.util.*; - -import org.jetbrains.annotations.Nullable; +import java.util.UUID; import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell.PlacementDelegate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.entity.EntityReference; -import com.minelittlepony.unicopia.entity.EntityReference.EntityValues; -import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; -import com.minelittlepony.unicopia.entity.mob.UEntities; -import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.network.Channel; -import com.minelittlepony.unicopia.network.MsgCasterLookRequest; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.server.world.Ether; -import com.minelittlepony.unicopia.util.NbtSerialisable; +import net.minecraft.entity.Entity; import net.minecraft.nbt.*; -import net.minecraft.registry.*; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; /** * A spell that can be attached to a specific location in the world. @@ -33,29 +21,8 @@ import net.minecraft.world.World; * When cast two copies of this spell are created. One is attached to the player and is the controlling spell, * the other is attached to a cast spell entity and placed in the world. * - * TODO: Split this up into separate classes. */ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedSpell { - /** - * Dimension the spell was originally cast in - */ - @Nullable - private RegistryKey dimension; - - /** - * ID of the placed counterpart of this spell. - */ - @Nullable - private UUID placedSpellId; - - /** - * The cast spell entity - */ - private final EntityReference castEntity = new EntityReference<>(); - - public float pitch; - public float yaw; - private int prevAge; private int age; @@ -63,15 +30,35 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS private int prevDeathTicks; private int deathTicks; - private Optional position = Optional.empty(); + private UUID controllingEntityUuid; + private UUID controllingSpellUuid; + + public float pitch; + public float yaw; public PlaceableSpell(CustomisedSpellType type) { super(type); } - public PlaceableSpell setSpell(Spell spell) { - delegate.set(spell); - return this; + PlaceableSpell(Caster caster, PlacementControlSpell control, Spell delegate) { + this(SpellType.PLACED_SPELL.withTraits()); + this.controllingEntityUuid = caster.asEntity().getUuid(); + this.controllingSpellUuid = control.getUuid(); + this.delegate.set(delegate); + + if (delegate instanceof PlacementDelegate s) { + s.onPlaced(caster, control); + } + } + + @Override + public boolean apply(Caster caster) { + boolean result = super.apply(caster); + if (result && !caster.isClient()) { + Ether.get(caster.asWorld()).getOrCreate(this, caster); + } + setDirty(); + return result; } public float getAge(float tickDelta) { @@ -86,7 +73,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public boolean isDying() { - return dead && deathTicks > 0; + return dead && deathTicks > 0 || super.isDying(); } @Override @@ -94,6 +81,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS super.setDead(); dead = true; deathTicks = 20; + setDirty(); } @Override @@ -103,126 +91,47 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public boolean tick(Caster source, Situation situation) { - if (situation == Situation.BODY) { - if (!source.isClient()) { - if (dimension == null) { - dimension = source.asWorld().getRegistryKey(); - if (source instanceof Pony) { - Channel.SERVER_REQUEST_PLAYER_LOOK.sendToPlayer(new MsgCasterLookRequest(getUuid()), (ServerPlayerEntity)source.asEntity()); - } - setDirty(); - } - - castEntity.getTarget().ifPresentOrElse( - target -> checkDetachment(source, target), - () -> spawnPlacedEntity(source) - ); - } - - return !isDead(); + if (!source.isClient() && !checkConnection(source)) { + setDead(); + return false; } - if (situation == Situation.GROUND_ENTITY) { - if (!source.isClient()) { - if (Ether.get(source.asWorld()).get(this, source) == null) { - setDead(); - return false; - } - } - - prevAge = age; - if (age < 25) { - age++; - } - - return super.tick(source, Situation.GROUND); + prevAge = age; + if (age < 25) { + age++; } - return !isDead(); + return super.tick(source, Situation.GROUND); + } + + private boolean checkConnection(Caster source) { + return Ether.get(source.asWorld()).get(SpellType.PLACE_CONTROL_SPELL, controllingEntityUuid, controllingSpellUuid) != null; } @Override public void tickDying(Caster caster) { + super.tickDying(caster); prevDeathTicks = deathTicks; deathTicks--; } - private void checkDetachment(Caster source, EntityValues target) { - if (getWorld(source).map(Ether::get).map(ether -> ether.get(getTypeAndTraits().type(), target, placedSpellId)).isEmpty()) { - setDead(); - } - } - - private void spawnPlacedEntity(Caster source) { - CastSpellEntity entity = UEntities.CAST_SPELL.create(source.asWorld()); - Vec3d pos = getPosition().orElse(position.orElse(source.asEntity().getPos())); - entity.updatePositionAndAngles(pos.x, pos.y, pos.z, source.asEntity().getYaw(), source.asEntity().getPitch()); - PlaceableSpell copy = delegate.get().toPlaceable(); - if (delegate.get() instanceof PlacementDelegate delegate) { - delegate.onPlaced(source, copy, entity); - } - entity.getSpellSlot().put(copy); - entity.setCaster(source); - entity.getWorld().spawnEntity(entity); - placedSpellId = copy.getUuid(); - Ether.get(entity.getWorld()).getOrCreate(copy, entity); - - castEntity.set(entity); - setDirty(); - } - - @Override - public void setOrientation(float pitch, float yaw) { - this.pitch = -90 - pitch; - this.yaw = -yaw; - if (delegate.get() instanceof OrientedSpell o) { - o.setOrientation(pitch, yaw); - } - setDirty(); - } - - public void setPosition(Caster source, Vec3d position) { - this.position = Optional.of(position); - this.dimension = source.asWorld().getRegistryKey(); - castEntity.ifPresent(source.asWorld(), entity -> { - entity.updatePositionAndAngles(position.x, position.y, position.z, entity.getYaw(), entity.getPitch()); - }); - if (delegate.get() instanceof PlaceableSpell o) { - o.setPosition(source, position); - } - setDirty(); - } - @Override protected void onDestroyed(Caster source) { if (!source.isClient()) { - castEntity.getTarget().ifPresent(target -> { - getWorld(source).map(Ether::get) - .ifPresent(ether -> ether.remove(getTypeAndTraits().type(), target.uuid())); - }); - castEntity.set(null); - getSpellEntity(source).ifPresent(e -> { - castEntity.set(null); - }); - - if (source.asEntity() instanceof CastSpellEntity) { - Ether.get(source.asWorld()).remove(this, source); - } + Ether.get(source.asWorld()).remove(this, source); } super.onDestroyed(source); } - public Optional getSpellEntity(Caster source) { - return getWorld(source).map(castEntity::get); - } - - public Optional getPosition() { - return castEntity.getTarget().map(EntityValues::pos); - } - - protected Optional getWorld(Caster source) { - return Optional.ofNullable(dimension) - .map(dim -> source.asWorld().getServer().getWorld(dim)); + @Override + public void setOrientation(Caster caster, float pitch, float yaw) { + this.pitch = -pitch - 90; + this.yaw = -yaw; + Entity entity = caster.asEntity(); + entity.updatePositionAndAngles(entity.getX(), entity.getY(), entity.getZ(), this.yaw, this.pitch); + entity.setYaw(this.yaw); + entity.setPitch(this.pitch); + setDirty(); } @Override @@ -233,17 +142,12 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS compound.putInt("age", age); compound.putFloat("pitch", pitch); compound.putFloat("yaw", yaw); - position.ifPresent(pos -> { - compound.put("position", NbtSerialisable.writeVector(pos)); - }); - if (placedSpellId != null) { - compound.putUuid("placedSpellId", placedSpellId); + if (controllingEntityUuid != null) { + compound.putUuid("owningEntity", controllingEntityUuid); } - if (dimension != null) { - compound.putString("dimension", dimension.getValue().toString()); + if (controllingSpellUuid != null) { + compound.putUuid("owningSpell", controllingSpellUuid); } - compound.put("castEntity", castEntity.toNBT()); - } @Override @@ -252,27 +156,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS dead = compound.getBoolean("dead"); deathTicks = compound.getInt("deathTicks"); age = compound.getInt("age"); + controllingEntityUuid = compound.containsUuid("owningEntity") ? compound.getUuid("owningEntity") : null; + controllingSpellUuid = compound.containsUuid("owningSpell") ? compound.getUuid("owningSpell") : null; pitch = compound.getFloat("pitch"); yaw = compound.getFloat("yaw"); - position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.FLOAT_TYPE))) : Optional.empty(); - placedSpellId = compound.containsUuid("placedSpellId") ? compound.getUuid("placedSpellId") : null; - if (compound.contains("dimension", NbtElement.STRING_TYPE)) { - Identifier id = Identifier.tryParse(compound.getString("dimension")); - if (id != null) { - dimension = RegistryKey.of(RegistryKeys.WORLD, id); - } - } - if (compound.contains("castEntity")) { - castEntity.fromNBT(compound.getCompound("castEntity")); - } - } - - @Override - public PlaceableSpell toPlaceable() { - return this; - } - - public interface PlacementDelegate { - void onPlaced(Caster source, PlaceableSpell parent, CastSpellEntity entity); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java new file mode 100644 index 00000000..d54b3e8f --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java @@ -0,0 +1,165 @@ +package com.minelittlepony.unicopia.ability.magic.spell; + +import java.util.Optional; +import java.util.UUID; + +import org.jetbrains.annotations.Nullable; +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.entity.EntityReference; +import com.minelittlepony.unicopia.entity.EntityReference.EntityValues; +import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; +import com.minelittlepony.unicopia.entity.mob.UEntities; +import com.minelittlepony.unicopia.server.world.Ether; +import com.minelittlepony.unicopia.util.NbtSerialisable; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class PlacementControlSpell extends AbstractDelegatingSpell implements OrientedSpell { + @Nullable + private UUID placedSpellId; + private final EntityReference castEntity = new EntityReference<>(); + + private Optional> dimension = Optional.empty(); + private Optional position = Optional.empty(); + private Optional orientation = Optional.empty(); + + public PlacementControlSpell(CustomisedSpellType type) { + super(type); + } + + PlacementControlSpell(CustomisedSpellType type, Spell delegate) { + super(type); + this.delegate.set(delegate); + } + + public Optional getPosition() { + return position; + } + + public void setDimension(RegistryKey dimension) { + this.dimension = Optional.of(dimension); + } + + public void setPosition(Vec3d position) { + this.position = Optional.of(position); + } + + @Override + public void setOrientation(Caster caster, float pitch, float yaw) { + this.orientation = Optional.of(new Vec3d(pitch, yaw, 0)); + castEntity.ifPresent(caster.asWorld(), entity -> { + entity.getSpellSlot().stream(SpellPredicate.IS_ORIENTED).forEach(spell -> { + if (!getTypeAndTraits().type().test(spell)) { + spell.setOrientation(caster, pitch, yaw); + } + }); + }); + setDirty(); + } + + @Override + public boolean apply(Caster caster) { + boolean result = super.apply(caster); + if (result) { + if (!caster.isClient()) { + Ether.get(caster.asWorld()).getOrCreate(this, caster); + } + if (dimension.isEmpty()) { + setDimension(caster.asWorld().getRegistryKey()); + } + if (position.isEmpty()) { + setPosition(caster.asEntity().getPos()); + } + } + return result; + } + + @Override + public boolean tick(Caster source, Situation situation) { + if (!source.isClient()) { + Ether.get(source.asWorld()).getOrCreate(this, source); + castEntity.getTarget().ifPresentOrElse(target -> { + if (!checkConnection(source, target)) { + setDead(); + } + }, () -> spawnPlacedEntity(source)); + } + return !isDead(); + } + + private void spawnPlacedEntity(Caster source) { + PlaceableSpell copy = new PlaceableSpell(source, this, getDelegate()); + + Vec3d pos = position.orElse(source.asEntity().getPos()); + Vec3d rot = orientation.orElse(Vec3d.ZERO); + + CastSpellEntity entity = UEntities.CAST_SPELL.create(source.asWorld()); + entity.setCaster(source); + entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x); + entity.setYaw((float)rot.y); + entity.setPitch((float)rot.x); + copy.apply(entity); + entity.getWorld().spawnEntity(entity); + + placedSpellId = copy.getUuid(); + castEntity.set(entity); + setDirty(); + } + + private boolean checkConnection(Caster source, EntityValues target) { + return getWorld(source) + .map(Ether::get) + .map(ether -> ether.get(SpellType.PLACED_SPELL, target, placedSpellId)) + .isPresent(); + } + + private Optional getWorld(Caster source) { + return dimension.map(source.asWorld().getServer()::getWorld); + } + + @Override + protected void onDestroyed(Caster source) { + if (!source.isClient()) { + Ether.get(source.asWorld()).remove(this, source); + } + super.onDestroyed(source); + } + + @Override + public void toNBT(NbtCompound compound) { + super.toNBT(compound); + position.ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos))); + orientation.ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o))); + dimension.ifPresent(d -> compound.putString("dimension", d.getValue().toString())); + if (placedSpellId != null) { + compound.putUuid("placedSpellId", placedSpellId); + } + compound.put("castEntity", castEntity.toNBT()); + + } + + @Override + public void fromNBT(NbtCompound compound) { + super.fromNBT(compound); + placedSpellId = compound.containsUuid("placedSpellId") ? compound.getUuid("placedSpellId") : null; + position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.FLOAT_TYPE))) : Optional.empty(); + orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.FLOAT_TYPE))) : Optional.empty(); + if (compound.contains("dimension", NbtElement.STRING_TYPE)) { + dimension = Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id)); + } + castEntity.fromNBT(compound.getCompound("castEntity")); + } + + public interface PlacementDelegate { + void onPlaced(Caster source, PlacementControlSpell parent); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index 4258b079..8ede5a8b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -123,8 +123,8 @@ public interface Spell extends NbtSerialisable, Affine { /** * Converts this spell into a placeable spell. */ - default PlaceableSpell toPlaceable() { - return SpellType.PLACED_SPELL.withTraits().create().setSpell(this); + default PlacementControlSpell toPlaceable() { + return new PlacementControlSpell(SpellType.PLACE_CONTROL_SPELL.withTraits(), this); } /** diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java index fea666b7..fff35722 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java @@ -13,7 +13,9 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.Living; -import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; +import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.network.Channel; +import com.minelittlepony.unicopia.network.MsgCasterLookRequest; import com.minelittlepony.unicopia.particle.*; import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.shape.*; @@ -25,13 +27,14 @@ import net.minecraft.entity.LivingEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.network.packet.s2c.play.PositionFlag; import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.WorldEvents; -public class PortalSpell extends AbstractSpell implements PlaceableSpell.PlacementDelegate, OrientedSpell { +public class PortalSpell extends AbstractSpell implements PlacementControlSpell.PlacementDelegate, OrientedSpell { public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() .with(Trait.LIFE, 10) .with(Trait.KNOWLEDGE, 1) @@ -91,7 +94,7 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme @Override public boolean apply(Caster caster) { - setOrientation(caster.asEntity().getPitch(), caster.asEntity().getYaw()); + setOrientation(caster, caster.asEntity().getPitch(), caster.asEntity().getYaw()); return toPlaceable().apply(caster); } @@ -195,22 +198,25 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme } @Override - public void setOrientation(float pitch, float yaw) { + public void setOrientation(Caster caster, float pitch, float yaw) { this.pitch = pitch; this.yaw = yaw; particleArea = PARTICLE_AREA.rotate( pitch * MathHelper.RADIANS_PER_DEGREE, - (180 - yaw) * MathHelper.RADIANS_PER_DEGREE + yaw * MathHelper.RADIANS_PER_DEGREE ); setDirty(); } @Override - public void onPlaced(Caster source, PlaceableSpell parent, CastSpellEntity entity) { + public void onPlaced(Caster source, PlacementControlSpell parent) { + parent.setOrientation(source, source.asEntity().getPitch(), source.asEntity().getYaw()); LivingEntity caster = source.getMaster(); Vec3d targetPos = caster.getRotationVector().multiply(3).add(caster.getEyePos()); - parent.setOrientation(pitch, yaw); - entity.setPos(targetPos.x, Math.abs(pitch) > 15 ? targetPos.y : caster.getPos().y, targetPos.z); + parent.setPosition(new Vec3d(targetPos.x, caster.getPos().y, targetPos.z)); + if (source instanceof Pony pony) { + Channel.SERVER_REQUEST_PLAYER_LOOK.sendToPlayer(new MsgCasterLookRequest(parent.getUuid()), (ServerPlayerEntity)pony.asEntity()); + } } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index 6bbf0219..c35911d5 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell; import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell; +import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell; import com.minelittlepony.unicopia.ability.magic.spell.RageAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell; @@ -43,6 +44,7 @@ public final class SpellType implements Affine, SpellPredicate< private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id)); + public static final SpellType PLACE_CONTROL_SPELL = register("place_controller", SpellType.builder(PlacementControlSpell::new).affinity(Affinity.NEUTRAL).unobtainable().stackable().shape(GemstoneItem.Shape.DONUT)); public static final SpellType PLACED_SPELL = register("placed", builder(PlaceableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().stackable().shape(GemstoneItem.Shape.DONUT)); public static final SpellType THROWN_SPELL = register("thrown", builder(ThrowableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().shape(GemstoneItem.Shape.DONUT)); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 873f7d10..85a5bd85 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -40,11 +40,11 @@ public class DismissSpellScreen extends GameGui { double azimuth = 0; double ring = 2; - List placeableSpells = new ArrayList<>(); + List placeableSpells = new ArrayList<>(); for (Spell spell : pony.getSpellSlot().stream().filter(SpellPredicate.IS_VISIBLE).toList()) { - if (spell instanceof PlaceableSpell placeable) { + if (spell instanceof PlacementControlSpell placeable) { if (placeable.getPosition().isPresent()) { placeableSpells.add(placeable); continue; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java index f0676140..856064d8 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java @@ -6,7 +6,6 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.client.render.model.PlaneModel; -import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.VertexConsumer; @@ -27,12 +26,7 @@ public class PlacedSpellRenderer extends SpellRenderer { @Override public void render(MatrixStack matrices, VertexConsumerProvider vertices, PlaceableSpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { - if (!(caster.asEntity() instanceof CastSpellEntity castSpell)) { - return; - } - matrices.push(); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-castSpell.getYaw())); Spell delegate = spell.getDelegate(); @@ -42,8 +36,8 @@ public class PlacedSpellRenderer extends SpellRenderer { matrices.push(); float height = caster.asEntity().getHeight(); matrices.translate(0, (-spell.pitch / 90F) * height * 0.5F, 0); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(spell.yaw)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-spell.pitch)); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw)); SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertices, delegate, caster, light, spell.getScale(tickDelta), limbDistance, tickDelta, animationProgress, headYaw, headPitch); matrices.pop(); } @@ -58,8 +52,8 @@ public class PlacedSpellRenderer extends SpellRenderer { float height = caster.asEntity().getHeight(); matrices.translate(0, (-spell.pitch / 90F) * height * 0.5F, 0); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(spell.yaw)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-spell.pitch)); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); float scale = spell.getScale(tickDelta) * 3; diff --git a/src/main/java/com/minelittlepony/unicopia/command/CastCommand.java b/src/main/java/com/minelittlepony/unicopia/command/CastCommand.java index 1983c550..e3c63072 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/CastCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/CastCommand.java @@ -4,7 +4,7 @@ import java.util.Optional; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; -import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell; +import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; @@ -98,11 +98,11 @@ public class CastCommand { private static int placed(CommandContext source, TraitsFunc traits, Optional position, Vec2f rotation) throws CommandSyntaxException { ServerPlayerEntity player = source.getSource().getPlayerOrThrow(); - PlaceableSpell spell = getSpell(source, traits).create().toPlaceable(); + PlacementControlSpell spell = getSpell(source, traits).create().toPlaceable(); Caster caster = Caster.of(player).orElseThrow(); - spell.setOrientation(rotation.x, rotation.y); - position.ifPresent(pos -> spell.setPosition(caster, pos)); + spell.setOrientation(caster, rotation.x, rotation.y); + position.ifPresent(spell::setPosition); spell.apply(caster); return 0; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 01cbf06b..2ae93d61 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -81,12 +81,10 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster { - spell.setOrientation(rotation); - }); + .ifPresent(spell -> spell.setOrientation(pony, rotation)); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index 10110d70..f0982276 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -113,7 +113,7 @@ public class Ether extends PersistentState { @SuppressWarnings("unchecked") @Nullable - private Entry get(SpellType spell, UUID entityId, @Nullable UUID spellId) { + public Entry get(SpellType spell, UUID entityId, @Nullable UUID spellId) { if (spellId == null) { return null; } diff --git a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java index 54093f51..1dcf0bba 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java +++ b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java @@ -46,7 +46,6 @@ public interface NbtSerialisable { } static Vec3d readVector(NbtList list) { - return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2)); } From 8a093a8a8bc2f58bc28430d643f87145f77d711c Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 May 2024 12:53:11 +0100 Subject: [PATCH 44/85] Sync all spells onto the ether --- .../magic/spell/AbstractDelegatingSpell.java | 5 + .../magic/spell/AbstractDisguiseSpell.java | 5 +- .../ability/magic/spell/PlaceableSpell.java | 40 ++++--- .../magic/spell/PlacementControlSpell.java | 102 ++++++++---------- .../unicopia/ability/magic/spell/Spell.java | 4 + .../magic/spell/effect/AbstractSpell.java | 10 +- .../spell/effect/AreaProtectionSpell.java | 5 - .../magic/spell/effect/BubbleSpell.java | 1 + .../magic/spell/effect/DisplacementSpell.java | 1 + .../magic/spell/effect/HydrophobicSpell.java | 7 +- .../magic/spell/effect/LightSpell.java | 1 + .../magic/spell/effect/NecromancySpell.java | 1 + .../magic/spell/effect/PortalSpell.java | 24 ++--- .../magic/spell/effect/ShieldSpell.java | 3 + .../client/gui/DismissSpellScreen.java | 7 +- .../unicopia/server/world/Ether.java | 49 ++++++++- 16 files changed, 154 insertions(+), 111 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index 5ad87443..79ed5954 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -6,6 +6,8 @@ import java.util.stream.Stream; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.server.world.Ether; + import net.minecraft.nbt.NbtCompound; public abstract class AbstractDelegatingSpell implements Spell { @@ -101,6 +103,9 @@ public abstract class AbstractDelegatingSpell implements Spell { } protected void onDestroyed(Caster caster) { + if (!caster.isClient()) { + Ether.get(caster.asWorld()).remove(this, caster); + } if (delegate.get() instanceof Spell s) { s.destroy(caster); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java index 14a35e99..41e7c996 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java @@ -28,10 +28,11 @@ public abstract class AbstractDisguiseSpell extends AbstractSpell implements Dis @Override protected void onDestroyed(Caster caster) { + super.onDestroyed(caster); caster.asEntity().calculateDimensions(); caster.asEntity().setInvisible(false); - if (caster instanceof Pony) { - ((Pony) caster).setInvisible(false); + if (caster instanceof Pony pony) { + pony.setInvisible(false); } disguise.remove(); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index 83c56ddf..548e66ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -51,16 +51,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS } } - @Override - public boolean apply(Caster caster) { - boolean result = super.apply(caster); - if (result && !caster.isClient()) { - Ether.get(caster.asWorld()).getOrCreate(this, caster); - } - setDirty(); - return result; - } - public float getAge(float tickDelta) { return MathHelper.lerp(tickDelta, prevAge, age); } @@ -91,9 +81,16 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public boolean tick(Caster source, Situation situation) { - if (!source.isClient() && !checkConnection(source)) { - setDead(); - return false; + if (!source.isClient()) { + if (!checkConnection(source)) { + setDead(); + return true; + } + + var entry = Ether.get(source.asWorld()).get(this, source); + if (entry != null && entry.hasChanged()) { + setOrientation(source, entry.getPitch(), entry.getYaw()); + } } prevAge = age; @@ -115,14 +112,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS deathTicks--; } - @Override - protected void onDestroyed(Caster source) { - if (!source.isClient()) { - Ether.get(source.asWorld()).remove(this, source); - } - super.onDestroyed(source); - } - @Override public void setOrientation(Caster caster, float pitch, float yaw) { this.pitch = -pitch - 90; @@ -131,6 +120,15 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS entity.updatePositionAndAngles(entity.getX(), entity.getY(), entity.getZ(), this.yaw, this.pitch); entity.setYaw(this.yaw); entity.setPitch(this.pitch); + + if (!caster.isClient()) { + var entry = Ether.get(caster.asWorld()).get(this, caster); + if (entry != null) { + entry.setPitch(pitch); + entry.setYaw(yaw); + } + } + setDirty(); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java index d54b3e8f..6103890b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java @@ -5,11 +5,9 @@ import java.util.UUID; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.SpellPredicate; +import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; -import com.minelittlepony.unicopia.entity.EntityReference; -import com.minelittlepony.unicopia.entity.EntityReference.EntityValues; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.server.world.Ether; @@ -23,15 +21,18 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -public class PlacementControlSpell extends AbstractDelegatingSpell implements OrientedSpell { +public class PlacementControlSpell extends AbstractSpell implements OrientedSpell { @Nullable private UUID placedSpellId; - private final EntityReference castEntity = new EntityReference<>(); + @Nullable + private UUID placedEntityId; private Optional> dimension = Optional.empty(); private Optional position = Optional.empty(); private Optional orientation = Optional.empty(); + private SpellReference delegate = new SpellReference<>(); + public PlacementControlSpell(CustomisedSpellType type) { super(type); } @@ -41,6 +42,11 @@ public class PlacementControlSpell extends AbstractDelegatingSpell implements Or this.delegate.set(delegate); } + @Nullable + public Spell getDelegate() { + return delegate.get(); + } + public Optional getPosition() { return position; } @@ -56,107 +62,91 @@ public class PlacementControlSpell extends AbstractDelegatingSpell implements Or @Override public void setOrientation(Caster caster, float pitch, float yaw) { this.orientation = Optional.of(new Vec3d(pitch, yaw, 0)); - castEntity.ifPresent(caster.asWorld(), entity -> { - entity.getSpellSlot().stream(SpellPredicate.IS_ORIENTED).forEach(spell -> { - if (!getTypeAndTraits().type().test(spell)) { - spell.setOrientation(caster, pitch, yaw); + setDirty(); + if (!caster.isClient() && placedEntityId != null) { + getWorld(caster).ifPresent(world -> { + var entry = Ether.get(world).get(SpellType.PLACED_SPELL, placedEntityId, placedSpellId); + if (entry != null) { + entry.setPitch(pitch); + entry.setYaw(yaw); } }); - }); - setDirty(); + } } @Override public boolean apply(Caster caster) { boolean result = super.apply(caster); if (result) { - if (!caster.isClient()) { - Ether.get(caster.asWorld()).getOrCreate(this, caster); - } if (dimension.isEmpty()) { setDimension(caster.asWorld().getRegistryKey()); } if (position.isEmpty()) { setPosition(caster.asEntity().getPos()); } + + PlaceableSpell copy = new PlaceableSpell(caster, this, delegate.get()); + + Vec3d pos = position.orElse(caster.asEntity().getPos()); + Vec3d rot = orientation.orElse(Vec3d.ZERO); + + CastSpellEntity entity = UEntities.CAST_SPELL.create(caster.asWorld()); + entity.setCaster(caster); + entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x); + entity.setYaw((float)rot.y); + entity.setPitch((float)rot.x); + copy.apply(entity); + entity.getWorld().spawnEntity(entity); + + placedSpellId = copy.getUuid(); + placedEntityId = entity.getUuid(); + setDirty(); } return result; } @Override public boolean tick(Caster source, Situation situation) { - if (!source.isClient()) { - Ether.get(source.asWorld()).getOrCreate(this, source); - castEntity.getTarget().ifPresentOrElse(target -> { - if (!checkConnection(source, target)) { - setDead(); - } - }, () -> spawnPlacedEntity(source)); + if (!source.isClient() && !checkConnection(source)) { + setDead(); } return !isDead(); } - private void spawnPlacedEntity(Caster source) { - PlaceableSpell copy = new PlaceableSpell(source, this, getDelegate()); - - Vec3d pos = position.orElse(source.asEntity().getPos()); - Vec3d rot = orientation.orElse(Vec3d.ZERO); - - CastSpellEntity entity = UEntities.CAST_SPELL.create(source.asWorld()); - entity.setCaster(source); - entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x); - entity.setYaw((float)rot.y); - entity.setPitch((float)rot.x); - copy.apply(entity); - entity.getWorld().spawnEntity(entity); - - placedSpellId = copy.getUuid(); - castEntity.set(entity); - setDirty(); - } - - private boolean checkConnection(Caster source, EntityValues target) { - return getWorld(source) - .map(Ether::get) - .map(ether -> ether.get(SpellType.PLACED_SPELL, target, placedSpellId)) - .isPresent(); + private boolean checkConnection(Caster source) { + return getWorld(source).map(world -> Ether.get(world).get(SpellType.PLACED_SPELL, placedEntityId, placedSpellId)).isPresent(); } private Optional getWorld(Caster source) { return dimension.map(source.asWorld().getServer()::getWorld); } - @Override - protected void onDestroyed(Caster source) { - if (!source.isClient()) { - Ether.get(source.asWorld()).remove(this, source); - } - super.onDestroyed(source); - } - @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); + compound.put("spell", delegate.toNBT()); position.ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos))); orientation.ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o))); dimension.ifPresent(d -> compound.putString("dimension", d.getValue().toString())); if (placedSpellId != null) { compound.putUuid("placedSpellId", placedSpellId); } - compound.put("castEntity", castEntity.toNBT()); - + if (placedEntityId != null) { + compound.putUuid("placedEntityId", placedEntityId); + } } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); + delegate.fromNBT(compound.getCompound("spell")); placedSpellId = compound.containsUuid("placedSpellId") ? compound.getUuid("placedSpellId") : null; + placedEntityId = compound.containsUuid("placedEntityId") ? compound.getUuid("placedEntityId") : null; position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.FLOAT_TYPE))) : Optional.empty(); orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.FLOAT_TYPE))) : Optional.empty(); if (compound.contains("dimension", NbtElement.STRING_TYPE)) { dimension = Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id)); } - castEntity.fromNBT(compound.getCompound("castEntity")); } public interface PlacementDelegate { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index 8ede5a8b..d087ed0c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.NbtSerialisable; import net.minecraft.nbt.NbtCompound; @@ -81,6 +82,9 @@ public interface Spell extends NbtSerialisable, Affine { */ default boolean apply(Caster caster) { caster.getSpellSlot().put(this); + if (!caster.isClient()) { + Ether.get(caster.asWorld()).getOrCreate(this, caster); + } return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java index ada82e85..f7cef06d 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java @@ -5,6 +5,7 @@ import java.util.UUID; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; +import com.minelittlepony.unicopia.server.world.Ether; import net.minecraft.nbt.NbtCompound; @@ -78,9 +79,6 @@ public abstract class AbstractSpell implements Spell { this.hidden = hidden; } - protected void onDestroyed(Caster caster) { - } - @Override public void tickDying(Caster caster) { dead = true; @@ -96,6 +94,12 @@ public abstract class AbstractSpell implements Spell { onDestroyed(caster); } + protected void onDestroyed(Caster caster) { + if (!caster.isClient()) { + Ether.get(caster.asWorld()).remove(this, caster); + } + } + @Override public void toNBT(NbtCompound compound) { compound.putBoolean("dying", dying); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java index 920c5bd5..5ae9df44 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java @@ -54,11 +54,6 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { return !isDead(); } - @Override - protected void onDestroyed(Caster caster) { - Ether.get(caster.asWorld()).remove(this, caster); - } - /** * Calculates the maximum radius of the shield. aka The area of effect. */ diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index 2cc4dd51..c35227af 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -139,6 +139,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, @Override protected void onDestroyed(Caster source) { + super.onDestroyed(source); if (source.asEntity() instanceof LivingEntity l) { MODIFIERS.forEach((attribute, modifier) -> { if (l.getAttributes().hasAttribute(attribute)) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java index a58b77de..b787778b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java @@ -90,6 +90,7 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro @Override protected void onDestroyed(Caster caster) { + super.onDestroyed(caster); caster.getOriginatingCaster().asEntity().setGlowing(false); target.ifPresent(caster.asWorld(), e -> e.setGlowing(false)); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java index ce21955f..434d6ad7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java @@ -92,8 +92,7 @@ public class HydrophobicSpell extends AbstractSpell { } double range = getRange(source); - var entry = Ether.get(source.asWorld()).getOrCreate(this, source); - entry.radius = (float)range; + Ether.get(source.asWorld()).getOrCreate(this, source).setRadius((float)range); source.spawnParticles(new Sphere(true, range), 10, pos -> { BlockPos bp = BlockPos.ofFloored(pos); @@ -116,7 +115,7 @@ public class HydrophobicSpell extends AbstractSpell { @Override protected void onDestroyed(Caster caster) { - Ether.get(caster.asWorld()).remove(this, caster); + super.onDestroyed(caster); storedFluidPositions.removeIf(entry -> { if (caster.canModifyAt(entry.pos())) { entry.restore(caster.asWorld()); @@ -175,7 +174,7 @@ public class HydrophobicSpell extends AbstractSpell { } public boolean blocksFlow(Ether.Entry entry, Vec3d center, BlockPos pos, FluidState fluid) { - return fluid.isIn(affectedFluid) && pos.isWithinDistance(center, (double)entry.radius + 1); + return fluid.isIn(affectedFluid) && pos.isWithinDistance(center, (double)entry.getRadius() + 1); } public static boolean blocksFluidFlow(BlockView world, BlockPos pos, FluidState state) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java index 8bd9c813..9688b7f7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java @@ -91,6 +91,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD @Override protected void onDestroyed(Caster caster) { + super.onDestroyed(caster); if (caster.isClient()) { return; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java index dbf79bab..910fddd3 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java @@ -153,6 +153,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti @Override protected void onDestroyed(Caster caster) { + super.onDestroyed(caster); if (caster.isClient()) { return; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java index fff35722..944f1365 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java @@ -121,11 +121,9 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. ); } - Ether ether = Ether.get(source.asWorld()); - var entry = ether.getOrCreate(this, source); - entry.pitch = pitch; - entry.yaw = yaw; - ether.markDirty(); + var entry = Ether.get(source.asWorld()).getOrCreate(this, source); + entry.setPitch(pitch); + entry.setYaw(yaw); } return !isDead(); @@ -133,13 +131,9 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. private void tickWithTargetLink(Caster source, Ether.Entry destination) { - if (!MathHelper.approximatelyEquals(targetPortalPitch, destination.pitch)) { - targetPortalPitch = destination.pitch; - setDirty(); - } - if (!MathHelper.approximatelyEquals(targetPortalYaw, destination.yaw)) { - targetPortalYaw = destination.yaw; - setDirty(); + if (destination.hasChanged()) { + targetPortalPitch = destination.getPitch(); + targetPortalYaw = destination.getYaw(); } destination.entity.getTarget().ifPresent(target -> { @@ -221,8 +215,10 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. @Override protected void onDestroyed(Caster caster) { - Ether.get(caster.asWorld()).remove(getType(), caster); - getDestination(caster).ifPresent(Ether.Entry::release); + super.onDestroyed(caster); + if (!caster.isClient()) { + getDestination(caster).ifPresent(Ether.Entry::release); + } } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java index da5e5dc2..541f1033 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java @@ -19,6 +19,7 @@ import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.projectile.ProjectileUtil; +import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.ColorHelper; import com.minelittlepony.unicopia.util.Lerp; import com.minelittlepony.unicopia.util.shape.Sphere; @@ -115,6 +116,8 @@ public class ShieldSpell extends AbstractSpell { if (source.isClient()) { generateParticles(source); + } else { + Ether.get(source.asWorld()).getOrCreate(this, source).setRadius(radius.getValue()); } if (situation == Situation.PROJECTILE) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 85a5bd85..9ff61ac3 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -136,7 +136,9 @@ public class DismissSpellScreen extends GameGui { } private Spell getActualSpell() { - return spell instanceof AbstractDelegatingSpell s && s.getDelegate() instanceof Spell p ? p : spell; + return spell instanceof AbstractDelegatingSpell s && s.getDelegate() instanceof Spell p ? p + : spell instanceof PlacementControlSpell s && s.getDelegate() instanceof Spell p ? p + : spell; } @Override @@ -161,11 +163,10 @@ public class DismissSpellScreen extends GameGui { MatrixStack matrices = context.getMatrices(); var type = actualSpell.getTypeAndTraits(); - var affinity = actualSpell.getAffinity(); copy.set(mouseX - width * 0.5F - x * 0.5F, mouseY - height * 0.5F - y * 0.5F, 0, 0); - DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, affinity.getColor().getColorValue()); + DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, actualSpell.getAffinity().getColor().getColorValue()); DrawableUtil.renderItemIcon(context, actualSpell.isDead() ? UItems.BOTCHED_GEM.getDefaultStack() : type.getDefaultStack(), x - 8 - copy.x * 0.2F, y - 8 - copy.y * 0.2F, diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index f0982276..13707da6 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.server.world; import java.lang.ref.WeakReference; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiPredicate; import java.util.function.Predicate; @@ -15,6 +16,7 @@ import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.util.NbtSerialisable; import net.minecraft.nbt.*; import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.PersistentState; import net.minecraft.world.World; @@ -168,9 +170,10 @@ public class Ether extends PersistentState { private boolean removed; private boolean taken; - public float pitch; - public float yaw; - public float radius; + private float pitch; + private final AtomicBoolean changed = new AtomicBoolean(true); + private float yaw; + private float radius; private Entry(NbtElement nbt) { this.entity = new EntityReference<>(); @@ -184,6 +187,46 @@ public class Ether extends PersistentState { spellId = spell.getUuid(); } + public boolean hasChanged() { + return changed.getAndSet(false); + } + + public float getPitch() { + return pitch; + } + + public void setPitch(float pitch) { + if (!MathHelper.approximatelyEquals(this.pitch, pitch)) { + this.pitch = pitch; + changed.set(true); + } + markDirty(); + } + + public float getYaw() { + return yaw; + } + + public void setYaw(float yaw) { + if (!MathHelper.approximatelyEquals(this.yaw, yaw)) { + this.yaw = yaw; + changed.set(true); + } + markDirty(); + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + if (!MathHelper.approximatelyEquals(this.radius, radius)) { + this.radius = radius; + changed.set(true); + } + markDirty(); + } + boolean isAlive() { return !isDead(); } From 1ecb28e51140a06c72e752a6ca50ee37d62a04c7 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 May 2024 17:02:29 +0100 Subject: [PATCH 45/85] Move placed spell logic into the cast spell entity and fix portals mislinking/multilinking --- .../ability/magic/SpellPredicate.java | 2 - .../magic/spell/AbstractDelegatingSpell.java | 16 +- .../ability/magic/spell/PlaceableSpell.java | 162 ------------------ .../magic/spell/PlacementControlSpell.java | 63 ++++--- .../unicopia/ability/magic/spell/Spell.java | 9 +- .../magic/spell/effect/PortalSpell.java | 113 ++++++------ .../ability/magic/spell/effect/SpellType.java | 2 - .../client/gui/DismissSpellScreen.java | 6 +- .../client/render/HornFeatureRenderer.java | 4 +- .../entity/CastSpellEntityRenderer.java | 74 +++++++- .../render/spell/PlacedSpellRenderer.java | 92 ---------- .../render/spell/PortalFrameBuffer.java | 4 +- .../render/spell/PortalSpellRenderer.java | 7 +- .../spell/SpellEffectsRenderDispatcher.java | 1 - .../unicopia/entity/mob/CastSpellEntity.java | 119 +++++++++++-- .../unicopia/entity/mob/UEntities.java | 2 +- .../unicopia/entity/player/Pony.java | 2 +- .../unicopia/item/EnchantedStaffItem.java | 3 +- .../unicopia/server/world/Ether.java | 45 +++-- 19 files changed, 326 insertions(+), 400 deletions(-) delete mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java delete mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java index 358c4fb6..9a3ab3d2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java @@ -12,14 +12,12 @@ import net.minecraft.entity.Entity; public interface SpellPredicate extends Predicate { SpellPredicate ALL = spell -> true; SpellPredicate CAN_SUPPRESS = s -> s instanceof IllusionarySpell; - SpellPredicate IS_PLACED = s -> s instanceof PlaceableSpell; SpellPredicate IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell; SpellPredicate IS_MIMIC = s -> s instanceof MimicSpell; SpellPredicate IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell; SpellPredicate IS_TIMED = spell -> spell instanceof TimedSpell; SpellPredicate IS_ORIENTED = spell -> spell instanceof OrientedSpell; - SpellPredicate IS_NOT_PLACED = IS_PLACED.negate(); SpellPredicate IS_VISIBLE = spell -> spell != null && !spell.isHidden(); SpellPredicate IS_CORRUPTING = spell -> spell.getAffinity() == Affinity.BAD; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index 79ed5954..b65acecf 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -50,31 +50,31 @@ public abstract class AbstractDelegatingSpell implements Spell { @Override public void setDead() { - if (delegate.get() instanceof Spell p) { - p.setDead(); + if (delegate.get() != null) { + delegate.get().setDead(); } } @Override public void tickDying(Caster caster) { - if (delegate.get() instanceof Spell p) { - p.tickDying(caster); + if (delegate.get() != null) { + delegate.get().tickDying(caster); } } @Override public boolean isDead() { - return !(delegate.get() instanceof Spell p) || p.isDead(); + return delegate.get() == null; } @Override public boolean isDying() { - return delegate.get() instanceof Spell p && p.isDying(); + return delegate.get() != null && delegate.get().isDying(); } @Override public boolean isDirty() { - return dirty || (delegate.get() instanceof Spell p && p.isDirty()); + return dirty || delegate.hasDirtySpell(); } @Override @@ -84,7 +84,7 @@ public abstract class AbstractDelegatingSpell implements Spell { @Override public boolean isHidden() { - return hidden || (delegate.get() instanceof Spell p && p.isHidden()); + return hidden || (delegate.get() != null && delegate.get().isHidden()); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java deleted file mode 100644 index 548e66ea..00000000 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.minelittlepony.unicopia.ability.magic.spell; - -import java.util.UUID; - -import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell.PlacementDelegate; -import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; -import com.minelittlepony.unicopia.server.world.Ether; - -import net.minecraft.entity.Entity; -import net.minecraft.nbt.*; -import net.minecraft.util.math.MathHelper; - -/** - * A spell that can be attached to a specific location in the world. - *

- * The spell's effects are still powered by the casting player, so if the player dies or leaves the area, their - * spell loses affect until they return. - *

- * When cast two copies of this spell are created. One is attached to the player and is the controlling spell, - * the other is attached to a cast spell entity and placed in the world. - * - */ -public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedSpell { - private int prevAge; - private int age; - - private boolean dead; - private int prevDeathTicks; - private int deathTicks; - - private UUID controllingEntityUuid; - private UUID controllingSpellUuid; - - public float pitch; - public float yaw; - - public PlaceableSpell(CustomisedSpellType type) { - super(type); - } - - PlaceableSpell(Caster caster, PlacementControlSpell control, Spell delegate) { - this(SpellType.PLACED_SPELL.withTraits()); - this.controllingEntityUuid = caster.asEntity().getUuid(); - this.controllingSpellUuid = control.getUuid(); - this.delegate.set(delegate); - - if (delegate instanceof PlacementDelegate s) { - s.onPlaced(caster, control); - } - } - - public float getAge(float tickDelta) { - return MathHelper.lerp(tickDelta, prevAge, age); - } - - public float getScale(float tickDelta) { - float add = MathHelper.clamp(getAge(tickDelta) / 25F, 0, 1); - float subtract = dead ? 1 - (MathHelper.lerp(tickDelta, prevDeathTicks, deathTicks) / 20F) : 0; - return MathHelper.clamp(add - subtract, 0, 1); - } - - @Override - public boolean isDying() { - return dead && deathTicks > 0 || super.isDying(); - } - - @Override - public void setDead() { - super.setDead(); - dead = true; - deathTicks = 20; - setDirty(); - } - - @Override - public boolean isDead() { - return dead && deathTicks <= 0 && super.isDead(); - } - - @Override - public boolean tick(Caster source, Situation situation) { - if (!source.isClient()) { - if (!checkConnection(source)) { - setDead(); - return true; - } - - var entry = Ether.get(source.asWorld()).get(this, source); - if (entry != null && entry.hasChanged()) { - setOrientation(source, entry.getPitch(), entry.getYaw()); - } - } - - prevAge = age; - if (age < 25) { - age++; - } - - return super.tick(source, Situation.GROUND); - } - - private boolean checkConnection(Caster source) { - return Ether.get(source.asWorld()).get(SpellType.PLACE_CONTROL_SPELL, controllingEntityUuid, controllingSpellUuid) != null; - } - - @Override - public void tickDying(Caster caster) { - super.tickDying(caster); - prevDeathTicks = deathTicks; - deathTicks--; - } - - @Override - public void setOrientation(Caster caster, float pitch, float yaw) { - this.pitch = -pitch - 90; - this.yaw = -yaw; - Entity entity = caster.asEntity(); - entity.updatePositionAndAngles(entity.getX(), entity.getY(), entity.getZ(), this.yaw, this.pitch); - entity.setYaw(this.yaw); - entity.setPitch(this.pitch); - - if (!caster.isClient()) { - var entry = Ether.get(caster.asWorld()).get(this, caster); - if (entry != null) { - entry.setPitch(pitch); - entry.setYaw(yaw); - } - } - - setDirty(); - } - - @Override - public void toNBT(NbtCompound compound) { - super.toNBT(compound); - compound.putBoolean("dead", dead); - compound.putInt("deathTicks", deathTicks); - compound.putInt("age", age); - compound.putFloat("pitch", pitch); - compound.putFloat("yaw", yaw); - if (controllingEntityUuid != null) { - compound.putUuid("owningEntity", controllingEntityUuid); - } - if (controllingSpellUuid != null) { - compound.putUuid("owningSpell", controllingSpellUuid); - } - } - - @Override - public void fromNBT(NbtCompound compound) { - super.fromNBT(compound); - dead = compound.getBoolean("dead"); - deathTicks = compound.getInt("deathTicks"); - age = compound.getInt("age"); - controllingEntityUuid = compound.containsUuid("owningEntity") ? compound.getUuid("owningEntity") : null; - controllingSpellUuid = compound.containsUuid("owningSpell") ? compound.getUuid("owningSpell") : null; - pitch = compound.getFloat("pitch"); - yaw = compound.getFloat("yaw"); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java index 6103890b..a42cd9a3 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java @@ -7,9 +7,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; -import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.NbtSerialisable; @@ -22,8 +20,6 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class PlacementControlSpell extends AbstractSpell implements OrientedSpell { - @Nullable - private UUID placedSpellId; @Nullable private UUID placedEntityId; @@ -31,20 +27,21 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel private Optional position = Optional.empty(); private Optional orientation = Optional.empty(); - private SpellReference delegate = new SpellReference<>(); + @Nullable + private Spell delegate; public PlacementControlSpell(CustomisedSpellType type) { super(type); } PlacementControlSpell(CustomisedSpellType type, Spell delegate) { - super(type); - this.delegate.set(delegate); + this(type); + this.delegate = delegate; } @Nullable public Spell getDelegate() { - return delegate.get(); + return delegate; } public Optional getPosition() { @@ -62,20 +59,24 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel @Override public void setOrientation(Caster caster, float pitch, float yaw) { this.orientation = Optional.of(new Vec3d(pitch, yaw, 0)); + if (delegate instanceof OrientedSpell o) { + o.setOrientation(caster, pitch, yaw); + } setDirty(); - if (!caster.isClient() && placedEntityId != null) { - getWorld(caster).ifPresent(world -> { - var entry = Ether.get(world).get(SpellType.PLACED_SPELL, placedEntityId, placedSpellId); - if (entry != null) { - entry.setPitch(pitch); - entry.setYaw(yaw); - } - }); + if (!caster.isClient()) { + var entry = getConnection(caster); + if (entry != null) { + entry.setPitch(pitch); + entry.setYaw(yaw); + } } } @Override public boolean apply(Caster caster) { + if (delegate == null) { + return false; + } boolean result = super.apply(caster); if (result) { if (dimension.isEmpty()) { @@ -84,21 +85,18 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel if (position.isEmpty()) { setPosition(caster.asEntity().getPos()); } + if (delegate instanceof PlacementDelegate) { + ((PlacementDelegate)delegate).onPlaced(caster, this); + } - PlaceableSpell copy = new PlaceableSpell(caster, this, delegate.get()); + CastSpellEntity entity = new CastSpellEntity(caster.asWorld(), caster, this); - Vec3d pos = position.orElse(caster.asEntity().getPos()); + Vec3d pos = position.get(); Vec3d rot = orientation.orElse(Vec3d.ZERO); - CastSpellEntity entity = UEntities.CAST_SPELL.create(caster.asWorld()); - entity.setCaster(caster); entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x); - entity.setYaw((float)rot.y); - entity.setPitch((float)rot.x); - copy.apply(entity); entity.getWorld().spawnEntity(entity); - placedSpellId = copy.getUuid(); placedEntityId = entity.getUuid(); setDirty(); } @@ -107,14 +105,17 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel @Override public boolean tick(Caster source, Situation situation) { - if (!source.isClient() && !checkConnection(source)) { + if (!source.isClient() && getConnection(source) == null) { setDead(); } return !isDead(); } - private boolean checkConnection(Caster source) { - return getWorld(source).map(world -> Ether.get(world).get(SpellType.PLACED_SPELL, placedEntityId, placedSpellId)).isPresent(); + @Nullable + private Ether.Entry getConnection(Caster source) { + return delegate == null || placedEntityId == null ? null : getWorld(source) + .map(world -> Ether.get(world).get(getDelegate().getTypeAndTraits().type(), placedEntityId, delegate.getUuid())) + .orElse(null); } private Optional getWorld(Caster source) { @@ -124,13 +125,10 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - compound.put("spell", delegate.toNBT()); + compound.put("spell", Spell.writeNbt(delegate)); position.ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos))); orientation.ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o))); dimension.ifPresent(d -> compound.putString("dimension", d.getValue().toString())); - if (placedSpellId != null) { - compound.putUuid("placedSpellId", placedSpellId); - } if (placedEntityId != null) { compound.putUuid("placedEntityId", placedEntityId); } @@ -139,8 +137,7 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); - delegate.fromNBT(compound.getCompound("spell")); - placedSpellId = compound.containsUuid("placedSpellId") ? compound.getUuid("placedSpellId") : null; + delegate = Spell.readNbt(compound.getCompound("spell")); placedEntityId = compound.containsUuid("placedEntityId") ? compound.getUuid("placedEntityId") : null; position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.FLOAT_TYPE))) : Optional.empty(); orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.FLOAT_TYPE))) : Optional.empty(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index d087ed0c..92f44adf 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -156,9 +156,16 @@ public interface Spell extends NbtSerialisable, Affine { return compound == null || !compound.containsUuid("uuid") ? Util.NIL_UUID : compound.getUuid("uuid"); } - static NbtCompound writeNbt(Spell effect) { + static NbtCompound writeNbt(@Nullable Spell effect) { + if (effect == null) { + return new NbtCompound(); + } NbtCompound compound = effect.toNBT(); effect.getTypeAndTraits().toNbt(compound); return compound; } + + static Spell copy(T spell) { + return readNbt(writeNbt(spell)); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java index 944f1365..8a012993 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java @@ -1,12 +1,10 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.Optional; import java.util.UUID; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.USounds; -import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; @@ -23,7 +21,6 @@ import com.minelittlepony.unicopia.util.shape.*; import net.minecraft.block.Block; import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.network.packet.s2c.play.PositionFlag; import net.minecraft.particle.ParticleTypes; @@ -59,12 +56,8 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. super(type); } - public boolean isLinked() { - return teleportationTarget.isSet(); - } - - public Optional> getTarget() { - return teleportationTarget.getTarget(); + public EntityReference getDestinationReference() { + return teleportationTarget; } public float getPitch() { @@ -88,13 +81,16 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. } @SuppressWarnings("unchecked") - private Optional> getDestination(Caster source) { - return getTarget().map(target -> Ether.get(source.asWorld()).get((SpellType)getType(), target, targetPortalId)); + private Ether.Entry getDestination(Caster source) { + return targetPortalId == null ? null : getDestinationReference() + .getTarget() + .map(target -> Ether.get(source.asWorld()).get((SpellType)getType(), target.uuid(), targetPortalId)) + .filter(destination -> destination.isClaimedBy(getUuid())) + .orElse(null); } @Override public boolean apply(Caster caster) { - setOrientation(caster, caster.asEntity().getPitch(), caster.asEntity().getYaw()); return toPlaceable().apply(caster); } @@ -106,19 +102,43 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. source.addParticle(ParticleTypes.ELECTRIC_SPARK, pos, Vec3d.ZERO); }); } else { - teleportationTarget.getTarget().ifPresent(target -> { - if (Ether.get(source.asWorld()).get(getType(), target, targetPortalId) == null) { - Unicopia.LOGGER.debug("Lost sibling, breaking connection to " + target.uuid()); - teleportationTarget.set(null); - setDirty(); - source.asWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, source.getOrigin(), Block.getRawIdFromState(Blocks.GLASS.getDefaultState())); - } - }); + var ownEntry = Ether.get(source.asWorld()).get(this, source); + synchronized (ownEntry) { + var targetEntry = getDestination(source); - getDestination(source).ifPresentOrElse( - entry -> tickWithTargetLink(source, entry), - () -> findLink(source) - ); + if (targetEntry == null) { + if (teleportationTarget.isSet()) { + teleportationTarget.set(null); + targetPortalId = null; + setDirty(); + source.asWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, source.getOrigin(), Block.getRawIdFromState(Blocks.GLASS.getDefaultState())); + } else { + Ether.get(source.asWorld()).anyMatch(getType(), entry -> { + if (entry.isAlive() && !entry.hasClaimant() && !entry.entityMatches(source.asEntity().getUuid())) { + entry.claim(getUuid()); + ownEntry.claim(entry.getSpellId()); + synchronized (entry) { + if (entry.getSpell() instanceof PortalSpell portal) { + portal.teleportationTarget.copyFrom(ownEntry.entity); + portal.targetPortalId = getUuid(); + portal.targetPortalPitch = pitch; + portal.targetPortalYaw = yaw; + portal.setDirty(); + } + } + teleportationTarget.copyFrom(entry.entity); + targetPortalId = entry.getSpellId(); + targetPortalPitch = entry.getPitch(); + targetPortalYaw = entry.getYaw(); + setDirty(); + } + return false; + }); + } + } else { + tickActive(source, targetEntry); + } + } } var entry = Ether.get(source.asWorld()).getOrCreate(this, source); @@ -129,13 +149,7 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. return !isDead(); } - private void tickWithTargetLink(Caster source, Ether.Entry destination) { - - if (destination.hasChanged()) { - targetPortalPitch = destination.getPitch(); - targetPortalYaw = destination.getYaw(); - } - + private void tickActive(Caster source, Ether.Entry destination) { destination.entity.getTarget().ifPresent(target -> { source.findAllEntitiesInRange(1).forEach(entity -> { if (!entity.hasPortalCooldown()) { @@ -145,8 +159,9 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. return; } - Vec3d offset = entity.getPos().subtract(source.getOriginVector()); - float yawDifference = pitch < 15 ? getYawDifference() : 0; + Vec3d offset = entity.getPos().subtract(source.asEntity().getPos()) + .add(new Vec3d(0, 0, -0.7F).rotateY(-getTargetYaw() * MathHelper.RADIANS_PER_DEGREE)); + float yawDifference = getYawDifference(); Vec3d dest = target.pos().add(offset.rotateY(yawDifference * MathHelper.RADIANS_PER_DEGREE)).add(0, 0.1, 0); if (entity.getWorld().isTopSolid(BlockPos.ofFloored(dest).up(), entity)) { @@ -176,37 +191,22 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. }); } - private void findLink(Caster source) { - if (source.isClient()) { - return; - } - - Ether.get(source.asWorld()).anyMatch(getType(), entry -> { - if (!entry.entity.referenceEquals(source.asEntity()) && entry.claim()) { - teleportationTarget.copyFrom(entry.entity); - targetPortalId = entry.getSpellId(); - setDirty(); - } - return false; - }); - } - @Override public void setOrientation(Caster caster, float pitch, float yaw) { - this.pitch = pitch; - this.yaw = yaw; + this.pitch = 90 - pitch; + this.yaw = -yaw; particleArea = PARTICLE_AREA.rotate( - pitch * MathHelper.RADIANS_PER_DEGREE, - yaw * MathHelper.RADIANS_PER_DEGREE + this.pitch * MathHelper.RADIANS_PER_DEGREE, + this.yaw * MathHelper.RADIANS_PER_DEGREE ); setDirty(); } @Override public void onPlaced(Caster source, PlacementControlSpell parent) { - parent.setOrientation(source, source.asEntity().getPitch(), source.asEntity().getYaw()); - LivingEntity caster = source.getMaster(); + Entity caster = source.asEntity(); Vec3d targetPos = caster.getRotationVector().multiply(3).add(caster.getEyePos()); + parent.setOrientation(source, -90 - source.asEntity().getPitch(), -source.asEntity().getYaw()); parent.setPosition(new Vec3d(targetPos.x, caster.getPos().y, targetPos.z)); if (source instanceof Pony pony) { Channel.SERVER_REQUEST_PLAYER_LOOK.sendToPlayer(new MsgCasterLookRequest(parent.getUuid()), (ServerPlayerEntity)pony.asEntity()); @@ -217,7 +217,10 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. protected void onDestroyed(Caster caster) { super.onDestroyed(caster); if (!caster.isClient()) { - getDestination(caster).ifPresent(Ether.Entry::release); + var destination = getDestination(caster); + if (destination != null) { + destination.release(getUuid()); + } } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index c35911d5..617fcf07 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -11,7 +11,6 @@ import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell; import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell; -import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell; import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell; import com.minelittlepony.unicopia.ability.magic.spell.RageAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.Spell; @@ -45,7 +44,6 @@ public final class SpellType implements Affine, SpellPredicate< private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id)); public static final SpellType PLACE_CONTROL_SPELL = register("place_controller", SpellType.builder(PlacementControlSpell::new).affinity(Affinity.NEUTRAL).unobtainable().stackable().shape(GemstoneItem.Shape.DONUT)); - public static final SpellType PLACED_SPELL = register("placed", builder(PlaceableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().stackable().shape(GemstoneItem.Shape.DONUT)); public static final SpellType THROWN_SPELL = register("thrown", builder(ThrowableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().shape(GemstoneItem.Shape.DONUT)); public static final SpellType CHANGELING_DISGUISE = register("disguise", builder(DispersableDisguiseSpell::new).affinity(Affinity.BAD).color(0x19E48E).unobtainable().shape(GemstoneItem.Shape.ARROW)); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 9ff61ac3..bad720d8 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -2,9 +2,9 @@ package com.minelittlepony.unicopia.client.gui; import java.util.ArrayList; import java.util.List; - import org.joml.Vector4f; +import com.google.common.base.MoreObjects; import com.minelittlepony.common.client.gui.GameGui; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; @@ -136,8 +136,8 @@ public class DismissSpellScreen extends GameGui { } private Spell getActualSpell() { - return spell instanceof AbstractDelegatingSpell s && s.getDelegate() instanceof Spell p ? p - : spell instanceof PlacementControlSpell s && s.getDelegate() instanceof Spell p ? p + return spell instanceof AbstractDelegatingSpell s ? MoreObjects.firstNonNull(s.getDelegate(), s) + : spell instanceof PlacementControlSpell s ? MoreObjects.firstNonNull(s.getDelegate(), s) : spell; } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java index 2b38a87f..8b430d57 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/HornFeatureRenderer.java @@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.client.render; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.ability.AbilityDispatcher.Stat; -import com.minelittlepony.unicopia.ability.magic.SpellPredicate; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import net.minecraft.client.model.Dilation; import net.minecraft.client.model.Model; @@ -56,7 +56,7 @@ public class HornFeatureRenderer implements AccessoryFea .flatMap(Stat::getActiveAbility) .map(ability -> ability.getColor(pony)) .filter(i -> i != -1).or(() -> pony.getSpellSlot() - .get(SpellPredicate.IS_NOT_PLACED) + .get(SpellType.PLACE_CONTROL_SPELL.negate()) .map(spell -> spell.getTypeAndTraits().type().getColor())); }).ifPresent(color -> { model.setState(true); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java index ece6638b..086d3b48 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java @@ -1,16 +1,35 @@ package com.minelittlepony.unicopia.client.render.entity; +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.common.util.Color; +import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.client.render.model.PlaneModel; import com.minelittlepony.unicopia.client.render.spell.SpellEffectsRenderDispatcher; +import com.minelittlepony.unicopia.client.render.spell.SpellRenderer; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.screen.PlayerScreenHandler; import net.minecraft.util.Identifier; +import net.minecraft.util.math.RotationAxis; public class CastSpellEntityRenderer extends EntityRenderer { + private static final Identifier[] TEXTURES = new Identifier[] { + Unicopia.id("textures/particles/runes_0.png"), + Unicopia.id("textures/particles/runes_1.png"), + Unicopia.id("textures/particles/runes_2.png"), + Unicopia.id("textures/particles/runes_3.png"), + Unicopia.id("textures/particles/runes_4.png"), + Unicopia.id("textures/particles/runes_5.png") + }; + public CastSpellEntityRenderer(EntityRendererFactory.Context ctx) { super(ctx); } @@ -21,11 +40,62 @@ public class CastSpellEntityRenderer extends EntityRenderer { } @Override - public void render(CastSpellEntity entity, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) { - SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertexConsumers, light, entity, 0, 0, tickDelta, getAnimationProgress(entity, tickDelta), yaw, 0); + public void render(CastSpellEntity entity, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light) { + matrices.push(); + matrices.translate(0, 0.001, 0); + final float height = entity.getHeight(); + final float pitch = entity.getPitch(tickDelta); + matrices.translate(0, (-pitch / 90F) * height * 0.5F, 0); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-pitch)); + + float animationProgress = getAnimationProgress(entity, tickDelta); + renderAmbientEffects(matrices, vertices, entity, entity.getSpellSlot().get().orElse(null), light, animationProgress, tickDelta); + SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertices, light, entity, entity.getScale(tickDelta), 0, tickDelta, animationProgress, yaw, pitch); + + matrices.pop(); } protected float getAnimationProgress(CastSpellEntity entity, float tickDelta) { return entity.age + tickDelta; } + + protected void renderAmbientEffects(MatrixStack matrices, VertexConsumerProvider vertices, CastSpellEntity entity, @Nullable Spell spell, int light, float animationProgress, float tickDelta) { + matrices.push(); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); + + float scale = entity.getScale(tickDelta) * 3; + matrices.scale(scale, scale, scale); + + float angle = (animationProgress / 9F) % 360; + + int color = spell == null ? 0 : spell.getTypeAndTraits().type().getColor(); + + float red = Color.r(color); + float green = Color.g(color); + float blue = Color.b(color); + + @Nullable + SpellRenderer renderer = spell == null ? null : SpellEffectsRenderDispatcher.INSTANCE.getRenderer(spell); + + for (int i = 0; i < TEXTURES.length; i++) { + if (renderer != null && !renderer.shouldRenderEffectPass(i)) { + continue; + } + VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityTranslucent(TEXTURES[i])); + + for (int dim = 0; dim < 3; dim++) { + float ringSpeed = (i % 2 == 0 ? i : -1) * i; + + matrices.push(); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(angle * ringSpeed)); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(angle * ringSpeed * dim)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(angle * ringSpeed * dim)); + PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, red, green, blue, scale / ((float)(dim * 3) + 1)); + matrices.pop(); + } + } + + matrices.pop(); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java deleted file mode 100644 index 856064d8..00000000 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.minelittlepony.unicopia.client.render.spell; - -import com.minelittlepony.common.util.Color; -import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; -import com.minelittlepony.unicopia.client.render.model.PlaneModel; - -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.RotationAxis; - -public class PlacedSpellRenderer extends SpellRenderer { - private static final Identifier[] TEXTURES = new Identifier[] { - Unicopia.id("textures/particles/runes_0.png"), - Unicopia.id("textures/particles/runes_1.png"), - Unicopia.id("textures/particles/runes_2.png"), - Unicopia.id("textures/particles/runes_3.png"), - Unicopia.id("textures/particles/runes_4.png"), - Unicopia.id("textures/particles/runes_5.png") - }; - - @Override - public void render(MatrixStack matrices, VertexConsumerProvider vertices, PlaceableSpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { - matrices.push(); - - Spell delegate = spell.getDelegate(); - - if (delegate != null) { - renderAmbientEffects(matrices, vertices, spell, delegate, caster, light, animationProgress, tickDelta); - - matrices.push(); - float height = caster.asEntity().getHeight(); - matrices.translate(0, (-spell.pitch / 90F) * height * 0.5F, 0); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(spell.yaw)); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-spell.pitch)); - SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertices, delegate, caster, light, spell.getScale(tickDelta), limbDistance, tickDelta, animationProgress, headYaw, headPitch); - matrices.pop(); - } - - matrices.pop(); - } - - protected void renderAmbientEffects(MatrixStack matrices, VertexConsumerProvider vertices, PlaceableSpell spell, Spell delegate, Caster caster, int light, float animationProgress, float tickDelta) { - matrices.push(); - matrices.translate(0, 0.001, 0); - - float height = caster.asEntity().getHeight(); - matrices.translate(0, (-spell.pitch / 90F) * height * 0.5F, 0); - - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(spell.yaw)); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-spell.pitch)); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); - - float scale = spell.getScale(tickDelta) * 3; - matrices.scale(scale, scale, scale); - - float angle = (animationProgress / 9F) % 360; - - int color = delegate.getTypeAndTraits().type().getColor(); - - float red = Color.r(color); - float green = Color.g(color); - float blue = Color.b(color); - - SpellRenderer renderer = SpellEffectsRenderDispatcher.INSTANCE.getRenderer(delegate); - - for (int i = 0; i < TEXTURES.length; i++) { - if (!renderer.shouldRenderEffectPass(i)) { - continue; - } - VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityTranslucent(TEXTURES[i])); - - for (int dim = 0; dim < 3; dim++) { - float ringSpeed = (i % 2 == 0 ? i : -1) * i; - - matrices.push(); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(angle * ringSpeed)); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(angle * ringSpeed * dim)); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(angle * ringSpeed * dim)); - PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, red, green, blue, scale / ((float)(dim * 3) + 1)); - matrices.pop(); - } - } - - matrices.pop(); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java index e594b647..7a558eef 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java @@ -159,13 +159,13 @@ class PortalFrameBuffer implements AutoCloseable { Camera camera = client.gameRenderer.getCamera(); Entity cameraEntity = UEntities.CAST_SPELL.create(caster.asWorld()); - Vec3d offset = new Vec3d(0, -0.2F, -0.2F).rotateY(-spell.getTargetYaw() * MathHelper.RADIANS_PER_DEGREE); + Vec3d offset = new Vec3d(0, 0, -0.1F).rotateY(-spell.getTargetYaw() * MathHelper.RADIANS_PER_DEGREE); float yaw = spell.getTargetYaw() + camera.getYaw() - spell.getYaw() + 180; float pitch = spell.getTargetPitch() + (camera.getPitch() - spell.getPitch()) * 1.65F; cameraEntity.setPosition(target.pos().add(offset)); - cameraEntity.setPitch(pitch); + cameraEntity.setPitch(90 + pitch); cameraEntity.setYaw(yaw); drawWorld(cameraEntity, 400, 400); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java index a75c3f72..bb65f063 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java @@ -10,6 +10,7 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; import net.minecraft.util.math.RotationAxis; public class PortalSpellRenderer extends SpellRenderer { @@ -29,7 +30,9 @@ public class PortalSpellRenderer extends SpellRenderer { SphereModel.DISK.render(matrices, buff, light, 0, 2F * strength, 1, 1, 1, 1); matrices.pop(); - if (Unicopia.getConfig().simplifiedPortals.get() || !spell.isLinked()) { + EntityReference destination = spell.getDestinationReference(); + + if (Unicopia.getConfig().simplifiedPortals.get() || !destination.isSet()) { matrices.push(); matrices.translate(0, -0.02, 0); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(180)); @@ -52,7 +55,7 @@ public class PortalSpellRenderer extends SpellRenderer { matrices.push(); matrices.scale(strength, strength, strength); - spell.getTarget().ifPresent(target -> { + destination.getTarget().ifPresent(target -> { float grown = Math.min(caster.asEntity().age, 20) / 20F; matrices.push(); matrices.translate(0, -0.01, 0); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index 423a8888..d80d55b6 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -47,7 +47,6 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader } static { - register(SpellType.PLACED_SPELL, PlacedSpellRenderer::new); register(SpellType.SHIELD, ShieldSpellRenderer::new); register(SpellType.DARK_VORTEX, DarkVortexSpellRenderer::new); register(SpellType.BUBBLE, BubbleSpellRenderer::new); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 2ae93d61..18280081 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -1,10 +1,14 @@ package com.minelittlepony.unicopia.entity.mob; +import java.util.UUID; + import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Levelled; import com.minelittlepony.unicopia.ability.magic.SpellInventory; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.SpellSlots; +import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; @@ -13,6 +17,7 @@ import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.network.track.Trackable; +import com.minelittlepony.unicopia.server.world.Ether; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityDimensions; @@ -24,6 +29,7 @@ import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.nbt.NbtCompound; import net.minecraft.text.Text; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; public class CastSpellEntity extends LightEmittingEntity implements Caster, WeaklyOwned.Mutable, MagicImmune { @@ -32,6 +38,8 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster CORRUPTION = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData MAX_CORRUPTION = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData DEAD = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.BOOLEAN); + private final EntityPhysics physics = new EntityPhysics<>(this); private final SpellInventory spells = SpellSlots.ofSingle(this); @@ -49,6 +57,23 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster dataTracker.get(MAX_CORRUPTION) ); + private UUID controllingEntityUuid; + private UUID controllingSpellUuid; + + private int prevAge; + + private int prevDeathTicks; + private int deathTicks; + + public CastSpellEntity(World world, Caster caster, PlacementControlSpell control) { + this(UEntities.CAST_SPELL, world); + this.controllingEntityUuid = caster.asEntity().getUuid(); + this.controllingSpellUuid = control.getUuid(); + setCaster(caster); + Spell spell = Spell.copy(control.getDelegate()); + spells.getSlots().put(spell); + } + public CastSpellEntity(EntityType type, World world) { super(type, world); ignoreCameraFrustum = true; @@ -61,6 +86,27 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster spell.setOrientation(this, pitch, yaw)); + } + + private boolean checkConnection() { + return Ether.get(getWorld()).get(SpellType.PLACE_CONTROL_SPELL, controllingEntityUuid, controllingSpellUuid) != null; + } + + public float getAge(float tickDelta) { + return MathHelper.lerp(tickDelta, prevAge, age); + } + + public float getScale(float tickDelta) { + float add = MathHelper.clamp(getAge(tickDelta) / 25F, 0, 1); + float subtract = MathHelper.clamp(MathHelper.lerp(tickDelta, prevDeathTicks, deathTicks) / 20F, 0, 1); + return MathHelper.clamp(add - subtract, 0, 1); } @Override @@ -78,19 +124,51 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster { + var entry = Ether.get(getWorld()).getOrCreate(spell, this); + if (entry.hasChanged()) { + //updatePositionAndAngles(getX(), getY(), getZ(), entry.getYaw(), entry.getPitch()); + } + }); + } + + prevDeathTicks = deathTicks; + + if (!spells.tick(Situation.GROUND) && deathTicks++ > 40) { + remove(Entity.RemovalReason.KILLED); + } + } + + @Override + public void kill() { + spells.getSlots().clear(); + } + + public boolean isDead() { + return dataTracker.get(DEAD); + } + + public void setDead(boolean dead) { + dataTracker.set(DEAD, dead); + if (dead) { + spells.getSlots().clear(); } } @Override public EntityDimensions getDimensions(EntityPose pose) { - return super.getDimensions(pose).scaled(getSpellSlot().get(SpellType.IS_PLACED).map(spell -> spell.getScale(1)).orElse(1F)); + return super.getDimensions(pose).scaled(getScale(1)); } @Override @@ -154,23 +232,42 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster CAST_SPELL = register("cast_spell", FabricEntityTypeBuilder.create(SpawnGroup.MISC, CastSpellEntity::new) + EntityType CAST_SPELL = register("cast_spell", FabricEntityTypeBuilder.create(SpawnGroup.MISC, CastSpellEntity::new) .trackRangeBlocks(200) .disableSummon() .dimensions(EntityDimensions.changing(4, 4))); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index d9e270ba..b5f18c77 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -892,7 +892,7 @@ public class Pony extends Living implements Copyable, Update oldSuppressedRace = Race.UNSET; Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(entity), "gui.unicopia.tribe_selection.respawn"), (ServerPlayerEntity)entity); } else { - oldPlayer.getSpellSlot().stream().filter(SpellPredicate.IS_PLACED).forEach(getSpellSlot()::put); + oldPlayer.getSpellSlot().stream().filter(SpellType.PLACE_CONTROL_SPELL).forEach(getSpellSlot()::put); } // putting it here instead of adding another injection point into ServerPlayerEntity.copyFrom() diff --git a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java index 04868e0b..fdf89f0c 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java @@ -9,7 +9,6 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; @@ -47,7 +46,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch public static SpellType getSpellType(Entity entity, boolean remove) { if (entity instanceof CastSpellEntity cast) { - return cast.getSpellSlot().get(c -> !SpellPredicate.IS_PLACED.test(c)) + return cast.getSpellSlot().get(SpellType.PLACE_CONTROL_SPELL.negate()) .map(Spell::getTypeAndTraits) .map(CustomisedSpellType::type) .orElse(SpellType.empty()); diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index 13707da6..21980091 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -168,13 +168,14 @@ public class Ether extends PersistentState { private WeakReference spell; private boolean removed; - private boolean taken; private float pitch; private final AtomicBoolean changed = new AtomicBoolean(true); private float yaw; private float radius; + private final Set claimants = new HashSet<>(); + private Entry(NbtElement nbt) { this.entity = new EntityReference<>(); this.spell = new WeakReference<>(null); @@ -227,7 +228,7 @@ public class Ether extends PersistentState { markDirty(); } - boolean isAlive() { + public boolean isAlive() { return !isDead(); } @@ -246,6 +247,7 @@ public class Ether extends PersistentState { public void markDead() { Unicopia.LOGGER.debug("Marking " + entity.getTarget().orElse(null) + " as dead"); removed = true; + claimants.clear(); markDirty(); } @@ -253,25 +255,22 @@ public class Ether extends PersistentState { return entity.getTarget().filter(target -> uuid.equals(target.uuid())).isPresent(); } - public boolean isAvailable() { - return !isDead() && !taken && entity.isSet(); - } - - public void setTaken(boolean taken) { - this.taken = taken; + public void claim(UUID claimant) { + claimants.add(claimant); markDirty(); } - public void release() { - setTaken(false); + public void release(UUID claimant) { + claimants.remove(claimant); + markDirty(); } - public boolean claim() { - if (isAvailable()) { - setTaken(true); - return true; - } - return false; + public boolean isClaimedBy(UUID claimant) { + return claimants.contains(claimant); + } + + public boolean hasClaimant() { + return !claimants.isEmpty(); } @Nullable @@ -315,24 +314,34 @@ public class Ether extends PersistentState { public void toNBT(NbtCompound compound) { entity.toNBT(compound); compound.putBoolean("removed", removed); - compound.putBoolean("taken", taken); compound.putFloat("pitch", pitch); compound.putFloat("yaw", yaw); compound.putFloat("radius", radius); if (spellId != null) { compound.putUuid("spellId", spellId); } + NbtList list = new NbtList(); + claimants.forEach(claimant -> { + list.add(NbtHelper.fromUuid(claimant)); + }); + compound.put("claimants", list); } @Override public void fromNBT(NbtCompound compound) { entity.fromNBT(compound); removed = compound.getBoolean("removed"); - taken = compound.getBoolean("taken"); pitch = compound.getFloat("pitch"); yaw = compound.getFloat("yaw"); radius = compound.getFloat("radius"); spellId = compound.containsUuid("spellid") ? compound.getUuid("spellId") : null; + + claimants.clear(); + if (compound.contains("claimants", NbtElement.LIST_TYPE)) { + compound.getList("claimants", NbtElement.INT_ARRAY_TYPE).forEach(el -> { + claimants.add(NbtHelper.toUuid(el)); + }); + } } @Override From 14084e270bbec4d76efc2fd222929d04a6dc6ac8 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 May 2024 17:36:57 +0100 Subject: [PATCH 46/85] Fix tooltip details --- .../minelittlepony/unicopia/entity/effect/EffectUtils.java | 4 ++-- src/main/resources/assets/unicopia/lang/en_us.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java index f60e6876..fd63fc84 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java @@ -51,9 +51,9 @@ public interface EffectUtils { } static Text formatModifierChange(String modifierName, float change, boolean isDetrimental) { - return Text.translatable("attribute.modifier." + (change > 0 ? "plus" : "take") + ".addition", + return Text.literal(" ").append(Text.translatable("attribute.modifier." + (change > 0 ? "plus" : "take") + ".0", ItemStack.MODIFIER_FORMAT.format(Math.abs(change)), Text.translatable(modifierName) - ).formatted((isDetrimental ? change : -change) < 0 ? Formatting.DARK_GREEN : Formatting.RED); + ).formatted((isDetrimental ? change : -change) < 0 ? Formatting.DARK_GREEN : Formatting.RED)); } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 91ec6e3c..60e60b2f 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -737,7 +737,7 @@ "affinity.unicopia.bad": "Bad", "affinity.unicopia.neutral": "Neutral", "affinity.unicopia.when_cast": "When Cast:", - "affinity.unicopia.corruption": " %s%.2f Corruption", + "affinity.unicopia.corruption": "Corruption", "gui.unicopia.trait.label": "Element of %s", "gui.unicopia.trait.group": "\n %s", From d909ee47f139f7bf4d5d731bde933855d4d191b0 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 May 2024 17:37:27 +0100 Subject: [PATCH 47/85] Fix dismiss animations on placed spells --- .../unicopia/entity/mob/CastSpellEntity.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 18280081..fbca955c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -136,11 +136,10 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster { - var entry = Ether.get(getWorld()).getOrCreate(spell, this); - if (entry.hasChanged()) { - //updatePositionAndAngles(getX(), getY(), getZ(), entry.getYaw(), entry.getPitch()); - } + Ether.get(getWorld()).getOrCreate(spell, this); }); + } else if (isDead()) { + spells.getSlots().clear(); } prevDeathTicks = deathTicks; @@ -152,7 +151,7 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster Date: Thu, 23 May 2024 17:38:11 +0100 Subject: [PATCH 48/85] Add tooltip for area protection spell and make use of the cached radius from the Ether entry --- .../unicopia/ability/magic/Caster.java | 15 ++++++++++- .../spell/effect/AreaProtectionSpell.java | 25 +++++++++++++------ .../magic/spell/effect/HydrophobicSpell.java | 18 +++++++------ 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java index 86c225f1..872aba90 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.Ability; +import com.minelittlepony.unicopia.ability.magic.spell.effect.AreaProtectionSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.damage.UDamageSources; @@ -111,7 +112,19 @@ public interface Caster extends } default boolean canCastAt(Vec3d pos) { - return !Ether.get(asWorld()).anyMatch(SpellType.ARCANE_PROTECTION, (spell, caster) -> spell.blocksMagicFor(caster, this, pos)); + return !Ether.get(asWorld()).anyMatch(SpellType.ARCANE_PROTECTION, entry -> { + var target = entry.entity.getTarget().orElse(null); + if (target != null && target.pos().distanceTo(pos) <= entry.getRadius()) { + Caster caster = entry.getCaster(); + if (caster != null) { + AreaProtectionSpell spell = entry.getSpell(); + if (spell != null) { + return spell.blocksMagicFor(caster, this, pos); + } + } + } + return false; + }); } default boolean canUse(Ability ability) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java index 5ae9df44..093ea63f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java @@ -1,10 +1,13 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; + import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.FriendshipBraceletItem; @@ -13,6 +16,8 @@ import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -22,6 +27,15 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { .with(Trait.STRENGTH, 30) .build(); + + static void appendTooltip(CustomisedSpellType type, List tooltip) { + float addedRange = type.traits().get(Trait.POWER); + if (addedRange != 0) { + tooltip.add(EffectUtils.formatModifierChange("spell.unicopia.shield.additional_range", addedRange, false)); + } + tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.caston.location")).formatted(Formatting.GRAY)); + } + protected AreaProtectionSpell(CustomisedSpellType type) { super(type); } @@ -33,7 +47,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { return false; } - float radius = (float)getDrawDropOffRange(source); + float radius = (float)getRange(source); if (source.isClient()) { Vec3d origin = source.getOriginVector(); @@ -44,7 +58,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { } }); } else { - Ether.get(source.asWorld()).getOrCreate(this, source); + Ether.get(source.asWorld()).getOrCreate(this, source).setRadius(radius); } source.findAllSpellsInRange(radius, e -> isValidTarget(source, e)).filter(caster -> !caster.hasCommonOwner(source)).forEach(caster -> { @@ -54,10 +68,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { return !isDead(); } - /** - * Calculates the maximum radius of the shield. aka The area of effect. - */ - public double getDrawDropOffRange(Caster source) { + private double getRange(Caster source) { float multiplier = source instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2; float min = 4 + getTraits().get(Trait.POWER); double range = (min + (source.getLevel().getScaled(4) * 2)) / multiplier; @@ -69,7 +80,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { public boolean blocksMagicFor(Caster source, Caster other, Vec3d position) { return !FriendshipBraceletItem.isComrade(other, other.asEntity()) - && source.getOriginVector().distanceTo(position) <= getDrawDropOffRange(source); + && source.getOriginVector().distanceTo(position) <= getRange(source); } protected boolean isValidTarget(Caster source, Entity entity) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java index 434d6ad7..cec7e61a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java @@ -178,15 +178,17 @@ public class HydrophobicSpell extends AbstractSpell { } public static boolean blocksFluidFlow(BlockView world, BlockPos pos, FluidState state) { - if (world instanceof ServerWorld sw) { - return Ether.get(sw).anyMatch(SpellType.HYDROPHOBIC, entry -> { - var spell = entry.getSpell(); - var target = entry.entity.getTarget().orElse(null); - return spell != null && target != null && spell.blocksFlow(entry, target.pos(), pos, state); - }); + if (!(world instanceof ServerWorld sw)) { + return false; } - return false; - + return Ether.get(sw).anyMatch(SpellType.HYDROPHOBIC, entry -> { + var target = entry.entity.getTarget().orElse(null); + if (target == null || !pos.isWithinDistance(target.pos(), entry.getRadius() + 1)) { + return false; + } + var spell = entry.getSpell(); + return spell != null && target != null && spell.blocksFlow(entry, target.pos(), pos, state); + }); } } From 98f612cd138b3a8b074db949c72cf359a22b9be1 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 May 2024 18:52:55 +0100 Subject: [PATCH 49/85] Fixed disguise orientation and door disguises. Fixes #259 --- .../client/render/EntityDisguiseRenderer.java | 12 ----------- .../entity/behaviour/EntityBehaviour.java | 7 ------- .../behaviour/FallingBlockBehaviour.java | 21 +++++++++---------- 3 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java index 40a83c9d..74137b58 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java @@ -9,7 +9,6 @@ import com.minelittlepony.unicopia.entity.behaviour.Disguise; import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance; import com.minelittlepony.unicopia.mixin.MixinBlockEntity; -import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.OverlayTexture; @@ -19,10 +18,7 @@ import net.minecraft.client.render.entity.LivingEntityRenderer; import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; -import net.minecraft.state.property.Properties; -import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.Vec3d; class EntityDisguiseRenderer { @@ -90,15 +86,7 @@ class EntityDisguiseRenderer { ((MixinBlockEntity)blockEntity).setPos(e.getBlockPos()); blockEntity.setWorld(e.getWorld()); matrices.push(); - - BlockState state = blockEntity.getCachedState(); - Direction direction = state.contains(Properties.HORIZONTAL_FACING) ? state.get(Properties.HORIZONTAL_FACING) : Direction.UP; - matrices.translate(x, y, z); - - matrices.multiply(direction.getRotationQuaternion()); - matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(90)); - matrices.translate(-0.5, 0, -0.5); r.render(blockEntity, 1, matrices, vertexConsumers, light, OverlayTexture.DEFAULT_UV); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java index a04113e6..09511f47 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java @@ -34,7 +34,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.LlamaSpitEntity; import net.minecraft.entity.projectile.thrown.SnowballEntity; import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.registry.Registry; @@ -138,12 +137,6 @@ public class EntityBehaviour { double y = positionOffset.y + Math.floor(from.getY()); double z = positionOffset.z + Math.floor(from.getZ()) + 0.5; - BlockPos pos = BlockPos.ofFloored(x, y, z); - - if (!from.getWorld().isAir(pos) && !from.getWorld().isWater(pos)) { - y++; - } - to.prevX = x; to.prevY = y; to.prevZ = z; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java index d932e0cc..c3f7e05a 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java @@ -25,7 +25,6 @@ import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.state.property.Properties; -import net.minecraft.registry.tag.BlockTags; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; @@ -74,7 +73,11 @@ public class FallingBlockBehaviour extends EntityBehaviour { BlockState state = entity.getBlockState(); Block block = state.getBlock(); - if (state.isIn(BlockTags.DOORS) && block instanceof DoorBlock) { + if (block instanceof BlockEntityProvider bep) { + context.addBlockEntity(bep.createBlockEntity(entity.getBlockPos(), state)); + } + + if (block instanceof DoorBlock) { BlockState lowerState = state.with(DoorBlock.HALF, DoubleBlockHalf.LOWER); BlockState upperState = state.with(DoorBlock.HALF, DoubleBlockHalf.UPPER); @@ -83,10 +86,6 @@ public class FallingBlockBehaviour extends EntityBehaviour { return configure(MixinFallingBlockEntity.createInstance(entity.getWorld(), entity.getX(), entity.getY() + 1, entity.getZ(), lowerState), block); } - if (block instanceof BlockEntityProvider bep) { - context.addBlockEntity(bep.createBlockEntity(entity.getBlockPos(), state)); - } - return configure(entity, block); } @@ -100,15 +99,10 @@ public class FallingBlockBehaviour extends EntityBehaviour { if (state.get(Properties.WATERLOGGED) != logged) { entity = MixinFallingBlockEntity.createInstance(entity.getWorld(), entity.getX(), entity.getY(), entity.getZ(), state.with(Properties.WATERLOGGED, logged)); spell.getDisguise().setAppearance(entity); - return; } } EntityAppearance disguise = spell.getDisguise(); - List attachments = disguise.getAttachments(); - if (attachments.size() > 0) { - copyBaseAttributes(source.asEntity(), attachments.get(0), UP); - } BlockEntity be = disguise.getBlockEntity(); @@ -122,5 +116,10 @@ public class FallingBlockBehaviour extends EntityBehaviour { ceb.tick(); be.setWorld(null); } + + List attachments = disguise.getAttachments(); + if (attachments.size() > 0) { + copyBaseAttributes(source.asEntity(), attachments.get(0), UP); + } } } From e22f181f4136b724a83919a456b16ccd2616a79b Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 May 2024 19:59:56 +0100 Subject: [PATCH 50/85] Fixed rendering of multi-segment blocks --- .../client/render/EntityDisguiseRenderer.java | 34 ++++++++++++---- .../entity/behaviour/EntityAppearance.java | 26 +++++++----- .../behaviour/FallingBlockBehaviour.java | 40 ++++++++++--------- 3 files changed, 63 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java index 74137b58..142edfc9 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java @@ -9,15 +9,18 @@ import com.minelittlepony.unicopia.entity.behaviour.Disguise; import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance; import com.minelittlepony.unicopia.mixin.MixinBlockEntity; +import net.minecraft.block.BlockRenderType; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.block.entity.BlockEntityRenderer; +import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.client.render.entity.LivingEntityRenderer; import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; +import net.minecraft.entity.FallingBlockEntity; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -49,11 +52,11 @@ class EntityDisguiseRenderer { } render(ve, e, x, y, z, fireTicks, tickDelta, matrices, vertices, light); - ve.getAttachments().forEach(ee -> { - PehkUtil.copyScale(pony.asEntity(), ee); - Vec3d difference = ee.getPos().subtract(e.getPos()); - render(ve, ee, x + difference.x, y + difference.y, z + difference.z, fireTicks, tickDelta, matrices, vertices, light); - PehkUtil.clearScale(ee); + ve.getAttachments().forEach(attachment -> { + PehkUtil.copyScale(pony.asEntity(), attachment.entity()); + Vec3d difference = attachment.entity().getPos().subtract(e.getPos()); + render(ve, attachment.entity(), x + difference.x, y + difference.y, z + difference.z, fireTicks, tickDelta, matrices, vertices, light); + PehkUtil.clearScale(attachment.entity()); }); matrices.push(); @@ -66,6 +69,7 @@ class EntityDisguiseRenderer { return true; } + @SuppressWarnings("deprecation") private void render(EntityAppearance ve, Entity e, double x, double y, double z, int fireTicks, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) { @@ -84,6 +88,9 @@ class EntityDisguiseRenderer { BlockEntityRenderer r = MinecraftClient.getInstance().getBlockEntityRenderDispatcher().get(blockEntity); if (r != null) { ((MixinBlockEntity)blockEntity).setPos(e.getBlockPos()); + if (e instanceof FallingBlockEntity fbe) { + blockEntity.setCachedState(fbe.getBlockState()); + } blockEntity.setWorld(e.getWorld()); matrices.push(); matrices.translate(x, y, z); @@ -92,8 +99,11 @@ class EntityDisguiseRenderer { r.render(blockEntity, 1, matrices, vertexConsumers, light, OverlayTexture.DEFAULT_UV); matrices.pop(); - blockEntity.setWorld(null); - return; + + BlockRenderType type = blockEntity.getCachedState().getRenderType(); + if (type == BlockRenderType.ENTITYBLOCK_ANIMATED) { + return; + } } } @@ -104,7 +114,15 @@ class EntityDisguiseRenderer { } e.setFireTicks(fireTicks); - delegate.client.getEntityRenderDispatcher().render(e, x, y, z, e.getYaw(), tickDelta, matrices, vertexConsumers, light); + + EntityRenderDispatcher dispatcher = delegate.client.getEntityRenderDispatcher(); + if (e instanceof FallingBlockEntity) { + dispatcher.setRenderShadows(false); + } + dispatcher.render(e, x, y, z, e.getYaw(), tickDelta, matrices, vertexConsumers, light); + if (e instanceof FallingBlockEntity) { + dispatcher.setRenderShadows(true); + } e.setFireTicks(0); if (model != null) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java index fd70ab27..acba1d32 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java @@ -48,21 +48,22 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.ShulkerBulletEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.shape.VoxelShape; public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider, EntityCollisions.ComplexCollidable { private static final Optional BLOCK_HEIGHT = Optional.of(0.5F); @NotNull - private String entityId = ""; + private transient String entityId = ""; @Nullable - private Entity entity; + private transient Entity entity; @Nullable - private BlockEntity blockEntity; + private transient BlockEntity blockEntity; - private List attachments = new ArrayList<>(); + private transient List attachments = new ArrayList<>(); private Optional dimensions = Optional.empty(); @@ -71,7 +72,7 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi * This is not serialized, so should only be used for server-side data. */ @Nullable - private NbtCompound tag; + private transient NbtCompound tag; @Nullable private NbtCompound entityNbt; @@ -86,16 +87,21 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi return blockEntity; } - public List getAttachments() { + public List getAttachments() { return attachments; } - public void addBlockEntity(BlockEntity blockEntity) { + public record Attachment(Vec3d offset, Entity entity) {} + + public void setBlockEntity(@Nullable BlockEntity blockEntity) { + if (this.blockEntity != null) { + this.blockEntity.markRemoved(); + } this.blockEntity = blockEntity; } - public void attachExtraEntity(Entity entity) { - attachments.add(entity); + public void attachExtraEntity(Vec3d offset, Entity entity) { + attachments.add(new Attachment(offset, entity)); } public void setAppearance(@Nullable Entity entity) { @@ -384,7 +390,7 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi @Override public void getCollissionShapes(ShapeContext context, Consumer output) { EntityCollisions.getCollissionShapes(getAppearance(), context, output); - getAttachments().forEach(e -> EntityCollisions.getCollissionShapes(e, context, output)); + getAttachments().forEach(e -> EntityCollisions.getCollissionShapes(e.entity(), context, output)); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java index c3f7e05a..1ed88f8f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java @@ -1,6 +1,5 @@ package com.minelittlepony.unicopia.entity.behaviour; -import java.util.List; import java.util.Optional; import com.minelittlepony.unicopia.ability.magic.Caster; @@ -11,27 +10,26 @@ import com.minelittlepony.unicopia.mixin.MixinFallingBlock; import com.minelittlepony.unicopia.mixin.MixinFallingBlockEntity; import com.minelittlepony.unicopia.util.Tickable; +import net.minecraft.block.BedBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; -import net.minecraft.block.DoorBlock; import net.minecraft.block.FallingBlock; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.ChestBlockEntity; import net.minecraft.block.entity.EnderChestBlockEntity; +import net.minecraft.block.enums.BedPart; +import net.minecraft.block.enums.ChestType; import net.minecraft.block.enums.DoubleBlockHalf; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.state.property.Properties; -import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; public class FallingBlockBehaviour extends EntityBehaviour { - - private static final Vec3d UP = Vec3d.of(Direction.UP.getVector()); - private static final Optional FULL_BLOCK = Optional.of(EntityDimensions.changing(0.6F, 0.9F)); @Override @@ -70,22 +68,27 @@ public class FallingBlockBehaviour extends EntityBehaviour { public FallingBlockEntity onCreate(FallingBlockEntity entity, EntityAppearance context, boolean replaceOld) { super.onCreate(entity, context, replaceOld); - BlockState state = entity.getBlockState(); + BlockState state = entity.getBlockState() + .withIfExists(Properties.CHEST_TYPE, ChestType.SINGLE) + .withIfExists(Properties.BED_PART, BedPart.HEAD) + .withIfExists(Properties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER); Block block = state.getBlock(); + context.setBlockEntity(block instanceof BlockEntityProvider bep ? bep.createBlockEntity(entity.getBlockPos(), state) : null); - if (block instanceof BlockEntityProvider bep) { - context.addBlockEntity(bep.createBlockEntity(entity.getBlockPos(), state)); + if (state.contains(Properties.BED_PART)) { + Vec3i offset = BedBlock.getOppositePartDirection(state).getVector(); + BlockState foot = state.with(Properties.BED_PART, BedPart.FOOT); + context.attachExtraEntity(Vec3d.of(offset), configure(MixinFallingBlockEntity.createInstance(entity.getWorld(), entity.getX() + offset.getX(), entity.getY() + offset.getY(), entity.getZ() + offset.getZ(), foot), block)); } - if (block instanceof DoorBlock) { - BlockState lowerState = state.with(DoorBlock.HALF, DoubleBlockHalf.LOWER); - BlockState upperState = state.with(DoorBlock.HALF, DoubleBlockHalf.UPPER); - - context.attachExtraEntity(configure(MixinFallingBlockEntity.createInstance(entity.getWorld(), entity.getX(), entity.getY(), entity.getZ(), upperState), block)); - - return configure(MixinFallingBlockEntity.createInstance(entity.getWorld(), entity.getX(), entity.getY() + 1, entity.getZ(), lowerState), block); + if (state.contains(Properties.DOUBLE_BLOCK_HALF)) { + BlockState upperState = state.with(Properties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.UPPER); + context.attachExtraEntity(new Vec3d(0, 1, 0), configure(MixinFallingBlockEntity.createInstance(entity.getWorld(), entity.getX(), entity.getY() + 1, entity.getZ(), upperState), block)); } + if (state != entity.getBlockState()) { + entity = MixinFallingBlockEntity.createInstance(entity.getWorld(), entity.getX(), entity.getY(), entity.getZ(), state); + } return configure(entity, block); } @@ -117,9 +120,8 @@ public class FallingBlockBehaviour extends EntityBehaviour { be.setWorld(null); } - List attachments = disguise.getAttachments(); - if (attachments.size() > 0) { - copyBaseAttributes(source.asEntity(), attachments.get(0), UP); + for (var attachment : disguise.getAttachments()) { + copyBaseAttributes(source.asEntity(), attachment.entity(), attachment.offset()); } } } From 61756050690920db4431c502eb72be62fb67df00 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 May 2024 20:00:17 +0100 Subject: [PATCH 51/85] Don't tick disguises if the game is paused --- .../unicopia/client/render/EntityDisguiseRenderer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java index 142edfc9..94941723 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/EntityDisguiseRenderer.java @@ -36,7 +36,9 @@ class EntityDisguiseRenderer { double x, double y, double z, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light) { int fireTicks = pony.asEntity().doesRenderOnFire() ? 1 : 0; - disguise.update(pony, false); + if (!delegate.client.isPaused()) { + disguise.update(pony, false); + } EntityAppearance ve = disguise.getDisguise(); Entity e = ve.getAppearance(); From d1b3e8702acc475c28fbfeceda7793e24ed3bda6 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 May 2024 20:23:44 +0100 Subject: [PATCH 52/85] Fix build --- .../magic/spell/AbstractDelegatingSpell.java | 37 ++++----- .../ability/magic/spell/EmptySpell.java | 77 +++++++++++++++++++ .../unicopia/entity/behaviour/Disguise.java | 11 +-- 3 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index b65acecf..ffd032c7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.ability.magic.spell; import java.util.*; import java.util.stream.Stream; +import com.google.common.base.MoreObjects; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; @@ -28,6 +29,10 @@ public abstract class AbstractDelegatingSpell implements Spell { return delegate.get(); } + private Spell getOrEmpty() { + return MoreObjects.firstNonNull(delegate.get(), EmptySpell.INSTANCE); + } + @Override public boolean equalsOrContains(UUID id) { return Spell.super.equalsOrContains(id) || delegate.equalsOrContains(id); @@ -50,26 +55,22 @@ public abstract class AbstractDelegatingSpell implements Spell { @Override public void setDead() { - if (delegate.get() != null) { - delegate.get().setDead(); - } + getOrEmpty().setDead(); } @Override public void tickDying(Caster caster) { - if (delegate.get() != null) { - delegate.get().tickDying(caster); - } + getOrEmpty().tickDying(caster); } @Override public boolean isDead() { - return delegate.get() == null; + return getOrEmpty().isDead(); } @Override public boolean isDying() { - return delegate.get() != null && delegate.get().isDying(); + return getOrEmpty().isDying(); } @Override @@ -84,12 +85,12 @@ public abstract class AbstractDelegatingSpell implements Spell { @Override public boolean isHidden() { - return hidden || (delegate.get() != null && delegate.get().isHidden()); + return hidden || getOrEmpty().isHidden(); } @Override public void setHidden(boolean hidden) { - this.hidden = hidden; + getOrEmpty().setHidden(hidden); } @Override @@ -106,21 +107,17 @@ public abstract class AbstractDelegatingSpell implements Spell { if (!caster.isClient()) { Ether.get(caster.asWorld()).remove(this, caster); } - if (delegate.get() instanceof Spell s) { - s.destroy(caster); - } + getOrEmpty().destroy(caster); } @Override public boolean tick(Caster source, Situation situation) { - if (delegate.get() instanceof Spell s) { - if (s.isDying()) { - s.tickDying(source); - return !s.isDead(); - } - return s.tick(source, situation) && !isDead(); + Spell s = getOrEmpty(); + if (s.isDying()) { + s.tickDying(source); + return !s.isDead(); } - return !isDead(); + return s.tick(source, situation); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java new file mode 100644 index 00000000..202c3830 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java @@ -0,0 +1,77 @@ +package com.minelittlepony.unicopia.ability.magic.spell; + +import java.util.UUID; + +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.Util; + +public final class EmptySpell implements Spell { + public static final EmptySpell INSTANCE = new EmptySpell(); + + private EmptySpell() {} + + @Override + public void toNBT(NbtCompound compound) { } + + @Override + public void fromNBT(NbtCompound compound) { } + + @Override + public CustomisedSpellType getTypeAndTraits() { + return SpellType.EMPTY_KEY.withTraits(); + } + + @Override + public UUID getUuid() { + return Util.NIL_UUID; + } + + @Override + public void setDead() { } + + @Override + public boolean isDead() { + return true; + } + + @Override + public boolean isDying() { + return false; + } + + @Override + public boolean isDirty() { + return false; + } + + @Override + public boolean tick(Caster caster, Situation situation) { + return false; + } + + @Override + public void tickDying(Caster caster) { } + + @Override + public void setDirty() { } + + @Override + public boolean isHidden() { + return true; + } + + @Override + public void setHidden(boolean hidden) { } + + @Override + public void destroy(Caster caster) { } + + @Override + public String toString() { + return "EmptySpell{}"; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java index 7041b6e7..b34606f7 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java @@ -64,11 +64,10 @@ public interface Disguise extends FlightType.Provider, PlayerDimensions.Provider @SuppressWarnings("unchecked") default boolean update(Caster caster, boolean tick) { - if (!(caster instanceof Living)) { + if (!(caster instanceof Living source)) { return false; } - Living source = (Living)caster; LivingEntity owner = source.asEntity(); if (owner == null) { @@ -89,8 +88,8 @@ public interface Disguise extends FlightType.Provider, PlayerDimensions.Provider entity.noClip = true; - if (entity instanceof MobEntity) { - ((MobEntity)entity).setAiDisabled(true); + if (entity instanceof MobEntity mob) { + mob.setAiDisabled(true); } entity.setInvisible(false); @@ -117,9 +116,7 @@ public interface Disguise extends FlightType.Provider, PlayerDimensions.Provider behaviour.update(source, entity, this); - if (source instanceof Pony) { - Pony player = (Pony)source; - + if (source instanceof Pony player) { source.asEntity().setInvisible(true); player.setInvisible(true); From 79d97adf0b32ed3ade374a48723c8f2b6071bfd3 Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 24 May 2024 16:43:11 +0100 Subject: [PATCH 53/85] Implement attribute tooltips for all spells --- .../magic/spell/AbstractAreaEffectSpell.java | 16 +++++ .../magic/spell/DispersableDisguiseSpell.java | 2 +- .../ability/magic/spell/SpellAttributes.java | 64 +++++++++++++++++++ .../ability/magic/spell/TimedSpell.java | 16 +++++ .../spell/effect/AreaProtectionSpell.java | 19 +++--- .../magic/spell/effect/AttractiveSpell.java | 24 ++++--- .../magic/spell/effect/BubbleSpell.java | 9 ++- .../magic/spell/effect/CatapultSpell.java | 8 +++ .../spell/effect/CustomisedSpellType.java | 8 ++- .../magic/spell/effect/DispellEvilSpell.java | 9 ++- .../spell/effect/DisperseIllusionSpell.java | 13 +++- .../magic/spell/effect/DisplacementSpell.java | 10 +++ .../magic/spell/effect/FeatherFallSpell.java | 37 +++++++---- .../magic/spell/effect/FireBoltSpell.java | 17 +++++ .../ability/magic/spell/effect/FireSpell.java | 14 +++- .../magic/spell/effect/HydrophobicSpell.java | 7 ++ .../magic/spell/effect/LightSpell.java | 9 ++- .../magic/spell/effect/MimicSpell.java | 11 +++- .../magic/spell/effect/NecromancySpell.java | 9 ++- .../magic/spell/effect/ScorchSpell.java | 2 +- .../magic/spell/effect/ShieldSpell.java | 49 ++++++++------ .../magic/spell/effect/SiphoningSpell.java | 8 ++- .../ability/magic/spell/effect/SpellType.java | 41 ++++++------ .../magic/spell/trait/SpellTraits.java | 4 ++ .../unicopia/entity/effect/EffectUtils.java | 8 +++ .../resources/assets/unicopia/lang/en_us.json | 33 ++++++++-- 26 files changed, 357 insertions(+), 90 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java index c0f63418..128323a0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java @@ -1,9 +1,21 @@ package com.minelittlepony.unicopia.ability.magic.spell; +import java.util.List; + import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.*; +import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; +import net.minecraft.text.Text; public abstract class AbstractAreaEffectSpell extends AbstractSpell { + + public static void appendRangeTooltip(CustomisedSpellType type, List tooltip) { + float addedRange = type.traits().get(Trait.POWER); + if (addedRange != 0) { + tooltip.add(SpellAttributes.ofRelative(SpellAttributes.RANGE, addedRange)); + } + } + protected AbstractAreaEffectSpell(CustomisedSpellType type) { super(type); } @@ -12,4 +24,8 @@ public abstract class AbstractAreaEffectSpell extends AbstractSpell { public Spell prepareForCast(Caster caster, CastingMethod method) { return toPlaceable(); } + + protected final float getAdditionalRange() { + return (int)getTraits().get(Trait.POWER); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java index f52b0e4a..d659cc90 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java @@ -36,7 +36,7 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I @Override public void onSuppressed(Caster otherSource, float time) { time /= getTraits().getOrDefault(Trait.STRENGTH, 1); - suppressionCounter = (int)(100 * time); + suppressionCounter = (int)time; setDirty(); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java new file mode 100644 index 00000000..f4b2ffdc --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java @@ -0,0 +1,64 @@ +package com.minelittlepony.unicopia.ability.magic.spell; + +import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; + +import net.minecraft.item.ItemStack; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; +import net.minecraft.util.StringHelper; +import net.minecraft.util.Util; + +public interface SpellAttributes { + Text CAST_ON_LOCATION = of(Unicopia.id("cast_on_location")); + Text CAST_ON_PERSON = of(Unicopia.id("cast_on_person")); + Text TARGET_ENTITY = of(Unicopia.id("focused_entity")); + Text FOLLOWS_TARGET = of(Unicopia.id("follows_target")); + + Text PERMIT_ITEMS = of(Unicopia.id("permit_items")); + Text PERMIT_PASSIVE = of(Unicopia.id("permit_passive")); + Text PERMIT_HOSTILE = of(Unicopia.id("permit_hostile")); + Text PERMIT_PLAYER = of(Unicopia.id("permit_player")); + + Identifier RANGE = Unicopia.id("range"); + Identifier DURATION = Unicopia.id("duration"); + Identifier STRENGTH = Unicopia.id("strength"); + Identifier VELOCITY = Unicopia.id("velocity"); + Identifier VERTICAL_VELOCITY = Unicopia.id("vertical_velocity"); + Identifier DAMAGE_TO_TARGET = Unicopia.id("damage_to_target"); + Identifier SIMULTANIOUS_TARGETS = Unicopia.id("simultanious_targets"); + Identifier COST_PER_INDIVIDUAL = Unicopia.id("cost_per_individual"); + Identifier EXPLOSION_STRENGTH = Unicopia.id("explosion_strength"); + Identifier PROJECTILE_COUNT = Unicopia.id("projectile_count"); + Identifier ORB_COUNT = Unicopia.id("orb_count"); + Identifier WAVE_SIZE = Unicopia.id("wave_size"); + Identifier FOLLOW_RANGE = Unicopia.id("follow_range"); + Identifier SOAPINESS = Unicopia.id("soapiness"); + + Identifier TARGET_PREFERENCE = Unicopia.id("target_preference"); + Identifier CASTER_PREFERENCE = Unicopia.id("caster_preference"); + + static Text of(Identifier id) { + return Text.literal(" ").append(Text.translatable(Util.createTranslationKey("spell_attribute", id))).formatted(Formatting.LIGHT_PURPLE); + } + + static Text of(Identifier id, float value) { + return Text.literal(" ").append( + Text.translatable("attribute.modifier.equals.0", + ItemStack.MODIFIER_FORMAT.format(value), + Text.translatable(Util.createTranslationKey("spell_attribute", id))) + ).formatted(Formatting.LIGHT_PURPLE); + } + + static Text ofRelative(Identifier id, float value) { + return EffectUtils.formatModifierChange(Util.createTranslationKey("spell_attribute", id), value, false); + } + + static Text ofTime(Identifier id, long time) { + return Text.literal(" ").append(Text.translatable("attribute.modifier.equals.0", + StringHelper.formatTicks((int)Math.abs(time)), + Text.translatable(Util.createTranslationKey("spell_attribute", id)) + ).formatted(Formatting.LIGHT_PURPLE)); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java index d81e4f39..33b2b837 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java @@ -1,17 +1,33 @@ package com.minelittlepony.unicopia.ability.magic.spell; +import java.util.List; + +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; +import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; /** * A magic effect with a set duration capable of reporting how long it has until it runs out. */ public interface TimedSpell extends Spell { + int BASE_DURATION = 120 * 20; + Timer getTimer(); + static void appendDurationTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.ofTime(SpellAttributes.DURATION, BASE_DURATION + getExtraDuration(type.traits()))); + } + + static int getExtraDuration(SpellTraits traits) { + return (int)(traits.get(Trait.FOCUS, 0, 160) * 19) * 20; + } + class Timer implements Tickable, NbtSerialisable { private int maxDuration; private int duration; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java index 093ea63f..b239cad6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java @@ -5,9 +5,9 @@ import java.util.List; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; -import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.FriendshipBraceletItem; @@ -17,7 +17,6 @@ import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -28,18 +27,20 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { .build(); - static void appendTooltip(CustomisedSpellType type, List tooltip) { - float addedRange = type.traits().get(Trait.POWER); - if (addedRange != 0) { - tooltip.add(EffectUtils.formatModifierChange("spell.unicopia.shield.additional_range", addedRange, false)); - } - tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.caston.location")).formatted(Formatting.GRAY)); + static void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.CAST_ON_LOCATION); + tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); } protected AreaProtectionSpell(CustomisedSpellType type) { super(type); } + /*@Override + public Spell prepareForCast(Caster caster, CastingMethod method) { + return method == CastingMethod.STAFF || getTraits().get(Trait.GENEROSITY) > 0 ? toPlaceable() : this; + }*/ + @Override public boolean tick(Caster source, Situation situation) { @@ -70,7 +71,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { private double getRange(Caster source) { float multiplier = source instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2; - float min = 4 + getTraits().get(Trait.POWER); + float min = 4 + getAdditionalRange(); double range = (min + (source.getLevel().getScaled(4) * 2)) / multiplier; if (source instanceof Pony && range > 2) { range = Math.sqrt(range); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java index 9af5cddb..c951cb9f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; + import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -13,9 +15,9 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; -import net.minecraft.entity.ItemEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; +import net.minecraft.text.Text; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -26,9 +28,20 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp private final Timer timer; + public static void appendTooltip2(CustomisedSpellType type, List tooltip) { + TimedSpell.appendDurationTooltip(type, tooltip); + AbstractAreaEffectSpell.appendRangeTooltip(type, tooltip); + if (type.traits().get(Trait.ORDER) >= 20) { + tooltip.add(SpellAttributes.TARGET_ENTITY); + } else { + appendValidTargetsTooltip(type, tooltip); + } + appendCastLocationTooltip(type, tooltip); + } + protected AttractiveSpell(CustomisedSpellType type) { super(type); - timer = new Timer((120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19)) * 20); + timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); } @Override @@ -73,17 +86,12 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp }); } - @Override - public double getDrawDropOffRange(Caster caster) { - return 10 + (caster.getLevel().getScaled(8) * 2); - } - @Override protected boolean isValidTarget(Caster source, Entity entity) { if (target.referenceEquals(entity)) { return true; } - return getTraits().get(Trait.KNOWLEDGE) > 10 ? entity instanceof ItemEntity : super.isValidTarget(source, entity); + return super.isValidTarget(source, entity); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index c35227af..925a8c5a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -1,5 +1,6 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -22,6 +23,7 @@ import net.minecraft.entity.attribute.*; import net.minecraft.entity.attribute.EntityAttributeModifier.Operation; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; +import net.minecraft.text.Text; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -46,6 +48,11 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, .with(Trait.POWER, 1) .build(); + static void appendTooltip(CustomisedSpellType type, List tooltip) { + TimedSpell.appendDurationTooltip(type, tooltip); + tooltip.add(SpellAttributes.of(SpellAttributes.SOAPINESS, (int)(type.traits().get(Trait.POWER) * 2))); + } + private final Timer timer; private int struggles; @@ -55,7 +62,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, protected BubbleSpell(CustomisedSpellType type) { super(type); - timer = new Timer((120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19)) * 20); + timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); struggles = (int)(getTraits().get(Trait.POWER) * 2); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java index ce440570..4c9c1dd7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java @@ -1,5 +1,6 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; import java.util.function.Consumer; import org.jetbrains.annotations.Nullable; @@ -7,6 +8,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.mixin.MixinFallingBlockEntity; @@ -17,6 +19,7 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.FallingBlockEntity; +import net.minecraft.text.Text; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.BlockPos; @@ -37,6 +40,11 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B private static final float HORIZONTAL_VARIANCE = 0.25F; private static final float MAX_STRENGTH = 120; + static void appendTooltip(CustomisedSpellType type, List tooltip) { + float velocity = 0.1F + type.relativeTraits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH); + tooltip.add(SpellAttributes.of(SpellAttributes.VERTICAL_VELOCITY, velocity / 16F)); + } + protected CatapultSpell(CustomisedSpellType type) { super(type); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java index 9a62d4db..8c7f1b61 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; import java.util.ArrayList; import java.util.List; +import java.util.function.Supplier; import org.jetbrains.annotations.Nullable; @@ -23,7 +24,8 @@ import net.minecraft.util.TypedActionResult; public record CustomisedSpellType ( SpellType type, - SpellTraits traits + SpellTraits traits, + Supplier traitsDifferenceSupplier ) implements SpellPredicate { public boolean isEmpty() { @@ -34,6 +36,10 @@ public record CustomisedSpellType ( return type().isStackable(); } + public SpellTraits relativeTraits() { + return traitsDifferenceSupplier.get(); + } + public T create() { try { return type.getFactory().create(this); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java index 869ef51d..760f222f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; + import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; @@ -11,6 +13,7 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; +import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegate.HitListener { @@ -18,6 +21,10 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat .with(Trait.POWER, 1) .build(); + static void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, (1 + type.relativeTraits().get(Trait.POWER)) * 10)); + } + protected DispellEvilSpell(CustomisedSpellType type) { super(type); } @@ -28,7 +35,7 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat return !isDead(); } - source.findAllEntitiesInRange(getTraits().get(Trait.POWER) * 10, e -> e.getType() == EntityType.PHANTOM).forEach(entity -> { + source.findAllEntitiesInRange((1 + getTraits().get(Trait.POWER)) * 10, e -> e.getType() == EntityType.PHANTOM).forEach(entity -> { entity.damage(entity.getDamageSources().magic(), 50); if (entity instanceof LivingEntity l) { double d = source.getOriginVector().getX() - entity.getX(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java index 3d88d40f..f67ceb2b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java @@ -1,20 +1,29 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; + import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.util.shape.Sphere; +import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; /** * An area-effect spell that disperses illusions. */ public class DisperseIllusionSpell extends AbstractAreaEffectSpell { + public static void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 15 + type.traits().get(Trait.POWER))); + tooltip.add(SpellAttributes.ofTime(SpellAttributes.DURATION, (1 + (long)type.traits().get(Trait.STRENGTH)) * 100)); + } + protected DisperseIllusionSpell(CustomisedSpellType type) { super(type); } @@ -22,7 +31,7 @@ public class DisperseIllusionSpell extends AbstractAreaEffectSpell { @Override public boolean tick(Caster source, Situation situation) { - float range = Math.max(0, 15 + getTraits().get(Trait.POWER)); + float range = Math.max(0, 15 + getAdditionalRange()); if (range == 0) { return false; @@ -41,7 +50,7 @@ public class DisperseIllusionSpell extends AbstractAreaEffectSpell { e.getSpellSlot().get(SpellPredicate.CAN_SUPPRESS) .filter(spell -> spell.isVulnerable(source, this)) .ifPresent(spell -> { - spell.onSuppressed(source, 1 + getTraits().get(Trait.STRENGTH)); + spell.onSuppressed(source, 100 * (1 + getTraits().get(Trait.STRENGTH))); e.playSound(USounds.SPELL_ILLUSION_DISPERSE, 0.2F, 0.5F); }); }); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java index b787778b..923701ce 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; + import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; @@ -11,11 +13,19 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import net.minecraft.entity.Entity; import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.Text; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.Vec3d; public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.EntityHitListener { + static void appendTooltip(CustomisedSpellType type, List tooltip) { + float damage = type.traits().get(Trait.BLOOD); + if (damage > 0) { + tooltip.add(SpellAttributes.ofRelative(SpellAttributes.DAMAGE_TO_TARGET, damage)); + } + } + private final EntityReference target = new EntityReference<>(); private int ticks = 10; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java index 40fd8413..eb2bc744 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java @@ -5,6 +5,7 @@ import java.util.stream.Stream; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -15,6 +16,7 @@ import com.minelittlepony.unicopia.particle.ParticleUtils; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -36,6 +38,17 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { .with(Trait.ORDER, 15) .build(); + public static void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.ofTime(SpellAttributes.DURATION, 10 + (int)(type.traits().get(Trait.FOCUS, 0, 160)))); + tooltip.add(SpellAttributes.of(SpellAttributes.STRENGTH, type.traits().get(Trait.STRENGTH, 2, 9))); + tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, (float)getEffectRange(type.traits()))); + tooltip.add(SpellAttributes.of(SpellAttributes.SIMULTANIOUS_TARGETS, getMaxTargets(type.traits()))); + tooltip.add(SpellAttributes.of(SpellAttributes.COST_PER_INDIVIDUAL, (float)getCostPerEntity(type.traits()))); + float generosity = type.traits().get(Trait.GENEROSITY, 1, MAX_GENEROSITY_FACTOR) / MAX_GENEROSITY_FACTOR; + tooltip.add(SpellAttributes.of(SpellAttributes.TARGET_PREFERENCE, (int)(generosity * 100))); + tooltip.add(SpellAttributes.of(SpellAttributes.CASTER_PREFERENCE, (int)((1 - generosity) * 100))); + } + private final Timer timer; protected FeatherFallSpell(CustomisedSpellType type) { @@ -91,35 +104,33 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { ParticleUtils.spawnParticles(new MagicParticleEffect(getType().getColor()), target, 7); }); - return caster.subtractEnergyCost(timer.getTicksRemaining() % 50 == 0 ? getCostPerEntity() * targets.size() : 0); + return caster.subtractEnergyCost(timer.getTicksRemaining() % 50 == 0 ? getCostPerEntity(getTraits()) * targets.size() : 0); } - protected double getCostPerEntity() { - float focus = Math.max(getTraits().get(Trait.FOCUS), 80) - 80; - float power = Math.max(getTraits().get(Trait.POWER), 10) - 10; + protected static double getCostPerEntity(SpellTraits traits) { + float focus = Math.max(traits.get(Trait.FOCUS), 80) - 80; + float power = Math.max(traits.get(Trait.POWER), 10) - 10; return MathHelper.clamp((power * POWERS_RANGE_WEIGHT) - (focus * FOCUS_RANGE_WEIGHT), 1, 7); } - protected double getEffectRange() { - float power = getTraits().get(Trait.POWER) - 10; - - return MathHelper.clamp(power * POWERS_RANGE_WEIGHT, MIN_RANGE, MAX_RANGE); + protected static double getEffectRange(SpellTraits traits) { + return MathHelper.clamp((traits.get(Trait.POWER) - 10) * POWERS_RANGE_WEIGHT, MIN_RANGE, MAX_RANGE); } - protected long getMaxTargets() { - long generosity = (long)getTraits().get(Trait.GENEROSITY) * 2L; - long focus = (long)getTraits().get(Trait.FOCUS, MIN_TARGETS, MAX_TARGETS) * 2L; + protected static long getMaxTargets(SpellTraits traits) { + long generosity = (long)traits.get(Trait.GENEROSITY) * 2L; + long focus = (long)traits.get(Trait.FOCUS, MIN_TARGETS, MAX_TARGETS) * 2L; return generosity + focus; } protected Stream getTargets(Caster caster) { - return Stream.concat(Stream.of(caster.asEntity()), caster.findAllEntitiesInRange(getEffectRange()).sorted((a, b) -> { + return Stream.concat(Stream.of(caster.asEntity()), caster.findAllEntitiesInRange(getEffectRange(getTraits())).sorted((a, b) -> { return Integer.compare( FriendshipBraceletItem.isComrade(caster, a) ? 1 : 0, FriendshipBraceletItem.isComrade(caster, b) ? 1 : 0 ); - }).distinct()).limit(getMaxTargets()); + }).distinct()).limit(getMaxTargets(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java index db63eaf4..47bdf918 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java @@ -1,9 +1,12 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; + import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; @@ -14,6 +17,7 @@ import net.minecraft.entity.Entity; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.text.Text; import net.minecraft.util.hit.EntityHitResult; public class FireBoltSpell extends AbstractSpell implements HomingSpell, @@ -31,6 +35,19 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell, .with(Trait.FIRE, 60) .build(); + public static void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.of(SpellAttributes.EXPLOSION_STRENGTH, type.traits().get(Trait.POWER, 0, type.traits().get(Trait.FOCUS) >= 50 ? 500 : 50) / 10F)); + tooltip.add(SpellAttributes.of(SpellAttributes.VELOCITY, 1.3F + type.traits().get(Trait.STRENGTH) / 11F)); + tooltip.add(SpellAttributes.of(SpellAttributes.PROJECTILE_COUNT, 1 + (int)type.traits().get(Trait.EARTH) * 3)); + + float homingRange = type.traits().get(Trait.FOCUS); + + if (homingRange >= 50) { + tooltip.add(SpellAttributes.FOLLOWS_TARGET); + tooltip.add(SpellAttributes.of(SpellAttributes.FOLLOW_RANGE, homingRange - 50)); + } + } + private final EntityReference target = new EntityReference<>(); protected FireBoltSpell(CustomisedSpellType type) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireSpell.java index 8dade44f..f633c952 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireSpell.java @@ -1,9 +1,12 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; + import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -25,6 +28,7 @@ import net.minecraft.entity.damage.DamageTypes; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.particle.ParticleTypes; import net.minecraft.sound.SoundCategory; +import net.minecraft.text.Text; import net.minecraft.registry.tag.BlockTags; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; @@ -41,6 +45,10 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele .with(Trait.FIRE, 15) .build(); + public static void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); + } + protected FireSpell(CustomisedSpellType type) { super(type); } @@ -67,14 +75,14 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele generateParticles(source); } - return new Sphere(false, Math.max(0, 4 + getTraits().get(Trait.POWER))).translate(source.getOrigin()).getBlockPositions().reduce(false, + return new Sphere(false, Math.max(0, 4 + getAdditionalRange())).translate(source.getOrigin()).getBlockPositions().reduce(false, (r, i) -> source.canModifyAt(i) && applyBlocks(source.asWorld(), i), (a, b) -> a || b) || applyEntities(source, source.getOriginVector()); } protected void generateParticles(Caster source) { - source.spawnParticles(new Sphere(false, Math.max(0, 4 + getTraits().get(Trait.POWER))), (int)(1 + source.getLevel().getScaled(8)) * 6, pos -> { + source.spawnParticles(new Sphere(false, Math.max(0, 4 + getAdditionalRange())), (int)(1 + source.getLevel().getScaled(8)) * 6, pos -> { source.addParticle(ParticleTypes.LARGE_SMOKE, pos, Vec3d.ZERO); }); } @@ -122,7 +130,7 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele } protected boolean applyEntities(Caster source, Vec3d pos) { - return source.findAllEntitiesInRange(Math.max(0, 3 + getTraits().get(Trait.POWER)), e -> { + return source.findAllEntitiesInRange(Math.max(0, 3 + getAdditionalRange()), e -> { LivingEntity master = source.getMaster(); return (!(e.equals(source.asEntity()) || e.equals(master)) || (master instanceof PlayerEntity && !EquinePredicates.PLAYER_UNICORN.test(master))) && !(e instanceof ItemEntity) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java index cec7e61a..6ec3554e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java @@ -1,6 +1,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; import java.util.HashSet; +import java.util.List; import java.util.Set; import com.minelittlepony.unicopia.USounds; @@ -8,6 +9,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.advancement.UCriteria; @@ -22,6 +24,7 @@ import net.minecraft.block.*; import net.minecraft.fluid.*; import net.minecraft.nbt.*; import net.minecraft.state.property.Properties; +import net.minecraft.text.Text; import net.minecraft.registry.tag.TagKey; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; @@ -34,6 +37,10 @@ public class HydrophobicSpell extends AbstractSpell { .with(Trait.FOCUS, 5) .with(Trait.KNOWLEDGE, 1) .build(); + static void appendTooltip(CustomisedSpellType type, List tooltip) { + ShieldSpell.appendCastLocationTooltip(type, tooltip); + tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); + } private final TagKey affectedFluid; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java index 9688b7f7..48c99c0c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java @@ -6,6 +6,7 @@ import java.util.List; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -20,6 +21,7 @@ import com.minelittlepony.unicopia.util.VecHelper; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; +import net.minecraft.text.Text; public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileDelegate.HitListener { public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() @@ -29,13 +31,18 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD .with(Trait.ORDER, 25) .build(); + public static void appendTooltip(CustomisedSpellType type, List tooltip) { + TimedSpell.appendDurationTooltip(type, tooltip); + tooltip.add(SpellAttributes.of(SpellAttributes.ORB_COUNT, 2 + (int)(type.relativeTraits().get(Trait.LIFE, 10, 20) / 10F))); + } + private final Timer timer; private final List> lights = new ArrayList<>(); protected LightSpell(CustomisedSpellType type) { super(type); - timer = new Timer((120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19)) * 20); + timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java index b48866b7..12032913 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java @@ -1,18 +1,25 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.List; + import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; -import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import net.minecraft.entity.Entity; import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.Text; public class MimicSpell extends AbstractDisguiseSpell implements HomingSpell, TimedSpell { + static final int BASE_DURATION = 120 * 20; + + public static void appendTooltip(CustomisedSpellType type, List tooltip) { + TimedSpell.appendDurationTooltip(type, tooltip); + } private final Timer timer; protected MimicSpell(CustomisedSpellType type) { super(type); - timer = new Timer((120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19)) * 20); + timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java index 910fddd3..b1209943 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java @@ -8,6 +8,7 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.EntityReference; @@ -31,6 +32,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; import net.minecraft.particle.ParticleTypes; +import net.minecraft.text.Text; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.BlockPos; @@ -79,6 +81,11 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti return e -> e.getType() == type; } + static void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); + tooltip.add(SpellAttributes.of(SpellAttributes.WAVE_SIZE, 10 + (int)type.traits().get(Trait.CHAOS, 0, 10))); + } + private final List> summonedEntities = new ArrayList<>(); private int spawnCountdown; @@ -90,7 +97,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti @Override public boolean tick(Caster source, Situation situation) { - float radius = 4 + source.getLevel().getScaled(4) * 4 + getTraits().get(Trait.POWER); + float radius = 4 + source.getLevel().getScaled(4) * 4 + getAdditionalRange(); if (radius <= 0) { return false; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ScorchSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ScorchSpell.java index 24c8a632..e64aa6fa 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ScorchSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ScorchSpell.java @@ -36,7 +36,7 @@ public class ScorchSpell extends FireSpell implements ProjectileDelegate.Configu BlockPos pos = PosHelper.findSolidGroundAt(source.asWorld(), source.getOrigin(), source.getPhysics().getGravitySignum()); if (source.canModifyAt(pos) && StateMaps.FIRE_AFFECTED.convert(source.asWorld(), pos)) { - source.spawnParticles(new Sphere(false, Math.max(1, getTraits().get(Trait.POWER))), 5, p -> { + source.spawnParticles(new Sphere(false, Math.max(1, getAdditionalRange())), 5, p -> { source.addParticle(ParticleTypes.SMOKE, PosHelper.offset(p, pos), Vec3d.ZERO); }); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java index 541f1033..705fb4b0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java @@ -7,13 +7,14 @@ import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; -import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect; @@ -27,6 +28,7 @@ import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; import net.minecraft.entity.EyeOfEnderEntity; import net.minecraft.entity.FallingBlockEntity; +import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.TntEntity; import net.minecraft.entity.Entity.RemovalReason; @@ -37,7 +39,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity; import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -49,27 +50,32 @@ public class ShieldSpell extends AbstractSpell { .with(Trait.AIR, 9) .build(); - static void appendTooltip(CustomisedSpellType type, List tooltip) { - float addedRange = type.traits().get(Trait.POWER); - if (addedRange != 0) { - tooltip.add(EffectUtils.formatModifierChange("spell.unicopia.shield.additional_range", addedRange, false)); - } - if (type.traits().get(Trait.LIFE) > 0) { - tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.permit.passive")).formatted(Formatting.GRAY)); - } - if (type.traits().get(Trait.BLOOD) > 0) { - tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.permit.hostile")).formatted(Formatting.GRAY)); - } - if (type.traits().get(Trait.ICE) > 0) { - tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.permit.player")).formatted(Formatting.GRAY)); - } - if (type.traits().get(Trait.GENEROSITY) > 0) { - tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.caston.location")).formatted(Formatting.GRAY)); + static void appendTooltip(CustomisedSpellType type, List tooltip) { + AbstractAreaEffectSpell.appendRangeTooltip(type, tooltip); + appendValidTargetsTooltip(type, tooltip); + appendCastLocationTooltip(type, tooltip); + } + + static void appendValidTargetsTooltip(CustomisedSpellType type, List tooltip) { + if (type.traits().get(Trait.KNOWLEDGE) > 10) { + tooltip.add(SpellAttributes.PERMIT_ITEMS); } else { - tooltip.add(Text.literal(" ").append(Text.translatable("spell.unicopia.shield.caston.person")).formatted(Formatting.GRAY)); + if (type.traits().get(Trait.LIFE) > 0) { + tooltip.add(SpellAttributes.PERMIT_PASSIVE); + } + if (type.traits().get(Trait.BLOOD) > 0) { + tooltip.add(SpellAttributes.PERMIT_HOSTILE); + } + if (type.traits().get(Trait.ICE) > 0) { + tooltip.add(SpellAttributes.PERMIT_PLAYER); + } } } + static void appendCastLocationTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(type.traits().get(Trait.GENEROSITY) > 0 ? SpellAttributes.CAST_ON_LOCATION : SpellAttributes.CAST_ON_PERSON); + } + protected final TargetSelecter targetSelecter = new TargetSelecter(this).setFilter(this::isValidTarget); private final Lerp radius = new Lerp(0); @@ -177,6 +183,11 @@ public class ShieldSpell extends AbstractSpell { } protected boolean isValidTarget(Caster source, Entity entity) { + + if (getTraits().get(Trait.KNOWLEDGE) > 10) { + return entity instanceof ItemEntity; + } + boolean valid = (entity instanceof LivingEntity || entity instanceof TntEntity || entity instanceof FallingBlockEntity diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java index f6f45d05..42e784d1 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.player.Pony; @@ -28,6 +29,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -37,6 +39,10 @@ import net.minecraft.util.math.Vec3d; public class SiphoningSpell extends AbstractAreaEffectSpell { static final Predicate TARGET_PREDICATE = EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.and(EntityPredicates.VALID_LIVING_ENTITY); + static void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4)); + } + private int ticksUpset; protected SiphoningSpell(CustomisedSpellType type) { @@ -56,7 +62,7 @@ public class SiphoningSpell extends AbstractAreaEffectSpell { } if (source.isClient()) { - float radius = 4 + source.getLevel().getScaled(5); + float radius = 4 + source.getLevel().getScaled(5) + getAdditionalRange(); int direction = isFriendlyTogether(source) ? 1 : -1; source.spawnParticles(new Sphere(true, radius, 1, 0, 1), 1, pos -> { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index 617fcf07..0490c0e0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.function.BiConsumer; import org.jetbrains.annotations.Nullable; +import com.google.common.base.Suppliers; import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Affine; @@ -54,29 +55,29 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType FROST = register("frost", builder(IceSpell::new).color(0xEABBFF).shape(GemstoneItem.Shape.TRIANGLE).traits(IceSpell.DEFAULT_TRAITS)); public static final SpellType CHILLING_BREATH = register("chilling_breath", builder(ChillingBreathSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEAFF).shape(GemstoneItem.Shape.TRIANGLE).traits(ChillingBreathSpell.DEFAULT_TRAITS)); - public static final SpellType SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).stackable().shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS)); - public static final SpellType FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS)); - public static final SpellType INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS)); + public static final SpellType SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).stackable().shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip)); + public static final SpellType FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip)); + public static final SpellType INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip)); public static final SpellType SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS).tooltip(ShieldSpell::appendTooltip)); - public static final SpellType ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS)); - public static final SpellType VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS)); + public static final SpellType ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS).tooltip(AreaProtectionSpell::appendTooltip)); + public static final SpellType VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS).tooltip(AttractiveSpell::appendTooltip2)); public static final SpellType DARK_VORTEX = register("dark_vortex", builder(DarkVortexSpell::new).affinity(Affinity.BAD).color(0xA33333).stackable().shape(GemstoneItem.Shape.VORTEX).traits(DarkVortexSpell.DEFAULT_TRAITS)); - public static final SpellType NECROMANCY = register("necromancy", builder(NecromancySpell::new).affinity(Affinity.BAD).color(0xFA3A3A).shape(GemstoneItem.Shape.SKULL)); - public static final SpellType SIPHONING = register("siphoning", builder(SiphoningSpell::new).affinity(Affinity.NEUTRAL).color(0xFFA3AA).shape(GemstoneItem.Shape.LAMBDA)); - public static final SpellType REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS)); + public static final SpellType NECROMANCY = register("necromancy", builder(NecromancySpell::new).affinity(Affinity.BAD).color(0xFA3A3A).shape(GemstoneItem.Shape.SKULL).tooltip(NecromancySpell::appendTooltip)); + public static final SpellType SIPHONING = register("siphoning", builder(SiphoningSpell::new).affinity(Affinity.NEUTRAL).color(0xFFA3AA).shape(GemstoneItem.Shape.LAMBDA).tooltip(SiphoningSpell::appendTooltip)); + public static final SpellType REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS).tooltip(DisperseIllusionSpell::appendTooltip)); public static final SpellType AWKWARD = register("awkward", builder(AwkwardSpell::new).affinity(Affinity.NEUTRAL).color(0x3A59FF).shape(GemstoneItem.Shape.ICE)); public static final SpellType TRANSFORMATION = register("transformation", builder(TransformationSpell::new).color(0x19E48E).shape(GemstoneItem.Shape.BRUSH)); - public static final SpellType FEATHER_FALL = register("feather_fall", builder(FeatherFallSpell::new).color(0x00EEFF).shape(GemstoneItem.Shape.LAMBDA).traits(FeatherFallSpell.DEFAULT_TRAITS)); - public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS)); - public static final SpellType FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS)); - public static final SpellType LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS)); - public static final SpellType DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).stackable().shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS)); + public static final SpellType FEATHER_FALL = register("feather_fall", builder(FeatherFallSpell::new).color(0x00EEFF).shape(GemstoneItem.Shape.LAMBDA).traits(FeatherFallSpell.DEFAULT_TRAITS).tooltip(FeatherFallSpell::appendTooltip)); + public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS).tooltip(CatapultSpell::appendTooltip)); + public static final SpellType FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS).tooltip(FireBoltSpell::appendTooltip)); + public static final SpellType LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS).tooltip(LightSpell::appendTooltip)); + public static final SpellType DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).stackable().shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS).tooltip(DisplacementSpell::appendTooltip)); public static final SpellType PORTAL = register("portal", builder(PortalSpell::new).color(0x99FFFF).shape(GemstoneItem.Shape.RING).traits(PortalSpell.DEFAULT_TRAITS)); - public static final SpellType MIMIC = register("mimic", builder(MimicSpell::new).color(0xFFFF00).shape(GemstoneItem.Shape.ARROW)); - public static final SpellType MIND_SWAP = register("mind_swap", builder(MindSwapSpell::new).affinity(Affinity.BAD).color(0xF9FF99).shape(GemstoneItem.Shape.WAVE)); - public static final SpellType HYDROPHOBIC = register("hydrophobic", SpellType.builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).stackable().shape(GemstoneItem.Shape.ROCKET)); - public static final SpellType BUBBLE = register("bubble", builder(BubbleSpell::new).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.DONUT).traits(BubbleSpell.DEFAULT_TRAITS)); - public static final SpellType DISPEL_EVIL = register("dispel_evil", builder(DispellEvilSpell::new).color(0x00FF00).shape(GemstoneItem.Shape.CROSS).traits(DispellEvilSpell.DEFAULT_TRAITS)); + public static final SpellType MIMIC = register("mimic", builder(MimicSpell::new).color(0xFFFF00).shape(GemstoneItem.Shape.ARROW).tooltip(MimicSpell::appendTooltip)); + public static final SpellType MIND_SWAP = register("mind_swap", builder(MindSwapSpell::new).affinity(Affinity.BAD).color(0xF9FF99).shape(GemstoneItem.Shape.WAVE).tooltip(MimicSpell::appendTooltip)); + public static final SpellType HYDROPHOBIC = register("hydrophobic", SpellType.builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).stackable().shape(GemstoneItem.Shape.ROCKET).tooltip(HydrophobicSpell::appendTooltip)); + public static final SpellType BUBBLE = register("bubble", builder(BubbleSpell::new).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.DONUT).traits(BubbleSpell.DEFAULT_TRAITS).tooltip(BubbleSpell::appendTooltip)); + public static final SpellType DISPEL_EVIL = register("dispel_evil", builder(DispellEvilSpell::new).color(0x00FF00).shape(GemstoneItem.Shape.CROSS).traits(DispellEvilSpell.DEFAULT_TRAITS).tooltip(DispellEvilSpell::appendTooltip)); public static void bootstrap() {} @@ -109,7 +110,7 @@ public final class SpellType implements Affine, SpellPredicate< this.factory = factory; this.traits = traits; this.stackable = stackable; - traited = new CustomisedSpellType<>(this, traits); + traited = new CustomisedSpellType<>(this, traits, SpellTraits::empty); defaultStack = UItems.GEMSTONE.getDefaultStack(this); } @@ -165,7 +166,7 @@ public final class SpellType implements Affine, SpellPredicate< } public CustomisedSpellType withTraits(SpellTraits traits) { - return traits.isEmpty() ? withTraits() : new CustomisedSpellType<>(this, traits); + return traits.isEmpty() ? withTraits() : new CustomisedSpellType<>(this, traits, Suppliers.memoize(() -> traits.map((trait, value) -> value - getTraits().get(trait)))); } public Factory getFactory() { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java index f900ac24..3bef5609 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java @@ -60,6 +60,10 @@ public final class SpellTraits implements Iterable> { }); } + public static SpellTraits empty() { + return EMPTY; + } + public static Map all() { return new HashMap<>(REGISTRY); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java index fd63fc84..750c1a8e 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java @@ -6,6 +6,7 @@ import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import net.minecraft.util.StringHelper; public interface EffectUtils { static boolean isPoisoned(LivingEntity entity) { @@ -50,6 +51,13 @@ public interface EffectUtils { return false; } + static Text formatModifierChange(String modifierName, int time, boolean isDetrimental) { + return Text.literal(" ").append(Text.translatable("attribute.modifier.equals.0", + StringHelper.formatTicks(Math.abs(time)), + Text.translatable(modifierName) + ).formatted((isDetrimental ? time : -time) < 0 ? Formatting.DARK_GREEN : Formatting.RED)); + } + static Text formatModifierChange(String modifierName, float change, boolean isDetrimental) { return Text.literal(" ").append(Text.translatable("attribute.modifier." + (change > 0 ? "plus" : "take") + ".0", ItemStack.MODIFIER_FORMAT.format(Math.abs(change)), diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 60e60b2f..7c75fb3b 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -548,12 +548,6 @@ "spell.unicopia.fire_bolt": "Fire Bolt", "spell.unicopia.fire_bolt.lore": "Produces several burning projectiles", "spell.unicopia.shield": "Protection", - "spell.unicopia.shield.additional_range": "Additional Range", - "spell.unicopia.shield.permit.passive": "Permits Passive Mobs", - "spell.unicopia.shield.permit.hostile": "Permits Hostile Mobs", - "spell.unicopia.shield.permit.player": " Permits Other Players", - "spell.unicopia.shield.caston.location": "Applies to location", - "spell.unicopia.shield.caston.person": "Applies to self", "spell.unicopia.shield.lore": "Casts a protective shield around the user", "spell.unicopia.bubble": "Bubble", "spell.unicopia.bubble.lore": "Traps any creature it hits in a soap bubble", @@ -589,6 +583,33 @@ "spell.unicopia.catapult.lore": "Grabs a nearby block or entity and throws it into the air", "spell.unicopia.dispel_evil": "Dispel Evil", "spell.unicopia.dispel_evil.lore": "Casts away any nearby unearthly forces", + + "spell_attribute.unicopia.cast_on_location": "Applies to location", + "spell_attribute.unicopia.cast_on_person": "Applies to self", + "spell_attribute.unicopia.focused_entity": "Applies to focused entity", + "spell_attribute.unicopia.follows_target": "Follows target", + + "spell_attribute.unicopia.permit_items": " Permits Items", + "spell_attribute.unicopia.permit_passive": "Permits Passive Mobs", + "spell_attribute.unicopia.permit_hostile": "Permits Hostile Mobs", + "spell_attribute.unicopia.permit_player": " Permits Other Players", + + "spell_attribute.unicopia.range": "Effect Range", + "spell_attribute.unicopia.duration": "Effect Duration", + "spell_attribute.unicopia.strength": "Effect Strength", + "spell_attribute.unicopia.soapiness": "Soapiness", + "spell_attribute.unicopia.velocity": "Velocity", + "spell_attribute.unicopia.vertical_velocity": "Launch Speed", + "spell_attribute.unicopia.damage_to_target": "Damage to Target", + "spell_attribute.unicopia.simultanious_targets": "Simultanious Targets", + "spell_attribute.unicopia.cost_per_individual": "Mana cost per individual", + "spell_attribute.unicopia.explosion_strength": "Blast Strength", + "spell_attribute.unicopia.projectile_count": "Projectile Count", + "spell_attribute.unicopia.follow_range": "Following Range", + "spell_attribute.unicopia.orb_count": "Orb Count", + "spell_attribute.unicopia.wave_size": "Wave Size", + "spell_attribute.unicopia.target_preference": "Target Preference", + "spell_attribute.unicopia.caster_preference": "Caster Preference", "trait.unicopia.strength.name": "Strength", "trait.unicopia.strength.description": "Imparts physical strength or enhances endurance.\nSpells with more of the strength trait hit harder and last longer.", From 1e3560fc04d47615464bf3f52c86e69a51268dde Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 14:38:17 +0100 Subject: [PATCH 54/85] Send tracked data in smaller packets to avoid large buffer allocation warnings being printed --- .../ability/ChangelingDisguiseAbility.java | 1 - .../unicopia/ability/ToggleFlightAbility.java | 1 - .../unicopia/command/GravityCommand.java | 1 - .../unicopia/entity/Living.java | 8 +-- .../unicopia/entity/player/PlayerPhysics.java | 5 +- .../unicopia/entity/player/Pony.java | 3 +- .../network/MsgPlayerCapabilities.java | 18 +---- .../network/datasync/Transmittable.java | 11 --- .../unicopia/network/track/DataTracker.java | 41 +++++------ .../network/track/DataTrackerManager.java | 69 +++++++------------ .../network/track/MsgTrackedValues.java | 19 ++--- .../unicopia/network/track/ObjectTracker.java | 26 ++++--- .../network/track/TrackableDataType.java | 1 + .../util/serialization/PacketCodec.java | 18 +++++ 14 files changed, 99 insertions(+), 123 deletions(-) delete mode 100644 src/main/java/com/minelittlepony/unicopia/network/datasync/Transmittable.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java index dd6af2cc..b8c88516 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java @@ -64,7 +64,6 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility { } player.calculateDimensions(); - iplayer.setDirty(); return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java index caa3c701..66aa0050 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java @@ -65,7 +65,6 @@ public class ToggleFlightAbility implements Ability { } else { player.getPhysics().cancelFlight(true); } - player.setDirty(); player.setAnimation(Animation.SPREAD_WINGS, Animation.Recipient.ANYONE); return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java b/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java index c5249dcb..a97272e9 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java @@ -48,7 +48,6 @@ class GravityCommand { static int set(ServerCommandSource source, Collection targets, float gravity, boolean isSelf) { List affected = targets.stream().map(Living::living).filter(Objects::nonNull).map(l -> { l.getPhysics().setBaseGravityModifier(gravity); - l.setDirty(); if (l.asEntity() instanceof PlayerEntity player) { if (source.getEntity() == player) { player.sendMessage(Text.translatable("commands.gravity.set.self", gravity)); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 0ea9bc46..f5c82baf 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -31,7 +31,6 @@ import com.minelittlepony.unicopia.input.Interactable; import com.minelittlepony.unicopia.item.GlassesItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; -import com.minelittlepony.unicopia.network.datasync.Transmittable; import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.network.track.DataTrackerManager; import com.minelittlepony.unicopia.network.track.Trackable; @@ -74,7 +73,7 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -public abstract class Living implements Equine, Caster, Transmittable { +public abstract class Living implements Equine, Caster { protected final T entity; private final SpellInventory spells; @@ -479,9 +478,6 @@ public abstract class Living implements Equine, Caste return MathHelper.clamp(level / (float)maxLevel, 0, 1); } - @Override - public void setDirty() {} - @Override public void toNBT(NbtCompound compound) { enchants.toNBT(compound); @@ -498,12 +494,10 @@ public abstract class Living implements Equine, Caste fromSynchronizedNbt(compound); } - @Override public void toSyncronisedNbt(NbtCompound compound) { compound.put("armour", armour.toNBT()); } - @Override public void fromSynchronizedNbt(NbtCompound compound) { armour.fromNBT(compound.getCompound("armour")); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index 2721193c..836ce227 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -232,9 +232,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab entity.calculateDimensions(); } - if (!pony.isClient()) { - pony.setDirty(); - } + pony.setDirty(); } public double getHorizontalMotion() { @@ -621,6 +619,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab thrustScale = 0; descentRate = 0; entity.calculateDimensions(); + pony.setDirty(); if (entity.isOnGround() || !force) { //BlockState steppingState = pony.asEntity().getSteppingBlockState(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index b5f18c77..c876668e 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -175,6 +175,7 @@ public class Pony extends Living implements Copyable, Update animation.animation().getSound().ifPresent(sound -> { playSound(sound, sound == USounds.ENTITY_PLAYER_WOLOLO ? 0.1F : 0.9F, 1); }); + setDirty(); } } @@ -314,7 +315,7 @@ public class Pony extends Living implements Copyable, Update return getSpecies().getAffinity(); } - @Override + @Deprecated public void setDirty() { dirty = true; } diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java index 5c390078..79cfab5b 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java @@ -1,17 +1,12 @@ package com.minelittlepony.unicopia.network; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import com.sollace.fabwork.api.packets.HandledPacket; -import io.netty.buffer.ByteBufInputStream; -import io.netty.buffer.ByteBufOutputStream; import net.minecraft.network.PacketByteBuf; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtIo; /** * Sent to the client to update various data pertaining to a particular player. @@ -26,11 +21,7 @@ public class MsgPlayerCapabilities implements HandledPacket { MsgPlayerCapabilities(PacketByteBuf buffer) { playerId = buffer.readInt(); - try (InputStream in = new ByteBufInputStream(buffer)) { - compoundTag = NbtIo.readCompressed(in); - } catch (IOException e) { - throw new RuntimeException(e); - } + compoundTag = PacketCodec.COMPRESSED_NBT.read(buffer); } public MsgPlayerCapabilities(Pony player) { @@ -42,10 +33,7 @@ public class MsgPlayerCapabilities implements HandledPacket { @Override public void toBuffer(PacketByteBuf buffer) { buffer.writeInt(playerId); - try (OutputStream out = new ByteBufOutputStream(buffer)) { - NbtIo.writeCompressed(compoundTag, out); - } catch (IOException e) { - } + PacketCodec.COMPRESSED_NBT.write(buffer, compoundTag); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/Transmittable.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/Transmittable.java deleted file mode 100644 index 8895bd77..00000000 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/Transmittable.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.minelittlepony.unicopia.network.datasync; - -import net.minecraft.nbt.NbtCompound; - -public interface Transmittable { - void setDirty(); - - void toSyncronisedNbt(NbtCompound compound); - - void fromSynchronizedNbt(NbtCompound compound); -} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index 517dccd9..22e9335d 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.network.track; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import org.jetbrains.annotations.Nullable; +import java.util.Optional; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -75,30 +75,31 @@ public class DataTracker { } } - synchronized void getInitialPairs(List output) { + synchronized Optional getInitialPairs() { + initial = false; + dirtyIndices = new IntOpenHashSet(); updateTrackables(); - output.add(new MsgTrackedValues.TrackerEntries(id, true, codecs)); + return Optional.of(new MsgTrackedValues.TrackerEntries(id, true, codecs)); } - @Nullable - synchronized void getDirtyPairs(List output) { + synchronized Optional getDirtyPairs() { if (initial) { - initial = false; - dirtyIndices = new IntOpenHashSet(); - getInitialPairs(output); - } else { - updateTrackables(); - - if (!dirtyIndices.isEmpty()) { - IntSet toSend = dirtyIndices; - dirtyIndices = new IntOpenHashSet(); - List> pairs = new ArrayList<>(); - for (int i : toSend) { - pairs.add(codecs.get(i)); - } - output.add(new MsgTrackedValues.TrackerEntries(id, false, pairs)); - } + return getInitialPairs(); } + + updateTrackables(); + + if (dirtyIndices.isEmpty()) { + return Optional.empty(); + } + + IntSet toSend = dirtyIndices; + dirtyIndices = new IntOpenHashSet(); + List> pairs = new ArrayList<>(); + for (int i : toSend) { + pairs.add(codecs.get(i)); + } + return Optional.of(new MsgTrackedValues.TrackerEntries(id, false, pairs)); } synchronized void load(MsgTrackedValues.TrackerEntries values) { diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java index f2058a78..3b199346 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -1,7 +1,7 @@ package com.minelittlepony.unicopia.network.track; -import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; @@ -19,7 +19,6 @@ public class DataTrackerManager { final boolean isClient; private final List trackers = new ObjectArrayList<>(); private final List> objectTrackers = new ObjectArrayList<>(); - private final List packetEmitters = new ObjectArrayList<>(); @Nullable @@ -44,12 +43,32 @@ public class DataTrackerManager { public synchronized DataTracker checkoutTracker() { DataTracker tracker = new DataTracker(this, trackers.size()); trackers.add(tracker); + packetEmitters.add((sender, initial) -> { + var update = initial ? tracker.getInitialPairs() : tracker.getDirtyPairs(); + if (update.isPresent()) { + sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(new MsgTrackedValues( + entity.getId(), + Optional.empty(), + update + ))); + } + }); return tracker; } public synchronized ObjectTracker checkoutTracker(Supplier objFunction) { ObjectTracker tracker = new ObjectTracker<>(objectTrackers.size(), objFunction); objectTrackers.add(tracker); + packetEmitters.add((sender, initial) -> { + var update = initial ? tracker.getInitialPairs() : tracker.getDirtyPairs(); + if (update.isPresent()) { + sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(new MsgTrackedValues( + entity.getId(), + update, + Optional.empty() + ))); + } + }); return tracker; } @@ -58,25 +77,6 @@ public class DataTrackerManager { for (var emitter : packetEmitters) { emitter.sendPackets(sender, false); } - - if (trackers.isEmpty() && objectTrackers.isEmpty()) { - return; - } - - List toTransmit = new ArrayList<>(); - List objToTransmit = new ArrayList<>(); - - for (var entry : trackers) entry.getDirtyPairs(toTransmit); - for (var entry : objectTrackers) entry.getDirtyPairs(objToTransmit); - - if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) { - MsgTrackedValues packet = new MsgTrackedValues( - entity.getId(), - objToTransmit, - toTransmit - ); - sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(packet)); - } } } @@ -86,41 +86,22 @@ public class DataTrackerManager { for (var emitter : packetEmitters) { emitter.sendPackets((Consumer)sender, true); } - - if (trackers.isEmpty() && objectTrackers.isEmpty()) { - return; - } - - List toTransmit = new ArrayList<>(); - List objToTransmit = new ArrayList<>(); - - for (var entry : trackers) entry.getInitialPairs(toTransmit); - for (var entry : objectTrackers) entry.getInitialPairs(objToTransmit); - - if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) { - MsgTrackedValues packet = new MsgTrackedValues( - entity.getId(), - objToTransmit, - toTransmit - ); - sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(packet)); - } } } synchronized void load(MsgTrackedValues packet) { - for (var update : packet.updatedTrackers()) { + packet.updatedTrackers().ifPresent(update -> { DataTracker tracker = trackers.get(update.id()); if (tracker != null) { tracker.load(update); } - } - for (var update : packet.updatedObjects()) { + }); + packet.updatedObjects().ifPresent(update -> { ObjectTracker tracker = objectTrackers.get(update.id()); if (tracker != null) { tracker.load(update); } - } + }); } public interface PacketEmitter { diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java index 2a2800fb..a8483855 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java @@ -5,9 +5,11 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import com.sollace.fabwork.api.packets.HandledPacket; import net.minecraft.entity.Entity; @@ -17,22 +19,22 @@ import net.minecraft.network.PacketByteBuf; public record MsgTrackedValues( int owner, - List updatedObjects, - List updatedTrackers + Optional updatedObjects, + Optional updatedTrackers ) implements HandledPacket { public MsgTrackedValues(PacketByteBuf buffer) { this( buffer.readInt(), - buffer.readCollection(ArrayList::new, TrackerObjects::new), - buffer.readCollection(ArrayList::new, TrackerEntries::new) + buffer.readOptional(TrackerObjects::new), + buffer.readOptional(TrackerEntries::new) ); } @Override public void toBuffer(PacketByteBuf buffer) { buffer.writeInt(owner); - buffer.writeCollection(updatedObjects, (buf, obj) -> obj.write(buf)); - buffer.writeCollection(updatedTrackers, (buf, tracker) -> tracker.write(buf)); + buffer.writeOptional(updatedObjects, (buf, obj) -> obj.write(buf)); + buffer.writeOptional(updatedTrackers, (buf, tracker) -> tracker.write(buf)); } @Override @@ -48,14 +50,15 @@ public record MsgTrackedValues( this( buffer.readInt(), buffer.readCollection(HashSet::new, PacketByteBuf::readUuid), - buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketByteBuf::readNbt) + buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketCodec.NBT::read) ); + } public void write(PacketByteBuf buffer) { buffer.writeInt(id); buffer.writeCollection(removedValues, PacketByteBuf::writeUuid); - buffer.writeMap(values, PacketByteBuf::writeUuid, PacketByteBuf::writeNbt); + buffer.writeMap(values, PacketByteBuf::writeUuid, PacketCodec.NBT::write); } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java index b6e3ec57..6a1e6005 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java @@ -3,8 +3,8 @@ package com.minelittlepony.unicopia.network.track; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Supplier; @@ -73,18 +73,20 @@ public class ObjectTracker implements NbtSerialisable quickAccess = Map.copyOf(trackedObjects); } - synchronized void getInitialPairs(List output) { - if (!trackedObjects.isEmpty()) { - Map trackableCompounds = new HashMap<>(); - quickAccess.entrySet().forEach(object -> { - trackableCompounds.put(object.getKey(), object.getValue().toTrackedNbt()); - }); - - output.add(new MsgTrackedValues.TrackerObjects(id, Set.of(), trackableCompounds)); + synchronized Optional getInitialPairs() { + if (trackedObjects.isEmpty()) { + return Optional.empty(); } + + Map trackableCompounds = new HashMap<>(); + quickAccess.entrySet().forEach(object -> { + trackableCompounds.put(object.getKey(), object.getValue().toTrackedNbt()); + }); + + return Optional.of(new MsgTrackedValues.TrackerObjects(id, Set.of(), trackableCompounds)); } - synchronized void getDirtyPairs(List output) { + synchronized Optional getDirtyPairs() { if (!trackedObjects.isEmpty()) { Map trackableCompounds = new HashMap<>(); Set removedTrackableObjects = new HashSet<>(); @@ -100,9 +102,11 @@ public class ObjectTracker implements NbtSerialisable quickAccess = Map.copyOf(trackedObjects); if (!trackableCompounds.isEmpty() || !removedTrackableObjects.isEmpty()) { - output.add(new MsgTrackedValues.TrackerObjects(id, removedTrackableObjects, trackableCompounds)); + return Optional.of(new MsgTrackedValues.TrackerObjects(id, removedTrackableObjects, trackableCompounds)); } } + + return Optional.empty(); } synchronized void load(MsgTrackedValues.TrackerObjects objects) { diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java index 620edcca..e106081f 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java @@ -22,6 +22,7 @@ public record TrackableDataType(int id, PacketCodec codec) { public static final TrackableDataType BOOLEAN = of(new Identifier("boolean"), PacketCodec.BOOLEAN); public static final TrackableDataType UUID = of(new Identifier("uuid"), PacketCodec.UUID); public static final TrackableDataType NBT = of(new Identifier("nbt"), PacketCodec.NBT); + public static final TrackableDataType COMPRESSED_NBT = of(new Identifier("compressed_nbt"), PacketCodec.COMPRESSED_NBT); public static final TrackableDataType> OPTIONAL_POS = of(new Identifier("optional_pos"), PacketCodec.OPTIONAL_POS); public static final TrackableDataType RACE = TrackableDataType.of(Unicopia.id("race"), PacketCodec.ofRegistry(Race.REGISTRY)); diff --git a/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java b/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java index a20a6b51..b4674ba1 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java +++ b/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java @@ -1,5 +1,8 @@ package com.minelittlepony.unicopia.util.serialization; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Optional; import java.util.UUID; import java.util.function.BiConsumer; @@ -7,7 +10,10 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtIo; import net.minecraft.network.PacketByteBuf; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; @@ -27,6 +33,18 @@ public record PacketCodec(PacketByteBuf.PacketReader reader, PacketByteBuf public static final PacketCodec IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString); public static final PacketCodec NBT = new PacketCodec<>(PacketByteBuf::readNbt, PacketByteBuf::writeNbt); + public static final PacketCodec COMPRESSED_NBT = new PacketCodec<>(buffer -> { + try (InputStream in = new ByteBufInputStream(buffer)) { + return NbtIo.readCompressed(in); + } catch (IOException e) { + throw new RuntimeException(e); + } + }, (buffer, nbt) -> { + try (OutputStream out = new ByteBufOutputStream(buffer)) { + NbtIo.writeCompressed(nbt, out); + } catch (IOException e) { + } + }); public static final PacketCodec POS = new PacketCodec<>(PacketByteBuf::readBlockPos, PacketByteBuf::writeBlockPos); public static final PacketCodec> OPTIONAL_POS = POS.asOptional(); From 81db96d8a2139fc5f14d8918e23a1ca9858e0dd9 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 15:03:26 +0100 Subject: [PATCH 55/85] Compress nbt when sending it over the network --- .../unicopia/network/track/DataTracker.java | 3 ++- .../network/track/MsgTrackedValues.java | 4 ++-- .../util/serialization/PacketCodec.java | 18 ++++++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index 22e9335d..1c99f1cb 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -29,7 +29,7 @@ public class DataTracker { } public Entry startTracking(T value) { - Entry entry = startTracking(TrackableDataType.NBT, value.toTrackedNbt()); + Entry entry = startTracking(TrackableDataType.COMPRESSED_NBT, value.toTrackedNbt()); persistentObjects.put(entry.id(), value); return entry; } @@ -136,6 +136,7 @@ public class DataTracker { tracker.set(this, t); } } + static class Pair { private final TrackableDataType type; public final int id; diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java index a8483855..0baa2a9b 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java @@ -50,7 +50,7 @@ public record MsgTrackedValues( this( buffer.readInt(), buffer.readCollection(HashSet::new, PacketByteBuf::readUuid), - buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketCodec.NBT::read) + buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketCodec.COMPRESSED_NBT::read) ); } @@ -58,7 +58,7 @@ public record MsgTrackedValues( public void write(PacketByteBuf buffer) { buffer.writeInt(id); buffer.writeCollection(removedValues, PacketByteBuf::writeUuid); - buffer.writeMap(values, PacketByteBuf::writeUuid, PacketCodec.NBT::write); + buffer.writeMap(values, PacketByteBuf::writeUuid, PacketCodec.COMPRESSED_NBT::write); } } diff --git a/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java b/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java index b4674ba1..03336ec2 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java +++ b/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java @@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.util.serialization; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.util.Optional; import java.util.UUID; import java.util.function.BiConsumer; @@ -12,6 +11,7 @@ import java.util.function.Supplier; import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.Unpooled; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtIo; import net.minecraft.network.PacketByteBuf; @@ -33,16 +33,26 @@ public record PacketCodec(PacketByteBuf.PacketReader reader, PacketByteBuf public static final PacketCodec IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString); public static final PacketCodec NBT = new PacketCodec<>(PacketByteBuf::readNbt, PacketByteBuf::writeNbt); - public static final PacketCodec COMPRESSED_NBT = new PacketCodec<>(buffer -> { + + public static final PacketCodec RAW_BYTES = new PacketCodec<>( + buffer -> new PacketByteBuf(buffer.readBytes(buffer.readInt())), + (buffer, bytes) -> { + buffer.writeInt(bytes.writerIndex()); + buffer.writeBytes(bytes); + }); + public static final PacketCodec COMPRESSED_NBT = RAW_BYTES.xMap(buffer -> { try (InputStream in = new ByteBufInputStream(buffer)) { return NbtIo.readCompressed(in); } catch (IOException e) { throw new RuntimeException(e); } - }, (buffer, nbt) -> { - try (OutputStream out = new ByteBufOutputStream(buffer)) { + }, nbt -> { + var buffer = new PacketByteBuf(Unpooled.buffer()); + try (ByteBufOutputStream out = new ByteBufOutputStream(buffer)) { NbtIo.writeCompressed(nbt, out); + return buffer; } catch (IOException e) { + throw new RuntimeException(e); } }); From 0b3f49e7fee6805ed513ebd0764fa059113fade0 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 15:19:53 +0100 Subject: [PATCH 56/85] Ensure registration happens in order --- .../minelittlepony/unicopia/mixin/MixinEntity.java | 12 +++++++++--- .../unicopia/mixin/MixinLivingEntity.java | 8 +++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java index 41927ec9..38934dc3 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java @@ -50,10 +50,16 @@ abstract class MixinEntity implements EntityDuck, Trackable { @Override public DataTrackerManager getDataTrackers() { - if (dataTrackerManager == null) { - dataTrackerManager = new DataTrackerManager((Entity)(Object)this); + synchronized (this) { + if (dataTrackerManager == null) { + dataTrackerManager = new DataTrackerManager((Entity)(Object)this); + // ensure lazy registration happens + if (this instanceof Equine.Container eq) { + eq.get(); + } + } + return dataTrackerManager; } - return dataTrackerManager; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java index 45bfa819..aafd1d35 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java @@ -52,10 +52,12 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ @Override public Living get() { - if (caster == null) { - caster = create(); + synchronized (this) { + if (caster == null) { + caster = create(); + } + return (Living)caster; } - return (Living)caster; } @Override From 8ba83934a349cea564026c545939d268eb08adb8 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 15:54:32 +0100 Subject: [PATCH 57/85] Fix incorrect default for new players --- .../java/com/minelittlepony/unicopia/entity/player/Pony.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index c876668e..afdead15 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -116,8 +116,8 @@ public class Pony extends Living implements Copyable, Update sender.accept(Channel.SERVER_PLAYER_CAPABILITIES.toPacket(new MsgPlayerCapabilities(this))); } }); - race = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.HUMAN); - suppressedRace = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.HUMAN); + race = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.UNSET); + suppressedRace = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.UNSET); this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); this.corruption = new PlayerLevelStore(this, tracker, false, USounds.ENTITY_PLAYER_CORRUPTION); this.mana = addTicker(new ManaContainer(this, tracker)); From a6a19a4d4be671b50c8122baa9b48f028c30679b Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 15:54:45 +0100 Subject: [PATCH 58/85] Remove broken wings logging --- .../com/minelittlepony/unicopia/entity/player/PlayerPhysics.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index 836ce227..1dc7851f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -290,7 +290,6 @@ public class PlayerPhysics extends EntityPhysics implements Tickab } if (!pony.isClient()) { - System.out.println(ticksInAir + " " + type.canFly() + " " + isFlying() + " " + EffectUtils.hasBothBrokenWing(entity)); if (type.canFly() && isFlying() && EffectUtils.hasBothBrokenWing(entity) From 6057d8ea3bc445af2d608ae0bddb1ee4fac82be1 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 18:52:19 +0100 Subject: [PATCH 59/85] Move flight check fixes to onTick() --- .../server/MixinServerPlayNetworkHandler.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java index c6580d88..de2ed3ef 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java @@ -17,36 +17,37 @@ import net.minecraft.server.world.EntityTrackingListener; @Mixin(ServerPlayNetworkHandler.class) abstract class MixinServerPlayNetworkHandler implements EntityTrackingListener, ServerPlayPacketListener { + @Shadow public ServerPlayerEntity player; @Shadow private boolean floating; @Shadow private int floatingTicks; - private boolean flyingSurvival; private boolean prevMotionChecks; @Inject(method = "onPlayerMove(Lnet/minecraft/network/packet/c2s/play/PlayerMoveC2SPacket;)V", at = @At("HEAD")) private void beforePlayerMove(PlayerMoveC2SPacket packet, CallbackInfo info) { - ServerPlayerEntity player = ((ServerPlayNetworkHandler)(Object)this).player; NetworkThreadUtils.forceMainThread(packet, this, player.getServerWorld()); - flyingSurvival = Pony.of(player).getPhysics().isFlyingSurvival; - - if (flyingSurvival) { - setPreventMotionChecks(true); + prevMotionChecks = player.isInTeleportationState(); + if (Pony.of(player).getPhysics().isFlyingSurvival) { + ((ServerPlayerEntityDuck)player).setPreventMotionChecks(true); } } @Inject(method = "onPlayerMove(Lnet/minecraft/network/packet/c2s/play/PlayerMoveC2SPacket;)V", at = @At("RETURN")) private void afterPlayerMove(PlayerMoveC2SPacket packet, CallbackInfo info) { - if (flyingSurvival) { - setPreventMotionChecks(prevMotionChecks); + ((ServerPlayerEntityDuck)player).setPreventMotionChecks(prevMotionChecks); + if (Pony.of(player).getPhysics().isFlyingSurvival) { + floating = false; + floatingTicks = 0; + player.fallDistance = 0; } } - private void setPreventMotionChecks(boolean motionChecks) { - ServerPlayerEntity player = ((ServerPlayNetworkHandler)(Object)this).player; - prevMotionChecks = player.isInTeleportationState(); - ((ServerPlayerEntityDuck)player).setPreventMotionChecks(motionChecks); - player.fallDistance = 0; - floating = false; - floatingTicks = 0; + @Inject(method = "tick()V", at = @At("HEAD")) + private void beforePlayerTick() { + if (Pony.of(player).getPhysics().isFlyingSurvival) { + floating = false; + floatingTicks = 0; + player.fallDistance = 0; + } } } From e9114f9e126d60510da09e0dea088f1fdf8ce69b Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 21:01:01 +0100 Subject: [PATCH 60/85] Fixed data not being copied when the player changes dimensions --- .../ability/magic/MultiSpellSlot.java | 10 +++++ .../ability/magic/SingleSpellSlot.java | 5 +++ .../unicopia/ability/magic/SpellSlots.java | 3 +- .../entity/player/PlayerCharmTracker.java | 10 ++++- .../unicopia/entity/player/Pony.java | 37 ++++++++++--------- .../client/MixinClientPlayNetworkHandler.java | 24 ++++++++++++ .../server/MixinServerPlayNetworkHandler.java | 2 +- .../unicopia/network/track/DataTracker.java | 11 ++++++ .../network/track/DataTrackerManager.java | 10 +++++ .../unicopia/network/track/ObjectTracker.java | 9 +++++ 10 files changed, 101 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java index c9763388..21d5c7a2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.SpellReference; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.network.track.ObjectTracker; import com.minelittlepony.unicopia.network.track.Trackable; import com.minelittlepony.unicopia.network.track.TrackableObject; @@ -128,4 +129,13 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable { spell.fromNBT(compound); } } + + @Override + public void copyFrom(SpellSlots other, boolean alive) { + if (alive) { + other.stream().forEach(this::put); + } else { + other.stream().filter(SpellType.PLACE_CONTROL_SPELL).forEach(this::put); + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java index b1ba5633..73a1c6f2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java @@ -65,4 +65,9 @@ class SingleSpellSlot implements SpellSlots, NbtSerialisable { public void fromNBT(NbtCompound compound) { entry.readTrackedNbt(compound.getCompound("effect")); } + + @Override + public void copyFrom(SpellSlots other, boolean alive) { + other.get().ifPresent(this::put); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellSlots.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellSlots.java index 97d30882..32a70f87 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellSlots.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellSlots.java @@ -7,9 +7,10 @@ import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.NbtSerialisable; -public interface SpellSlots extends NbtSerialisable { +public interface SpellSlots extends NbtSerialisable, Copyable { static SpellInventory ofUnbounded(Caster caster) { return new SpellInventory(caster, new MultiSpellSlot(caster)); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java index 2721ec83..fbb29e1c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java @@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.item.EnchantableItem; +import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.NbtSerialisable; import net.minecraft.nbt.NbtCompound; @@ -15,7 +16,7 @@ import net.minecraft.nbt.NbtList; import net.minecraft.util.Hand; import net.minecraft.util.TypedActionResult; -public class PlayerCharmTracker implements NbtSerialisable { +public class PlayerCharmTracker implements NbtSerialisable, Copyable { private final Pony pony; @@ -62,6 +63,13 @@ public class PlayerCharmTracker implements NbtSerialisable { return previous; } + @Override + public void copyFrom(PlayerCharmTracker old, boolean alive) { + for (int i = 0; i < handSpells.length; i++) { + handSpells[i] = old.handSpells[i]; + } + } + @Override public void toNBT(NbtCompound compound) { NbtList equippedSpells = new NbtList(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index afdead15..09ec5ceb 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -63,7 +63,6 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; import net.minecraft.util.math.*; import net.minecraft.world.GameMode; import net.minecraft.world.GameRules; @@ -116,6 +115,7 @@ public class Pony extends Living implements Copyable, Update sender.accept(Channel.SERVER_PLAYER_CAPABILITIES.toPacket(new MsgPlayerCapabilities(this))); } }); + race = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.UNSET); suppressedRace = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.UNSET); this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); @@ -817,8 +817,6 @@ public class Pony extends Living implements Copyable, Update @Override public void toNBT(NbtCompound compound) { - compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString()); - compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString()); compound.put("mana", mana.toNBT()); compound.putInt("levels", levels.get()); compound.putInt("corruption", corruption.get()); @@ -827,8 +825,6 @@ public class Pony extends Living implements Copyable, Update @Override public void fromNBT(NbtCompound compound) { - setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN)); - setSuppressedRace(Race.fromName(compound.getString("suppressedSpecies"), Race.UNSET)); levels.set(compound.getInt("levels")); corruption.set(compound.getInt("corruption")); mana.fromNBT(compound.getCompound("mana")); @@ -837,7 +833,10 @@ public class Pony extends Living implements Copyable, Update @Override public void toSyncronisedNbt(NbtCompound compound) { + System.out.println("toSyncNbt"); super.toSyncronisedNbt(compound); + compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString()); + compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString()); compound.putFloat("magicExhaustion", magicExhaustion); compound.putInt("ticksInSun", ticksInSun); compound.putBoolean("hasShades", hasShades); @@ -857,7 +856,10 @@ public class Pony extends Living implements Copyable, Update @Override public void fromSynchronizedNbt(NbtCompound compound) { + System.out.println("fromSyncNbt"); super.fromSynchronizedNbt(compound); + setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN)); + setSuppressedRace(Race.fromName(compound.getString("suppressedSpecies"), Race.UNSET)); powers.fromNBT(compound.getCompound("powers")); gravity.fromNBT(compound.getCompound("gravity")); charms.fromNBT(compound.getCompound("charms")); @@ -877,7 +879,6 @@ public class Pony extends Living implements Copyable, Update @Override public void copyFrom(Pony oldPlayer, boolean alive) { - boolean forcedSwap = (!alive && entity instanceof ServerPlayerEntity && entity.getWorld().getGameRules().getBoolean(UGameRules.SWAP_TRIBE_ON_DEATH) @@ -885,17 +886,20 @@ public class Pony extends Living implements Copyable, Update || oldPlayer.getSpecies().isUnset(); Race oldSuppressedRace = oldPlayer.getSuppressedRace(); + Race newRace = oldPlayer.respawnRace != Race.UNSET && !alive ? oldPlayer.respawnRace : oldPlayer.getSpecies(); - if (alive) { - oldPlayer.getSpellSlot().stream().forEach(getSpellSlot()::put); + if (forcedSwap || !newRace.canCast()) { + getSpellSlot().clear(); } else { - if (forcedSwap) { - oldSuppressedRace = Race.UNSET; - Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(entity), "gui.unicopia.tribe_selection.respawn"), (ServerPlayerEntity)entity); - } else { - oldPlayer.getSpellSlot().stream().filter(SpellType.PLACE_CONTROL_SPELL).forEach(getSpellSlot()::put); - } + getSpellSlot().copyFrom(oldPlayer.getSpellSlot(), alive); + } + if (forcedSwap) { + oldSuppressedRace = Race.UNSET; + Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(entity), "gui.unicopia.tribe_selection.respawn"), (ServerPlayerEntity)entity); + } + + if (!alive) { // putting it here instead of adding another injection point into ServerPlayerEntity.copyFrom() if (!asWorld().getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) { PlayerInventory inventory = oldPlayer.asEntity().getInventory(); @@ -908,14 +912,13 @@ public class Pony extends Living implements Copyable, Update } } - setSpecies(oldPlayer.respawnRace != Race.UNSET && !alive ? oldPlayer.respawnRace : oldPlayer.getSpecies()); + setSpecies(newRace); setSuppressedRace(oldSuppressedRace); getDiscoveries().copyFrom(oldPlayer.getDiscoveries(), alive); getPhysics().copyFrom(oldPlayer.getPhysics(), alive); if (!forcedSwap) { getArmour().copyFrom(oldPlayer.getArmour(), alive); - getCharms().equipSpell(Hand.MAIN_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.MAIN_HAND)); - getCharms().equipSpell(Hand.OFF_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.OFF_HAND)); + getCharms().copyFrom(oldPlayer.getCharms(), alive); corruption.set(oldPlayer.getCorruption().get()); levels.set(oldPlayer.getLevel().get()); } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinClientPlayNetworkHandler.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinClientPlayNetworkHandler.java index e8c1179b..607c7bd9 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinClientPlayNetworkHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinClientPlayNetworkHandler.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.mixin.client; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -10,13 +12,19 @@ import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.behaviour.Disguise; import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance; +import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.network.track.Trackable; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; @Mixin(ClientPlayNetworkHandler.class) abstract class MixinClientPlayNetworkHandler { + @Shadow private @Final MinecraftClient client; @Shadow private ClientWorld world; @Inject(method = "onEntityStatus", at = @At("TAIL")) @@ -32,4 +40,20 @@ abstract class MixinClientPlayNetworkHandler { }); } } + + @Nullable + private ClientPlayerEntity oldPlayer; + + @Inject(method = "onPlayerRespawn", at = @At("HEAD")) + public void beforeOnPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo info) { + oldPlayer = client.player; + } + + @Inject(method = "onPlayerRespawn", at = @At("RETURN")) + public void afterOnPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo info) { + if (oldPlayer != null && oldPlayer != client.player) { + Trackable.of(oldPlayer).getDataTrackers().copyTo(Trackable.of(client.player).getDataTrackers()); + Pony.of(client.player).copyFrom(Pony.of(oldPlayer), true); + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java index de2ed3ef..08db3c52 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayNetworkHandler.java @@ -43,7 +43,7 @@ abstract class MixinServerPlayNetworkHandler implements EntityTrackingListener, } @Inject(method = "tick()V", at = @At("HEAD")) - private void beforePlayerTick() { + private void beforePlayerTick(CallbackInfo info) { if (Pony.of(player).getPhysics().isFlyingSurvival) { floating = false; floatingTicks = 0; diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index 1c99f1cb..bad61f3f 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -75,6 +75,17 @@ public class DataTracker { } } + @SuppressWarnings("unchecked") + synchronized void copyTo(DataTracker destination) { + for (int i = 0; i < codecs.size(); i++) { + ((Pair)destination.codecs.get(i)).value = codecs.get(i).value; + TrackableObject o = destination.persistentObjects.get(i); + if (o != null) { + o.readTrackedNbt((NbtCompound)codecs.get(i).value); + } + } + } + synchronized Optional getInitialPairs() { initial = false; dirtyIndices = new IntOpenHashSet(); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java index 3b199346..b13e9eaa 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -80,6 +80,16 @@ public class DataTrackerManager { } } + @SuppressWarnings({ "unchecked", "rawtypes" }) + public synchronized void copyTo(DataTrackerManager destination) { + for (int i = 0; i < trackers.size(); i++) { + trackers.get(i).copyTo(i >= destination.trackers.size() ? destination.checkoutTracker() : destination.trackers.get(i)); + } + for (int i = 0; i < objectTrackers.size(); i++) { + ((ObjectTracker)objectTrackers.get(i)).copyTo(destination.objectTrackers.get(i)); + } + } + @SuppressWarnings({ "rawtypes", "unchecked" }) public synchronized void sendInitial(ServerPlayerEntity player, Consumer> sender) { synchronized (this) { diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java index 6a1e6005..85554c4a 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java @@ -73,6 +73,15 @@ public class ObjectTracker implements NbtSerialisable quickAccess = Map.copyOf(trackedObjects); } + synchronized void copyTo(ObjectTracker destination) { + for (var entry : trackedObjects.entrySet()) { + T copy = destination.constructor.get(); + copy.readTrackedNbt(entry.getValue().toTrackedNbt()); + destination.trackedObjects.put(entry.getKey(), copy); + } + destination.quickAccess = Map.copyOf(destination.trackedObjects); + } + synchronized Optional getInitialPairs() { if (trackedObjects.isEmpty()) { return Optional.empty(); From 7937604c41e870453bba0f36ee949ccd896fb883 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 21:01:33 +0100 Subject: [PATCH 61/85] Fixed placed spells not reflecting their correct location in the dismiss spell screen --- .../magic/spell/PlacementControlSpell.java | 4 +-- .../client/gui/DismissSpellScreen.java | 31 ++++++++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java index a42cd9a3..f486c0d4 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java @@ -139,8 +139,8 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel super.fromNBT(compound); delegate = Spell.readNbt(compound.getCompound("spell")); placedEntityId = compound.containsUuid("placedEntityId") ? compound.getUuid("placedEntityId") : null; - position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.FLOAT_TYPE))) : Optional.empty(); - orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.FLOAT_TYPE))) : Optional.empty(); + position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.DOUBLE_TYPE))) : Optional.empty(); + orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.DOUBLE_TYPE))) : Optional.empty(); if (compound.contains("dimension", NbtElement.STRING_TYPE)) { dimension = Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id)); } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index bad720d8..d73091c0 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -57,15 +57,16 @@ public class DismissSpellScreen extends GameGui { } double minimalDistance = 75 * (ring - 1) - 25; - Vec3d origin = pony.getOriginVector(); + Vec3d origin = pony.asEntity().getPos(); placeableSpells.forEach(placeable -> { placeable.getPosition().ifPresent(position -> { - Vec3d relativePos = position.subtract(origin); + Vec3d relativePos = position.subtract(origin).multiply(1, 0, 1); + float yaw = client.gameRenderer.getCamera().getYaw(); Vec3d cartesian = relativePos .normalize() - .multiply(minimalDistance + relativePos.length()) - .rotateY((pony.asEntity().getYaw() - 180) * MathHelper.RADIANS_PER_DEGREE); + .multiply(minimalDistance + relativePos.horizontalLength()) + .rotateY((180 + yaw) * MathHelper.RADIANS_PER_DEGREE); addDrawableChild(new Entry(placeable).ofCartesian(cartesian)); }); }); @@ -167,20 +168,28 @@ public class DismissSpellScreen extends GameGui { copy.set(mouseX - width * 0.5F - x * 0.5F, mouseY - height * 0.5F - y * 0.5F, 0, 0); DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, actualSpell.getAffinity().getColor().getColorValue()); - DrawableUtil.renderItemIcon(context, actualSpell.isDead() ? UItems.BOTCHED_GEM.getDefaultStack() : type.getDefaultStack(), - x - 8 - copy.x * 0.2F, - y - 8 - copy.y * 0.2F, - 1 - ); + int color = type.type().getColor() << 2; matrices.push(); matrices.translate(x, y, 0); - DrawableUtil.drawArc(matrices, 7, 8, 0, DrawableUtil.TAU, color | 0x00000088, false); + matrices.push(); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(((MinecraftClient.getInstance().player.age + tickDelta) * 2) % 360)); + DrawableUtil.renderItemIcon(context, actualSpell.isDead() ? UItems.BOTCHED_GEM.getDefaultStack() : type.getDefaultStack(), + -8, + -8, + 1 + ); + matrices.pop(); - if (isMouseOver(relativeMouseX, relativeMouseY)) { + boolean hovered = isMouseOver(relativeMouseX, relativeMouseY); + double radius = (hovered ? 9 + MathHelper.sin((MinecraftClient.getInstance().player.age + tickDelta) / 9F) : 7); + + DrawableUtil.drawArc(matrices, radius, radius + 1, 0, DrawableUtil.TAU, color | 0x00000088, false); + + if (hovered) { DrawableUtil.drawArc(matrices, 0, 8, 0, DrawableUtil.TAU, color | 0x000000FF, false); List tooltip = new ArrayList<>(); From d716d2e00bcee363128a4df0d4b1170227e6eb88 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 25 May 2024 21:08:38 +0100 Subject: [PATCH 62/85] Move wind trail particles behind the player's view --- .../minelittlepony/unicopia/client/particle/WindParticle.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/WindParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/WindParticle.java index 245c2b06..38700671 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/WindParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/WindParticle.java @@ -89,7 +89,8 @@ public class WindParticle extends AbstractBillboardParticle { trail.update(new Vec3d(x + cos, y + sin, z - cos)); } else { if (target != null && target.isAlive()) { - trail.update(target.getPos().add(offset).add(cos, sin, -cos)); + + trail.update(target.getPos().add(target.getRotationVecClient().multiply(-7)).add(offset).add(cos, sin, -cos)); if (attachmentTicks > 0 && --attachmentTicks <= 0) { target = null; From 2edf2c69890aeb8df9c4471aa00c1ba818439583 Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 27 May 2024 06:39:01 +0100 Subject: [PATCH 63/85] Implement data trackers for spells --- .../ability/magic/MultiSpellSlot.java | 98 ++++++++++++----- .../ability/magic/SingleSpellSlot.java | 4 +- .../magic/spell/AbstractDelegatingSpell.java | 37 +++---- .../magic/spell/DispersableDisguiseSpell.java | 12 ++- .../ability/magic/spell/EmptySpell.java | 6 ++ .../magic/spell/PlacementControlSpell.java | 8 +- .../ability/magic/spell/RageAbilitySpell.java | 4 - .../unicopia/ability/magic/spell/Spell.java | 19 ++-- .../ability/magic/spell/SpellReference.java | 15 +-- .../ability/magic/spell/ThrowableSpell.java | 6 +- .../magic/spell/effect/AbstractSpell.java | 49 +++++---- .../magic/spell/effect/AttractiveSpell.java | 3 +- .../magic/spell/effect/AwkwardSpell.java | 2 - .../magic/spell/effect/BubbleSpell.java | 35 +++--- .../magic/spell/effect/DarkVortexSpell.java | 20 ++-- .../magic/spell/effect/FeatherFallSpell.java | 2 - .../magic/spell/effect/LightSpell.java | 3 - .../magic/spell/effect/MimicSpell.java | 2 - .../magic/spell/effect/MindSwapSpell.java | 9 +- .../magic/spell/effect/NecromancySpell.java | 2 - .../magic/spell/effect/PortalSpell.java | 101 +++++++++--------- .../magic/spell/effect/SiphoningSpell.java | 12 ++- .../ability/magic/spell/effect/SpellType.java | 2 +- .../unicopia/entity/EntityReference.java | 17 +-- .../entity/player/CorruptionHandler.java | 3 - .../unicopia/network/track/DataTracker.java | 84 +++++++-------- .../network/track/DataTrackerManager.java | 4 +- .../network/track/MsgTrackedValues.java | 17 +-- .../unicopia/network/track/ObjectTracker.java | 73 +++++-------- .../network/track/TrackableDataType.java | 1 + .../network/track/TrackableObject.java | 29 +++-- .../unicopia/server/world/Ether.java | 2 +- .../unicopia/util/NbtSerialisable.java | 27 ++++- 33 files changed, 383 insertions(+), 325 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java index 21d5c7a2..e38184b7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java @@ -1,18 +1,25 @@ package com.minelittlepony.unicopia.ability.magic; +import java.util.Optional; import java.util.UUID; import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; +import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.SpellReference; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.network.track.MsgTrackedValues; import com.minelittlepony.unicopia.network.track.ObjectTracker; import com.minelittlepony.unicopia.network.track.Trackable; import com.minelittlepony.unicopia.network.track.TrackableObject; import com.minelittlepony.unicopia.util.NbtSerialisable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; + +import io.netty.buffer.Unpooled; import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.PacketByteBuf; /** * Container for multiple spells @@ -21,7 +28,7 @@ import net.minecraft.nbt.NbtCompound; */ class MultiSpellSlot implements SpellSlots, NbtSerialisable { private final Caster owner; - private final ObjectTracker> tracker; + private final ObjectTracker> tracker; public MultiSpellSlot(Caster owner) { this.owner = owner; @@ -41,7 +48,7 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable { @Override public void put(@Nullable Spell effect) { if (effect != null) { - tracker.add(new Entry<>(owner, effect)); + tracker.add(effect.getUuid(), new Entry<>(owner, effect)); } } @@ -62,18 +69,32 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable { @Override public void toNBT(NbtCompound compound) { - compound.put("spells", tracker.toNBT()); + compound.put("spells", NbtSerialisable.writeMap(tracker.entries(), UUID::toString, entry -> entry.spell.toNBT())); } @Override public void fromNBT(NbtCompound compound) { - tracker.fromNBT(compound.getCompound("spells")); + tracker.load(NbtSerialisable.readMap(compound.getCompound("spells"), key -> { + try { + return UUID.fromString(key); + } catch (Throwable ignore) {} + return null; + }, (key, nbt) -> { + try { + Entry entry = new Entry<>(owner); + entry.spell.fromNBT((NbtCompound)nbt); + return entry; + } catch (Throwable t) { + Unicopia.LOGGER.warn("Exception loading tracked object: {}", t.getMessage()); + } + return null; + })); } - static final class Entry implements TrackableObject { + static final class Entry implements TrackableObject> { private final Caster owner; final SpellReference spell = new SpellReference<>(); - private Status status = Status.NEW; + private boolean hasValue; public Entry(Caster owner) { this.owner = owner; @@ -99,34 +120,63 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable { } } - @Override - public UUID getUuid() { - return spell.get().getUuid(); - } - @Override public Status getStatus() { - try { - if (spell.get() == null) { - return Status.REMOVED; - } - if (spell.hasDirtySpell()) { - return Status.UPDATED; - } - return status; - } finally { - status = Status.DEFAULT; + boolean hasValue = spell.get() != null; + if (hasValue != this.hasValue) { + this.hasValue = hasValue; + return hasValue ? Status.NEW : Status.REMOVED; } + + return spell.hasDirtySpell() ? Status.UPDATED : Status.DEFAULT; } @Override - public NbtCompound toTrackedNbt() { + public void readTrackedNbt(NbtCompound nbt) { + spell.fromNBT(nbt); + } + + @Override + public NbtCompound writeTrackedNbt() { return spell.toNBT(); } @Override - public void readTrackedNbt(NbtCompound compound) { - spell.fromNBT(compound); + public void read(PacketByteBuf buffer) { + byte contentType = buffer.readByte(); + if (contentType == 1) { + readTrackedNbt(PacketCodec.COMPRESSED_NBT.read(buffer)); + } else { + T spell = this.spell.get(); + if (spell != null) { + spell.getDataTracker().load(new MsgTrackedValues.TrackerEntries(buffer)); + } + } + } + + @Override + public Optional write(Status status) { + if (status != Status.DEFAULT) { + PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()); + buffer.writeByte(1); + PacketCodec.COMPRESSED_NBT.write(buffer, spell.toNBT()); + return Optional.of(buffer); + } + @Nullable T spell = this.spell.get(); + if (spell == null) { + return Optional.empty(); + } + return spell.getDataTracker().getDirtyPairs().map(entries -> { + PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()); + buffer.writeByte(0); + entries.write(buffer); + return buffer; + }); + } + + @Override + public void copyTo(Entry destination) { + destination.spell.set(spell.get()); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java index 73a1c6f2..94d6c664 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SingleSpellSlot.java @@ -58,12 +58,12 @@ class SingleSpellSlot implements SpellSlots, NbtSerialisable { @Override public void toNBT(NbtCompound compound) { - compound.put("effect", entry.toTrackedNbt()); + compound.put("effect", entry.spell.toNBT()); } @Override public void fromNBT(NbtCompound compound) { - entry.readTrackedNbt(compound.getCompound("effect")); + entry.spell.fromNBT(compound.getCompound("effect")); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index ffd032c7..78373b5a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -7,15 +7,12 @@ import com.google.common.base.MoreObjects; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.server.world.Ether; import net.minecraft.nbt.NbtCompound; public abstract class AbstractDelegatingSpell implements Spell { - private boolean dirty; - private boolean hidden; - private boolean destroyed; - private UUID uuid = UUID.randomUUID(); private final CustomisedSpellType type; @@ -25,10 +22,20 @@ public abstract class AbstractDelegatingSpell implements Spell { this.type = type; } + public AbstractDelegatingSpell(CustomisedSpellType type, Spell delegate) { + this.type = type; + this.delegate.set(delegate); + } + public final Spell getDelegate() { return delegate.get(); } + @Override + public final DataTracker getDataTracker() { + return getOrEmpty().getDataTracker(); + } + private Spell getOrEmpty() { return MoreObjects.firstNonNull(delegate.get(), EmptySpell.INSTANCE); } @@ -73,19 +80,21 @@ public abstract class AbstractDelegatingSpell implements Spell { return getOrEmpty().isDying(); } + @Deprecated @Override public boolean isDirty() { - return dirty || delegate.hasDirtySpell(); + return delegate.hasDirtySpell(); } + @Deprecated @Override public void setDirty() { - dirty = true; + getOrEmpty().setDirty(); } @Override public boolean isHidden() { - return hidden || getOrEmpty().isHidden(); + return getOrEmpty().isHidden(); } @Override @@ -95,15 +104,6 @@ public abstract class AbstractDelegatingSpell implements Spell { @Override public final void destroy(Caster caster) { - if (destroyed) { - return; - } - destroyed = true; - setDead(); - onDestroyed(caster); - } - - protected void onDestroyed(Caster caster) { if (!caster.isClient()) { Ether.get(caster.asWorld()).remove(this, caster); } @@ -123,14 +123,11 @@ public abstract class AbstractDelegatingSpell implements Spell { @Override public void toNBT(NbtCompound compound) { compound.putUuid("uuid", uuid); - compound.putBoolean("hidden", hidden); compound.put("spell", delegate.toNBT()); } @Override public void fromNBT(NbtCompound compound) { - dirty = false; - hidden = compound.getBoolean("hidden"); if (compound.contains("uuid")) { uuid = compound.getUuid("uuid"); } @@ -139,6 +136,6 @@ public abstract class AbstractDelegatingSpell implements Spell { @Override public final String toString() { - return "Delegate{" + getTypeAndTraits() + "}[uuid=" + uuid + ", destroyed=" + destroyed + ", hidden=" + hidden + "][spell=" + delegate.get() + "]"; + return "Delegate{" + getTypeAndTraits() + "}[uuid=" + uuid + "][spell=" + delegate.get() + "]"; } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java index d659cc90..7f614bc6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java @@ -9,6 +9,8 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellTyp import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.UParticles; import net.minecraft.entity.Entity; @@ -21,6 +23,7 @@ import net.minecraft.nbt.NbtCompound; */ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements IllusionarySpell { + private final DataTracker.Entry suppressed = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private int suppressionCounter; public DispersableDisguiseSpell(CustomisedSpellType type) { @@ -37,7 +40,7 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I public void onSuppressed(Caster otherSource, float time) { time /= getTraits().getOrDefault(Trait.STRENGTH, 1); suppressionCounter = (int)time; - setDirty(); + suppressed.set(true); } @Override @@ -64,7 +67,9 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I Entity appearance = getDisguise().getAppearance(); if (isSuppressed()) { - suppressionCounter--; + if (--suppressionCounter <= 0) { + suppressed.set(false); + } owner.setInvisible(false); if (source instanceof Pony) { @@ -92,6 +97,9 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I public void fromNBT(NbtCompound compound) { super.fromNBT(compound); suppressionCounter = compound.getInt("suppressionCounter"); + if (suppressionCounter > 0) { + suppressed.set(true); + } } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java index 202c3830..89b3f986 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java @@ -5,6 +5,7 @@ import java.util.UUID; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.network.track.DataTracker; import net.minecraft.nbt.NbtCompound; import net.minecraft.util.Util; @@ -74,4 +75,9 @@ public final class EmptySpell implements Spell { public String toString() { return "EmptySpell{}"; } + + @Override + public DataTracker getDataTracker() { + return null; + } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java index f486c0d4..9eee830f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.NbtSerialisable; @@ -34,8 +35,8 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel super(type); } - PlacementControlSpell(CustomisedSpellType type, Spell delegate) { - this(type); + PlacementControlSpell(Spell delegate) { + this(SpellType.PLACE_CONTROL_SPELL.withTraits(delegate.getTypeAndTraits().traits())); this.delegate = delegate; } @@ -50,10 +51,12 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel public void setDimension(RegistryKey dimension) { this.dimension = Optional.of(dimension); + setDirty(); } public void setPosition(Vec3d position) { this.position = Optional.of(position); + setDirty(); } @Override @@ -98,7 +101,6 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel entity.getWorld().spawnEntity(entity); placedEntityId = entity.getUuid(); - setDirty(); } return result; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RageAbilitySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RageAbilitySpell.java index 62ef6a43..dbf98cf2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RageAbilitySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RageAbilitySpell.java @@ -54,7 +54,6 @@ public class RageAbilitySpell extends AbstractSpell { ticksExtenguishing++; source.playSound(USounds.Vanilla.ENTITY_GENERIC_EXTINGUISH_FIRE, 1); source.spawnParticles(ParticleTypes.CLOUD, 12); - setDirty(); } else { ticksExtenguishing = 0; } @@ -127,9 +126,6 @@ public class RageAbilitySpell extends AbstractSpell { age++; source.asEntity().setInvulnerable(age < 25); - - - setDirty(); return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index 92f44adf..aab10703 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.NbtSerialisable; @@ -30,6 +31,8 @@ public interface Spell extends NbtSerialisable, Affine { */ CustomisedSpellType getTypeAndTraits(); + DataTracker getDataTracker(); + default boolean isOf(SpellType type) { return getTypeAndTraits().type() == type; } @@ -74,8 +77,15 @@ public interface Spell extends NbtSerialisable, Affine { /** * Returns true if this effect has changes that need to be sent to the client. */ + @Deprecated boolean isDirty(); + /** + * Marks this effect as dirty. + */ + @Deprecated + void setDirty(); + /** * Applies this spell to the supplied caster. * @param caster The caster to apply the spell to @@ -110,11 +120,6 @@ public interface Spell extends NbtSerialisable, Affine { */ void tickDying(Caster caster); - /** - * Marks this effect as dirty. - */ - void setDirty(); - boolean isHidden(); void setHidden(boolean hidden); @@ -128,7 +133,7 @@ public interface Spell extends NbtSerialisable, Affine { * Converts this spell into a placeable spell. */ default PlacementControlSpell toPlaceable() { - return new PlacementControlSpell(SpellType.PLACE_CONTROL_SPELL.withTraits(), this); + return new PlacementControlSpell(this); } /** @@ -136,7 +141,7 @@ public interface Spell extends NbtSerialisable, Affine { * @return */ default ThrowableSpell toThrowable() { - return SpellType.THROWN_SPELL.withTraits().create().setSpell(this); + return new ThrowableSpell(this); } @Nullable diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java index 6c3d22e9..4bab564c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java @@ -15,7 +15,6 @@ import net.minecraft.nbt.NbtCompound; public final class SpellReference implements NbtSerialisable { @Nullable private transient T spell; - private int nbtHash; @Nullable public T get() { @@ -26,6 +25,7 @@ public final class SpellReference implements NbtSerialisable { set(spell, null); } + @Deprecated public boolean hasDirtySpell() { return spell != null && spell.isDirty(); } @@ -37,7 +37,6 @@ public final class SpellReference implements NbtSerialisable { } T oldValue = this.spell; this.spell = spell; - nbtHash = 0; if (owner != null && oldValue != null && (spell == null || !oldValue.getUuid().equals(spell.getUuid()))) { oldValue.destroy(owner); } @@ -65,19 +64,9 @@ public final class SpellReference implements NbtSerialisable { @Override public void fromNBT(NbtCompound compound) { - fromNBT(compound, true); - } - - public void fromNBT(NbtCompound compound, boolean force) { - final int hash = compound.hashCode(); - if (nbtHash == hash) { - return; - } - nbtHash = hash; - if (spell == null || !Objects.equals(Spell.getUuid(compound), spell.getUuid())) { spell = Spell.readNbt(compound); - } else if (force || !spell.isDirty()) { + } else { spell.fromNBT(compound); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java index b823cf6f..d722147d 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java @@ -5,6 +5,7 @@ import java.util.Optional; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.projectile.MagicBeamEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; @@ -20,9 +21,8 @@ public final class ThrowableSpell extends AbstractDelegatingSpell implements super(type); } - public ThrowableSpell setSpell(Spell spell) { - delegate.set(spell); - return this; + public ThrowableSpell(Spell delegate) { + super(SpellType.THROWN_SPELL.withTraits(delegate.getTypeAndTraits().traits()), delegate); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java index f7cef06d..6d08d6a9 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java @@ -5,26 +5,34 @@ import java.util.UUID; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.server.world.Ether; import net.minecraft.nbt.NbtCompound; public abstract class AbstractSpell implements Spell { - private boolean dead; - private boolean dying; - private boolean dirty; - private boolean hidden; - private boolean destroyed; - + private UUID uuid = UUID.randomUUID(); private final CustomisedSpellType type; - private UUID uuid = UUID.randomUUID(); + protected final DataTracker dataTracker = new DataTracker(0); + + private final DataTracker.Entry dead = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); + private final DataTracker.Entry dying = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); + private boolean dirty; + private final DataTracker.Entry hidden = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); + private boolean destroyed; protected AbstractSpell(CustomisedSpellType type) { this.type = type; } + @Override + public final DataTracker getDataTracker() { + return dataTracker; + } + @Override public final UUID getUuid() { return uuid; @@ -45,25 +53,26 @@ public abstract class AbstractSpell implements Spell { @Override public final void setDead() { - dying = true; - setDirty(); + dying.set(true); } @Override public final boolean isDead() { - return dead; + return dead.get(); } @Override public final boolean isDying() { - return dying; + return dying.get(); } + @Deprecated @Override public final boolean isDirty() { return dirty; } + @Deprecated @Override public final void setDirty() { dirty = true; @@ -71,17 +80,17 @@ public abstract class AbstractSpell implements Spell { @Override public final boolean isHidden() { - return hidden; + return hidden.get(); } @Override public final void setHidden(boolean hidden) { - this.hidden = hidden; + this.hidden.set(hidden); } @Override public void tickDying(Caster caster) { - dead = true; + dead.set(true); } @Override @@ -102,9 +111,9 @@ public abstract class AbstractSpell implements Spell { @Override public void toNBT(NbtCompound compound) { - compound.putBoolean("dying", dying); - compound.putBoolean("dead", dead); - compound.putBoolean("hidden", hidden); + compound.putBoolean("dying", dying.get()); + compound.putBoolean("dead", dead.get()); + compound.putBoolean("hidden", hidden.get()); compound.putUuid("uuid", uuid); compound.put("traits", getTraits().toNbt()); } @@ -115,9 +124,9 @@ public abstract class AbstractSpell implements Spell { if (compound.containsUuid("uuid")) { uuid = compound.getUuid("uuid"); } - dying = compound.getBoolean("dying"); - dead = compound.getBoolean("dead"); - hidden = compound.getBoolean("hidden"); + dying.set(compound.getBoolean("dying")); + dead.set(compound.getBoolean("dead")); + hidden.set(compound.getBoolean("hidden")); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java index c951cb9f..04a0185d 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java @@ -42,6 +42,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp protected AttractiveSpell(CustomisedSpellType type) { super(type); timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); + dataTracker.startTracking(target); } @Override @@ -57,8 +58,6 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp if (timer.getTicksRemaining() <= 0) { return false; } - - setDirty(); } target.getOrEmpty(caster.asWorld()) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java index 964fe1d4..dab51b1b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java @@ -40,8 +40,6 @@ public class AwkwardSpell extends AbstractSpell implements TimedSpell { if (timer.getTicksRemaining() <= 0) { return false; } - - setDirty(); } if (source.isClient()) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index 925a8c5a..bd24dfae 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -12,6 +12,8 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; @@ -55,15 +57,15 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, private final Timer timer; - private int struggles; - private float prevRadius; - private float radius; + private DataTracker.Entry radius; + private DataTracker.Entry struggles; protected BubbleSpell(CustomisedSpellType type) { super(type); timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); - struggles = (int)(getTraits().get(Trait.POWER) * 2); + radius = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); + struggles = dataTracker.startTracking(TrackableDataType.INT, (int)(getTraits().get(Trait.POWER) * 2)); } @Override @@ -72,7 +74,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, } public float getRadius(float tickDelta) { - return MathHelper.lerp(tickDelta, prevRadius, radius); + return MathHelper.lerp(tickDelta, prevRadius, radius.get()); } @Override @@ -91,7 +93,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, } }); } - radius = Math.max(entity.getHeight(), entity.getWidth()) * 1.2F; + radius.set(Math.max(entity.getHeight(), entity.getWidth()) * 1.2F); source.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1); entity.addVelocity(0, 0.2F * source.getPhysics().getGravitySignum(), 0); Living.updateVelocity(entity); @@ -111,7 +113,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, boolean done = timer.getTicksRemaining() <= 0; - source.spawnParticles(source.getOriginVector().add(0, 1, 0), new Sphere(true, radius * (done ? 0.25F : 0.5F)), done ? 13 : 1, pos -> { + source.spawnParticles(source.getOriginVector().add(0, 1, 0), new Sphere(true, radius.get() * (done ? 0.25F : 0.5F)), done ? 13 : 1, pos -> { source.addParticle(done ? ParticleTypes.BUBBLE_POP : UParticles.BUBBLE, pos, Vec3d.ZERO); }); @@ -119,8 +121,6 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, return false; } - setDirty(); - source.asEntity().addVelocity( MathHelper.sin(source.asEntity().age / 6F) / 50F, MathHelper.sin(source.asEntity().age / 6F) / 50F, @@ -129,13 +129,14 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, source.asEntity().fallDistance = 0; - prevRadius = radius; + prevRadius = radius.get(); if (source instanceof Pony pony && pony.sneakingChanged() && pony.asEntity().isSneaking()) { - setDirty(); - radius += 0.5F; + radius.set(radius.get() + 0.5F); source.playSound(USounds.SPELL_BUBBLE_DISTURB, 1); - if (struggles-- <= 0) { + int s = struggles.get() - 1; + struggles.set(s); + if (s <= 0) { setDead(); return false; } @@ -168,16 +169,16 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - compound.putInt("struggles", struggles); - compound.putFloat("radius", radius); + compound.putInt("struggles", struggles.get()); + compound.putFloat("radius", radius.get()); timer.toNBT(compound); } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); - struggles = compound.getInt("struggles"); - radius = compound.getFloat("radius"); + struggles.set(compound.getInt("struggles")); + radius.set(compound.getFloat("radius")); timer.fromNBT(compound); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java index e46941c0..14eaa665 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java @@ -17,6 +17,8 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; @@ -56,7 +58,7 @@ public class DarkVortexSpell extends AbstractSpell implements ProjectileDelegate .with(Trait.DARKNESS, 100) .build(); - private float accumulatedMass = 0; + private final DataTracker.Entry accumulatedMass = this.dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private final TargetSelecter targetSelecter = new TargetSelecter(this).setFilter(this::isValidTarget).setTargetowner(true).setTargetAllies(true); @@ -70,7 +72,7 @@ public class DarkVortexSpell extends AbstractSpell implements ProjectileDelegate // 3. force reaches 0 at distance of drawDropOffRange private double getMass() { - return 0.1F + accumulatedMass / 10F; + return 0.1F + accumulatedMass.get() / 10F; } public double getEventHorizonRadius() { @@ -174,11 +176,12 @@ public class DarkVortexSpell extends AbstractSpell implements ProjectileDelegate @Override public void tickDying(Caster source) { - accumulatedMass -= 0.8F; + float m = accumulatedMass.get() - 0.8F; + accumulatedMass.set(m); double mass = getMass() * 0.1; double logarithm = 1 - (1D / (1 + (mass * mass))); radius.update((float)Math.max(0.1, logarithm * source.asWorld().getGameRules().getInt(UGameRules.MAX_DARK_VORTEX_SIZE)), 200L); - if (accumulatedMass < 1) { + if (m < 1) { super.tickDying(source); } @@ -202,7 +205,7 @@ public class DarkVortexSpell extends AbstractSpell implements ProjectileDelegate @Override public boolean isFriendlyTogether(Affine other) { - return accumulatedMass < 4; + return accumulatedMass.get() < 4; } private boolean isValidTarget(Caster source, Entity entity) { @@ -274,8 +277,7 @@ public class DarkVortexSpell extends AbstractSpell implements ProjectileDelegate double massOfTarget = AttractionUtils.getMass(target); if (!source.isClient() && massOfTarget != 0) { - accumulatedMass += massOfTarget; - setDirty(); + accumulatedMass.set((float)(accumulatedMass.get() + massOfTarget)); } target.damage(source.damageOf(UDamageTypes.GAVITY_WELL_RECOIL, source), Integer.MAX_VALUE); @@ -303,12 +305,12 @@ public class DarkVortexSpell extends AbstractSpell implements ProjectileDelegate @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - compound.putFloat("accumulatedMass", accumulatedMass); + compound.putFloat("accumulatedMass", accumulatedMass.get()); } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); - accumulatedMass = compound.getFloat("accumulatedMass"); + accumulatedMass.set(compound.getFloat("accumulatedMass")); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java index eb2bc744..59491f8f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java @@ -69,8 +69,6 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { return false; } - setDirty(); - List targets = getTargets(caster).toList(); if (targets.isEmpty()) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java index 48c99c0c..6825df24 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java @@ -63,8 +63,6 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD return false; } - setDirty(); - if (!caster.isClient()) { if (lights.isEmpty()) { int size = 2 + caster.asWorld().random.nextInt(2) + (int)(getTraits().get(Trait.LIFE, 10, 20) - 10)/10; @@ -83,7 +81,6 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD entity.getWorld().spawnEntity(entity); ref.set(entity); - setDirty(); } }); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java index 12032913..0e599e8d 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java @@ -35,8 +35,6 @@ public class MimicSpell extends AbstractDisguiseSpell implements HomingSpell, Ti return false; } - setDirty(); - return super.tick(caster, situation); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java index ed55f91b..eefb6ebb 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java @@ -135,7 +135,6 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti caster.playSound(USounds.SPELL_MINDSWAP_SWAP, 1); }); initialized = true; - setDirty(); } if (counterpart.isSet()) { @@ -143,13 +142,12 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti if (other == null) { caster.getOriginatingCaster().asEntity().damage(caster.asWorld().getDamageSources().magic(), Float.MAX_VALUE); - setDead(); + destroy(caster); return false; } if (!Caster.of(other).get().getSpellSlot().contains(SpellType.MIMIC)) { - onDestroyed(caster); - setDead(); + destroy(caster); return false; } } @@ -158,8 +156,7 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti counterpart.ifPresent(caster.asWorld(), e -> { e.damage(e.getDamageSources().magic(), Float.MAX_VALUE); }); - onDestroyed(caster); - setDead(); + destroy(caster); return false; } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java index b1209943..c2063211 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java @@ -131,7 +131,6 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti float additional = source.asWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty() + getTraits().get(Trait.CHAOS, 0, 10); - setDirty(); if (--spawnCountdown > 0 && !summonedEntities.isEmpty()) { return true; } @@ -213,7 +212,6 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti source.asWorld().spawnEntity(minion); summonedEntities.add(new EntityReference<>(minion)); - setDirty(); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java index 8a012993..4277ff0c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java @@ -14,6 +14,8 @@ import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.MsgCasterLookRequest; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.particle.*; import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.shape.*; @@ -26,6 +28,7 @@ import net.minecraft.network.packet.s2c.play.PositionFlag; import net.minecraft.particle.ParticleTypes; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Util; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -40,15 +43,13 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. private static final Shape PARTICLE_AREA = new Sphere(true, 2, 1, 1, 0); @Nullable - private UUID targetPortalId; - private float targetPortalPitch; - private float targetPortalYaw; + private final DataTracker.Entry targetPortalId = dataTracker.startTracking(TrackableDataType.UUID, Util.NIL_UUID); + private final DataTracker.Entry targetPortalPitch = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); + private final DataTracker.Entry targetPortalYaw = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private final EntityReference teleportationTarget = new EntityReference<>(); - private boolean publishedPosition; - - private float pitch; - private float yaw; + private final DataTracker.Entry pitch = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); + private final DataTracker.Entry yaw = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private Shape particleArea = PARTICLE_AREA; @@ -61,30 +62,30 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. } public float getPitch() { - return pitch; + return pitch.get(); } public float getYaw() { - return yaw; + return yaw.get(); } public float getTargetPitch() { - return targetPortalPitch; + return targetPortalPitch.get(); } public float getTargetYaw() { - return targetPortalYaw; + return targetPortalYaw.get(); } public float getYawDifference() { - return MathHelper.wrapDegrees(180 + targetPortalYaw - yaw); + return MathHelper.wrapDegrees(180 + getTargetYaw() - getYaw()); } @SuppressWarnings("unchecked") private Ether.Entry getDestination(Caster source) { - return targetPortalId == null ? null : getDestinationReference() + return Util.NIL_UUID.equals(targetPortalId.get()) ? null : getDestinationReference() .getTarget() - .map(target -> Ether.get(source.asWorld()).get((SpellType)getType(), target.uuid(), targetPortalId)) + .map(target -> Ether.get(source.asWorld()).get((SpellType)getType(), target.uuid(), targetPortalId.get())) .filter(destination -> destination.isClaimedBy(getUuid())) .orElse(null); } @@ -94,6 +95,18 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. return toPlaceable().apply(caster); } + protected void setDestination(@Nullable Ether.Entry destination) { + if (destination == null) { + teleportationTarget.set(null); + targetPortalId.set(Util.NIL_UUID); + } else { + teleportationTarget.copyFrom(destination.entity); + targetPortalId.set(destination.getSpellId()); + targetPortalPitch.set(destination.getPitch()); + targetPortalYaw.set(destination.getYaw()); + } + } + @Override public boolean tick(Caster source, Situation situation) { if (situation == Situation.GROUND) { @@ -108,9 +121,7 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. if (targetEntry == null) { if (teleportationTarget.isSet()) { - teleportationTarget.set(null); - targetPortalId = null; - setDirty(); + setDestination(null); source.asWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, source.getOrigin(), Block.getRawIdFromState(Blocks.GLASS.getDefaultState())); } else { Ether.get(source.asWorld()).anyMatch(getType(), entry -> { @@ -119,18 +130,10 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. ownEntry.claim(entry.getSpellId()); synchronized (entry) { if (entry.getSpell() instanceof PortalSpell portal) { - portal.teleportationTarget.copyFrom(ownEntry.entity); - portal.targetPortalId = getUuid(); - portal.targetPortalPitch = pitch; - portal.targetPortalYaw = yaw; - portal.setDirty(); + portal.setDestination(ownEntry); } } - teleportationTarget.copyFrom(entry.entity); - targetPortalId = entry.getSpellId(); - targetPortalPitch = entry.getPitch(); - targetPortalYaw = entry.getYaw(); - setDirty(); + setDestination(entry); } return false; }); @@ -142,8 +145,8 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. } var entry = Ether.get(source.asWorld()).getOrCreate(this, source); - entry.setPitch(pitch); - entry.setYaw(yaw); + entry.setPitch(pitch.get()); + entry.setYaw(yaw.get()); } return !isDead(); @@ -154,7 +157,7 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. source.findAllEntitiesInRange(1).forEach(entity -> { if (!entity.hasPortalCooldown()) { - float approachYaw = Math.abs(MathHelper.wrapDegrees(entity.getYaw() - this.yaw)); + float approachYaw = Math.abs(MathHelper.wrapDegrees(entity.getYaw() - this.yaw.get())); if (approachYaw > 80) { return; } @@ -177,7 +180,6 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. entity.getWorld().playSoundFromEntity(null, entity, USounds.ENTITY_PLAYER_UNICORN_TELEPORT, entity.getSoundCategory(), 1, 1); entity.teleport((ServerWorld)entity.getWorld(), dest.x, dest.y, dest.z, PositionFlag.VALUES, yaw, entity.getPitch()); entity.getWorld().playSoundFromEntity(null, entity, USounds.ENTITY_PLAYER_UNICORN_TELEPORT, entity.getSoundCategory(), 1, 1); - setDirty(); Living.updateVelocity(entity); @@ -193,13 +195,12 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. @Override public void setOrientation(Caster caster, float pitch, float yaw) { - this.pitch = 90 - pitch; - this.yaw = -yaw; + this.pitch.set(90 - pitch); + this.yaw.set(-yaw); particleArea = PARTICLE_AREA.rotate( - this.pitch * MathHelper.RADIANS_PER_DEGREE, - this.yaw * MathHelper.RADIANS_PER_DEGREE + this.pitch.get() * MathHelper.RADIANS_PER_DEGREE, + (180 - this.yaw.get()) * MathHelper.RADIANS_PER_DEGREE ); - setDirty(); } @Override @@ -227,30 +228,26 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - if (targetPortalId != null) { - compound.putUuid("targetPortalId", targetPortalId); - } - compound.putBoolean("publishedPosition", publishedPosition); + compound.putUuid("targetPortalId", targetPortalId.get()); compound.put("teleportationTarget", teleportationTarget.toNBT()); - compound.putFloat("pitch", pitch); - compound.putFloat("yaw", yaw); - compound.putFloat("targetPortalPitch", targetPortalPitch); - compound.putFloat("targetPortalYaw", targetPortalYaw); + compound.putFloat("pitch", getPitch()); + compound.putFloat("yaw", getYaw()); + compound.putFloat("targetPortalPitch", getTargetPitch()); + compound.putFloat("targetPortalYaw", getTargetYaw()); } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); - targetPortalId = compound.containsUuid("targetPortalId") ? compound.getUuid("targetPortalId") : null; - publishedPosition = compound.getBoolean("publishedPosition"); + targetPortalId.set(compound.containsUuid("targetPortalId") ? compound.getUuid("targetPortalId") : Util.NIL_UUID); teleportationTarget.fromNBT(compound.getCompound("teleportationTarget")); - pitch = compound.getFloat("pitch"); - yaw = compound.getFloat("yaw"); - targetPortalPitch = compound.getFloat("targetPortalPitch"); - targetPortalYaw = compound.getFloat("targetPortalYaw"); + pitch.set(compound.getFloat("pitch")); + yaw.set(compound.getFloat("yaw")); + targetPortalPitch.set(compound.getFloat("targetPortalPitch")); + targetPortalYaw.set(compound.getFloat("targetPortalYaw")); particleArea = PARTICLE_AREA.rotate( - pitch * MathHelper.RADIANS_PER_DEGREE, - (180 - yaw) * MathHelper.RADIANS_PER_DEGREE + pitch.get() * MathHelper.RADIANS_PER_DEGREE, + (180 - yaw.get()) * MathHelper.RADIANS_PER_DEGREE ); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java index 42e784d1..a7e1cbfd 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java @@ -16,6 +16,8 @@ import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.UParticles; @@ -43,6 +45,7 @@ public class SiphoningSpell extends AbstractAreaEffectSpell { tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4)); } + private final DataTracker.Entry upset = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private int ticksUpset; protected SiphoningSpell(CustomisedSpellType type) { @@ -57,8 +60,8 @@ public class SiphoningSpell extends AbstractAreaEffectSpell { @Override public boolean tick(Caster source, Situation situation) { - if (ticksUpset > 0) { - ticksUpset--; + if (ticksUpset > 0 && --ticksUpset <= 0) { + upset.set(false); } if (source.isClient()) { @@ -108,7 +111,7 @@ public class SiphoningSpell extends AbstractAreaEffectSpell { } else { e.damage(damage, e.getHealth() / 4); ticksUpset = 100; - setDirty(); + upset.set(true); } } else { e.heal((float)Math.min(source.getLevel().getScaled(e.getHealth()) / 2F, maxHealthGain * 0.6)); @@ -174,5 +177,8 @@ public class SiphoningSpell extends AbstractAreaEffectSpell { public void fromNBT(NbtCompound compound) { super.fromNBT(compound); ticksUpset = compound.getInt("upset"); + if (ticksUpset > 0) { + upset.set(true); + } } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index 0490c0e0..c2255509 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -45,7 +45,7 @@ public final class SpellType implements Affine, SpellPredicate< private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id)); public static final SpellType PLACE_CONTROL_SPELL = register("place_controller", SpellType.builder(PlacementControlSpell::new).affinity(Affinity.NEUTRAL).unobtainable().stackable().shape(GemstoneItem.Shape.DONUT)); - public static final SpellType THROWN_SPELL = register("thrown", builder(ThrowableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().shape(GemstoneItem.Shape.DONUT)); + public static final SpellType THROWN_SPELL = register("thrown", SpellType.builder(ThrowableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().shape(GemstoneItem.Shape.DONUT)); public static final SpellType CHANGELING_DISGUISE = register("disguise", builder(DispersableDisguiseSpell::new).affinity(Affinity.BAD).color(0x19E48E).unobtainable().shape(GemstoneItem.Shape.ARROW)); public static final SpellType FEED = register("feed", SpellType.builder(ChangelingFeedingSpell::new).affinity(Affinity.BAD).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.ARROW)); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java index d4070f44..3f6e9ca0 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java @@ -30,7 +30,7 @@ import net.minecraft.world.World; * * @param The type of the entity this reference points to. */ -public class EntityReference implements NbtSerialisable, TrackableObject { +public class EntityReference implements NbtSerialisable, TrackableObject> { private static final Serializer SERIALIZER = Serializer.of(EntityReference::new); @SuppressWarnings("unchecked") @@ -122,12 +122,7 @@ public class EntityReference implements NbtSerialisable, Track @Override public int hashCode() { - return getUuid().hashCode(); - } - - @Override - public UUID getUuid() { - return getTarget().map(EntityValues::uuid).orElse(Util.NIL_UUID); + return getTarget().map(EntityValues::uuid).orElse(Util.NIL_UUID).hashCode(); } @Override @@ -140,7 +135,7 @@ public class EntityReference implements NbtSerialisable, Track } @Override - public NbtCompound toTrackedNbt() { + public NbtCompound writeTrackedNbt() { return toNBT(); } @@ -149,6 +144,12 @@ public class EntityReference implements NbtSerialisable, Track fromNBT(compound); } + @Override + public void copyTo(EntityReference destination) { + destination.reference = reference; + destination.directReference = directReference; + } + @Override public void discard(boolean immediate) { set(null); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/CorruptionHandler.java b/src/main/java/com/minelittlepony/unicopia/entity/player/CorruptionHandler.java index 0ea3e639..489bf5b7 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/CorruptionHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/CorruptionHandler.java @@ -38,12 +38,10 @@ public class CorruptionHandler implements Tickable { if (entity.age % (10 * ItemTracker.SECONDS) == 0) { if (random.nextInt(100) == 0) { pony.getCorruption().add(-1); - pony.setDirty(); } if (entity.getHealth() >= entity.getMaxHealth() - 1 && !entity.getHungerManager().isNotFull()) { pony.getCorruption().add(-random.nextInt(4)); - pony.setDirty(); } } } @@ -79,6 +77,5 @@ public class CorruptionHandler implements Tickable { MagicReserves reserves = pony.getMagicalReserves(); reserves.getExertion().addPercent(10); reserves.getEnergy().add(10); - pony.setDirty(); } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index bad61f3f..193246d3 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -1,37 +1,33 @@ package com.minelittlepony.unicopia.network.track; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; public class DataTracker { private final List> codecs = new ObjectArrayList<>(); private IntSet dirtyIndices = new IntOpenHashSet(); - private Int2ObjectMap persistentObjects = new Int2ObjectOpenHashMap<>(); + private List> persistentObjects = new ObjectArrayList<>(); - private final DataTrackerManager manager; private boolean initial = true; final int id; - public DataTracker(DataTrackerManager manager, int id) { - this.manager = manager; + public DataTracker(int id) { this.id = id; } - public Entry startTracking(T value) { - Entry entry = startTracking(TrackableDataType.COMPRESSED_NBT, value.toTrackedNbt()); - persistentObjects.put(entry.id(), value); - return entry; + public > T startTracking(T value) { + persistentObjects.add(value); + return value; } public Entry startTracking(TrackableDataType type, T initialValue) { @@ -50,10 +46,6 @@ public class DataTracker { } private void set(Entry entry, T value) { - if (manager.isClient) { - return; - } - Pair pair = getPair(entry); if (!Objects.equals(pair.value, value)) { synchronized (this) { @@ -63,25 +55,14 @@ public class DataTracker { } } - @SuppressWarnings("unchecked") - private void updateTrackables() { - for (var entry : persistentObjects.int2ObjectEntrySet()) { - int key = entry.getIntKey(); - TrackableObject.Status status = entry.getValue().getStatus(); - if (status == TrackableObject.Status.NEW || status == TrackableObject.Status.UPDATED) { - ((Pair)codecs.get(key)).value = entry.getValue().toTrackedNbt(); - dirtyIndices.add(key); - } - } - } - - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) synchronized void copyTo(DataTracker destination) { for (int i = 0; i < codecs.size(); i++) { ((Pair)destination.codecs.get(i)).value = codecs.get(i).value; - TrackableObject o = destination.persistentObjects.get(i); - if (o != null) { - o.readTrackedNbt((NbtCompound)codecs.get(i).value); + TrackableObject a = persistentObjects.get(i); + TrackableObject b = destination.persistentObjects.get(i); + if (a != null && b != null) { + ((TrackableObject)a).copyTo(b); } } } @@ -89,18 +70,17 @@ public class DataTracker { synchronized Optional getInitialPairs() { initial = false; dirtyIndices = new IntOpenHashSet(); - updateTrackables(); - return Optional.of(new MsgTrackedValues.TrackerEntries(id, true, codecs)); + return Optional.of(new MsgTrackedValues.TrackerEntries(id, true, codecs, writePersistentObjects(true))); } - synchronized Optional getDirtyPairs() { + public synchronized Optional getDirtyPairs() { if (initial) { return getInitialPairs(); } - updateTrackables(); + Map updates = writePersistentObjects(false); - if (dirtyIndices.isEmpty()) { + if (dirtyIndices.isEmpty() && updates.isEmpty()) { return Optional.empty(); } @@ -110,32 +90,40 @@ public class DataTracker { for (int i : toSend) { pairs.add(codecs.get(i)); } - return Optional.of(new MsgTrackedValues.TrackerEntries(id, false, pairs)); + return Optional.of(new MsgTrackedValues.TrackerEntries(id, false, pairs, updates)); } - synchronized void load(MsgTrackedValues.TrackerEntries values) { + private Map writePersistentObjects(boolean initial) { + Map updates = new HashMap<>(); + for (int i = 0; i < persistentObjects.size(); i++) { + TrackableObject o = persistentObjects.get(i); + TrackableObject.Status status = initial ? TrackableObject.Status.NEW : o.getStatus(); + int id = i; + o.write(status).ifPresent(data -> updates.put(id, data)); + } + return updates; + } + + public synchronized void load(MsgTrackedValues.TrackerEntries values) { if (values.wipe()) { codecs.clear(); codecs.addAll(values.values()); - for (var entry : persistentObjects.int2ObjectEntrySet()) { - Pair pair = codecs.get(entry.getIntKey()); - if (pair != null) { - entry.getValue().readTrackedNbt((NbtCompound)pair.value); - } - } } else { for (var value : values.values()) { if (value.id >= 0 && value.id < codecs.size()) { if (codecs.get(value.id).type == value.type) { codecs.set(value.id, value); - TrackableObject o = persistentObjects.get(value.id); - if (o != null) { - o.readTrackedNbt((NbtCompound)value.value); - } } } } } + + for (var entry : values.objects().entrySet()) { + TrackableObject o = persistentObjects.get(entry.getKey()); + if (o != null) { + o.read(entry.getValue()); + } + } } public record Entry(DataTracker tracker, int id) { diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java index b13e9eaa..5b3cc76b 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -41,7 +41,7 @@ public class DataTrackerManager { } public synchronized DataTracker checkoutTracker() { - DataTracker tracker = new DataTracker(this, trackers.size()); + DataTracker tracker = new DataTracker(trackers.size()); trackers.add(tracker); packetEmitters.add((sender, initial) -> { var update = initial ? tracker.getInitialPairs() : tracker.getDirtyPairs(); @@ -56,7 +56,7 @@ public class DataTrackerManager { return tracker; } - public synchronized ObjectTracker checkoutTracker(Supplier objFunction) { + public synchronized > ObjectTracker checkoutTracker(Supplier objFunction) { ObjectTracker tracker = new ObjectTracker<>(objectTrackers.size(), objFunction); objectTrackers.add(tracker); packetEmitters.add((sender, initial) -> { diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java index 0baa2a9b..d9c405cc 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java @@ -14,7 +14,6 @@ import com.sollace.fabwork.api.packets.HandledPacket; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; public record MsgTrackedValues( @@ -45,12 +44,12 @@ public record MsgTrackedValues( } } - public record TrackerObjects(int id, Set removedValues, Map values) { + public record TrackerObjects(int id, Set removedValues, Map values) { public TrackerObjects(PacketByteBuf buffer) { this( buffer.readInt(), buffer.readCollection(HashSet::new, PacketByteBuf::readUuid), - buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketCodec.COMPRESSED_NBT::read) + buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketCodec.RAW_BYTES::read) ); } @@ -58,19 +57,25 @@ public record MsgTrackedValues( public void write(PacketByteBuf buffer) { buffer.writeInt(id); buffer.writeCollection(removedValues, PacketByteBuf::writeUuid); - buffer.writeMap(values, PacketByteBuf::writeUuid, PacketCodec.COMPRESSED_NBT::write); + buffer.writeMap(values, PacketByteBuf::writeUuid, PacketCodec.RAW_BYTES::write); } } - public record TrackerEntries(int id, boolean wipe, List> values) { + public record TrackerEntries(int id, boolean wipe, List> values, Map objects) { public TrackerEntries(PacketByteBuf buffer) { - this(buffer.readInt(), buffer.readBoolean(), buffer.readCollection(ArrayList::new, DataTracker.Pair::new)); + this( + buffer.readInt(), + buffer.readBoolean(), + buffer.readCollection(ArrayList::new, DataTracker.Pair::new), + buffer.readMap(PacketByteBuf::readInt, PacketCodec.RAW_BYTES::read) + ); } public void write(PacketByteBuf buffer) { buffer.writeInt(id); buffer.writeBoolean(wipe); buffer.writeCollection(values, (buf, pair) -> pair.write(buf)); + buffer.writeMap(objects, PacketByteBuf::writeInt, PacketCodec.RAW_BYTES::write); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java index 85554c4a..8e4ef2e2 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/ObjectTracker.java @@ -11,14 +11,11 @@ import java.util.function.Supplier; import org.jetbrains.annotations.Nullable; -import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.util.NbtSerialisable; - +import com.minelittlepony.unicopia.network.track.TrackableObject.Status; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.Util; +import net.minecraft.network.PacketByteBuf; -public class ObjectTracker implements NbtSerialisable { +public class ObjectTracker> { private final Map trackedObjects = new Object2ObjectOpenHashMap<>(); private volatile Map quickAccess = Map.of(); @@ -30,6 +27,10 @@ public class ObjectTracker implements NbtSerialisable this.constructor = constructor; } + public Map entries() { + return quickAccess; + } + public Set keySet() { return quickAccess.keySet(); } @@ -68,15 +69,15 @@ public class ObjectTracker implements NbtSerialisable return true; } - public synchronized void add(T obj) { - trackedObjects.put(obj.getUuid(), obj); + public synchronized void add(UUID id, T obj) { + trackedObjects.put(id, obj); quickAccess = Map.copyOf(trackedObjects); } synchronized void copyTo(ObjectTracker destination) { for (var entry : trackedObjects.entrySet()) { T copy = destination.constructor.get(); - copy.readTrackedNbt(entry.getValue().toTrackedNbt()); + entry.getValue().copyTo(copy); destination.trackedObjects.put(entry.getKey(), copy); } destination.quickAccess = Map.copyOf(destination.trackedObjects); @@ -87,31 +88,35 @@ public class ObjectTracker implements NbtSerialisable return Optional.empty(); } - Map trackableCompounds = new HashMap<>(); + Map updates = new HashMap<>(); quickAccess.entrySet().forEach(object -> { - trackableCompounds.put(object.getKey(), object.getValue().toTrackedNbt()); + object.getValue().write(Status.NEW).ifPresent(data -> { + updates.put(object.getKey(), data); + }); }); - return Optional.of(new MsgTrackedValues.TrackerObjects(id, Set.of(), trackableCompounds)); + return Optional.of(new MsgTrackedValues.TrackerObjects(id, Set.of(), updates)); } synchronized Optional getDirtyPairs() { if (!trackedObjects.isEmpty()) { - Map trackableCompounds = new HashMap<>(); + Map updates = new HashMap<>(); Set removedTrackableObjects = new HashSet<>(); trackedObjects.entrySet().removeIf(object -> { TrackableObject.Status status = object.getValue().getStatus(); if (status == TrackableObject.Status.REMOVED) { removedTrackableObjects.add(object.getKey()); - } else if (status != TrackableObject.Status.DEFAULT) { - trackableCompounds.put(object.getKey(), object.getValue().toTrackedNbt()); + return true; } - return status == TrackableObject.Status.REMOVED; + object.getValue().write(status).ifPresent(data -> { + updates.put(object.getKey(), data); + }); + return false; }); quickAccess = Map.copyOf(trackedObjects); - if (!trackableCompounds.isEmpty() || !removedTrackableObjects.isEmpty()) { - return Optional.of(new MsgTrackedValues.TrackerObjects(id, removedTrackableObjects, trackableCompounds)); + if (!updates.isEmpty() || !removedTrackableObjects.isEmpty()) { + return Optional.of(new MsgTrackedValues.TrackerObjects(id, removedTrackableObjects, updates)); } } @@ -125,44 +130,18 @@ public class ObjectTracker implements NbtSerialisable o.discard(true); } }); - objects.values().forEach((id, nbt) -> { + objects.values().forEach((id, data) -> { T o = trackedObjects.get(id); if (o == null) { o = constructor.get(); trackedObjects.put(id, o); } - o.readTrackedNbt(nbt); + o.read(data); }); quickAccess = Map.copyOf(trackedObjects); } - @Override - public synchronized void toNBT(NbtCompound compound) { - quickAccess.forEach((id, value) -> { - compound.put(id.toString(), value.toTrackedNbt()); - }); - } - - @Override - public void fromNBT(NbtCompound compound) { - Map values = new Object2ObjectOpenHashMap<>(); - compound.getKeys().forEach(key -> { - try { - UUID id = Util.NIL_UUID; - try { - id = UUID.fromString(key); - } catch (Throwable ignore) {} - - if (id != null && !Util.NIL_UUID.equals(id)) { - NbtCompound nbt = compound.getCompound(key); - T entry = constructor.get(); - entry.readTrackedNbt(nbt); - values.put(id, entry); - } - } catch (Throwable t) { - Unicopia.LOGGER.warn("Exception loading tracked object: {}", t.getMessage()); - } - }); + public void load(Map values) { synchronized (this) { trackedObjects.clear(); trackedObjects.putAll(values); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java index e106081f..9c5c6b74 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java @@ -23,6 +23,7 @@ public record TrackableDataType(int id, PacketCodec codec) { public static final TrackableDataType UUID = of(new Identifier("uuid"), PacketCodec.UUID); public static final TrackableDataType NBT = of(new Identifier("nbt"), PacketCodec.NBT); public static final TrackableDataType COMPRESSED_NBT = of(new Identifier("compressed_nbt"), PacketCodec.COMPRESSED_NBT); + public static final TrackableDataType> RAW_BYTES = of(new Identifier("raw_bytes"), PacketCodec.RAW_BYTES.asOptional()); public static final TrackableDataType> OPTIONAL_POS = of(new Identifier("optional_pos"), PacketCodec.OPTIONAL_POS); public static final TrackableDataType RACE = TrackableDataType.of(Unicopia.id("race"), PacketCodec.ofRegistry(Race.REGISTRY)); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableObject.java b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableObject.java index 40439f93..8065aa81 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableObject.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableObject.java @@ -1,20 +1,37 @@ package com.minelittlepony.unicopia.network.track; -import java.util.UUID; +import java.util.Optional; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; + +import io.netty.buffer.Unpooled; import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.PacketByteBuf; -public interface TrackableObject { - UUID getUuid(); - +public interface TrackableObject> { Status getStatus(); - NbtCompound toTrackedNbt(); + default void read(PacketByteBuf buffer) { + readTrackedNbt(PacketCodec.COMPRESSED_NBT.read(buffer)); + } - void readTrackedNbt(NbtCompound compound); + default Optional write(Status status) { + if (status == Status.NEW || status == Status.UPDATED) { + PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()); + PacketCodec.COMPRESSED_NBT.write(buffer, writeTrackedNbt()); + return Optional.of(buffer); + } + return Optional.empty(); + } + + void readTrackedNbt(NbtCompound nbt); + + NbtCompound writeTrackedNbt(); void discard(boolean immediate); + void copyTo(T destination); + public enum Status { DEFAULT, NEW, diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index 21980091..840e66fa 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -37,7 +37,7 @@ public class Ether extends PersistentState { this.world = world; this.endpoints = NbtSerialisable.readMap(compound.getCompound("endpoints"), Identifier::tryParse, typeNbt -> { return NbtSerialisable.readMap((NbtCompound)typeNbt, UUID::fromString, entityNbt -> { - return NbtSerialisable.readMap((NbtCompound)entityNbt, UUID::fromString, Entry::new); + return NbtSerialisable.readMap((NbtCompound)entityNbt, UUID::fromString, nbt -> new Entry<>(nbt)); }); }); } diff --git a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java index 1dcf0bba..32f9ea21 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java +++ b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java @@ -69,14 +69,31 @@ public interface NbtSerialisable { } static Map readMap(NbtCompound nbt, Function keyFunction, Function valueFunction) { - return nbt.getKeys().stream().collect(Collectors.toMap(keyFunction, k -> valueFunction.apply(nbt.get(k)))); + return readMap(nbt, keyFunction, (k, v) -> valueFunction.apply(v)); + } + + static Map readMap(NbtCompound nbt, Function keyFunction, BiFunction valueFunction) { + return nbt.getKeys().stream().map(k -> { + K key = keyFunction.apply(k); + if (key == null) { + return null; + } + V value = valueFunction.apply(key, nbt.get(k)); + if (value == null) { + return null; + } + return Map.entry(key, value); + }) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } static NbtCompound writeMap(Map map, Function keyFunction, Function valueFunction) { - NbtCompound nbt = new NbtCompound(); - map.forEach((k, v) -> { - nbt.put(keyFunction.apply(k), valueFunction.apply(v)); - }); + return writeMap(new NbtCompound(), map, keyFunction, valueFunction); + } + + static NbtCompound writeMap(NbtCompound nbt, Map map, Function keyFunction, Function valueFunction) { + map.forEach((k, v) -> nbt.put(keyFunction.apply(k), valueFunction.apply(v))); return nbt; } From a25d8b7a2cbb3305fb0ae5db4c8cab5215a752f8 Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 27 May 2024 06:40:47 +0100 Subject: [PATCH 64/85] Remove debug messages --- .../minelittlepony/unicopia/ability/EarthPonyStompAbility.java | 1 - .../com/minelittlepony/unicopia/entity/ai/TargettingUtil.java | 1 - .../java/com/minelittlepony/unicopia/entity/player/Pony.java | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java index 82586e85..de4c8be8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java @@ -181,7 +181,6 @@ public class EarthPonyStompAbility implements Ability { @Override public void onCancelled() { - System.out.println("Cancel Stomp"); iplayer.playSound(USounds.GUI_ABILITY_FAIL, 1F); } }; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java index fe611c57..b165579f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java @@ -32,7 +32,6 @@ public interface TargettingUtil { static Vec3d getProjectedPos(LivingEntity entity) { if (entity instanceof PlayerEntity player) { Vec3d velocity = Pony.of(player).getPhysics().getClientVelocity(); - System.out.println(velocity); return entity.getEyePos().add(velocity.multiply(1.5)).add(0, -1, 0); } return entity.getEyePos().add(entity.getVelocity()); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 09ec5ceb..6c55a3be 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -833,7 +833,6 @@ public class Pony extends Living implements Copyable, Update @Override public void toSyncronisedNbt(NbtCompound compound) { - System.out.println("toSyncNbt"); super.toSyncronisedNbt(compound); compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString()); compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString()); @@ -856,7 +855,6 @@ public class Pony extends Living implements Copyable, Update @Override public void fromSynchronizedNbt(NbtCompound compound) { - System.out.println("fromSyncNbt"); super.fromSynchronizedNbt(compound); setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN)); setSuppressedRace(Race.fromName(compound.getString("suppressedSpecies"), Race.UNSET)); From c510c727fa9b040519b841e4d60839d9fbfe5481 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 13:28:49 +0100 Subject: [PATCH 65/85] Display full tooltip details in the spellbook for equipped spells --- .../unicopia/client/gui/spellbook/SpellbookScreen.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java index 56ff0539..86df4595 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java @@ -14,7 +14,6 @@ import com.minelittlepony.unicopia.Debug; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.client.TextHelper; import com.minelittlepony.unicopia.client.gui.*; import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*; import com.minelittlepony.unicopia.compat.trinkets.TrinketSlotBackSprites; @@ -211,8 +210,7 @@ public class SpellbookScreen extends HandledScreen imple List tooltip = new ArrayList<>(); tooltip.add(spell.type().getName()); - tooltip.addAll(TextHelper.wrap(Text.translatable(spell.type().getTranslationKey() + ".lore").formatted(spell.type().getAffinity().getColor()), 180).toList()); - + spell.appendTooltip(tooltip); context.drawTooltip(textRenderer, tooltip, x, y); context.getMatrices().pop(); From cf4d98078c6099b665ac90f3a0074d33d869828c Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 13:32:40 +0100 Subject: [PATCH 66/85] Fixed (regression) spellbook not having a page when first placed --- .../com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java index 5808aea4..41180bda 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpellbookEntity.java @@ -75,6 +75,7 @@ public class SpellbookEntity extends MobEntity implements MagicImmune { super(type, world); setPersistent(); setAltered(world.random.nextInt(3) == 0); + state.setCurrentPageId(SpellbookState.CRAFTING_ID); if (!world.isClient) { state.setSynchronizer(state -> { getWorld().getPlayers().forEach(player -> { From ce48d86fd6ce8710929c9d9d761a79e9bec95d5f Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 14:31:59 +0100 Subject: [PATCH 67/85] Reduce casting time for projectiles --- .../unicopia/ability/UnicornProjectileAbility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornProjectileAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornProjectileAbility.java index e05038a9..09258a4a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornProjectileAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornProjectileAbility.java @@ -24,7 +24,7 @@ import net.minecraft.util.TypedActionResult; public class UnicornProjectileAbility extends AbstractSpellCastingAbility { @Override public int getWarmupTime(Pony player) { - return 8; + return 1; } @Override From 98714556a0ea8b1bffad87be8e654c04e6995537 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 14:32:22 +0100 Subject: [PATCH 68/85] Fixed magic projectiles not affecting falling blocks --- .../unicopia/projectile/MagicProjectileEntity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java index 8591048d..be5afd69 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java @@ -14,6 +14,7 @@ import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.item.UItems; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; +import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.data.TrackedData; @@ -207,7 +208,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements WeaklyOwn protected void onEntityHit(EntityHitResult hit) { Entity entity = hit.getEntity(); - if (EquinePredicates.IS_MAGIC_IMMUNE.test(entity)) { + if (!(entity instanceof FallingBlockEntity) && EquinePredicates.IS_MAGIC_IMMUNE.test(entity)) { return; } From 9efe49afbd26a14f32606f577c3120022f985ffb Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 14:32:31 +0100 Subject: [PATCH 69/85] Fix error printed when respawning --- .../unicopia/network/track/DataTracker.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java index 193246d3..1bc68115 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -59,10 +59,12 @@ public class DataTracker { synchronized void copyTo(DataTracker destination) { for (int i = 0; i < codecs.size(); i++) { ((Pair)destination.codecs.get(i)).value = codecs.get(i).value; - TrackableObject a = persistentObjects.get(i); - TrackableObject b = destination.persistentObjects.get(i); - if (a != null && b != null) { - ((TrackableObject)a).copyTo(b); + if (i < persistentObjects.size() && i < destination.persistentObjects.size()) { + TrackableObject a = persistentObjects.get(i); + TrackableObject b = destination.persistentObjects.get(i); + if (a != null && b != null) { + ((TrackableObject)a).copyTo(b); + } } } } From 5207f7fefb5886e6a4b5411899f5133b31318b21 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 14:33:30 +0100 Subject: [PATCH 70/85] Tweak catapult to make pushing entities easier and fix falling blocks not updating their velocity when pushed --- .../magic/spell/effect/CatapultSpell.java | 49 ++++++++++++++----- .../resources/assets/unicopia/lang/en_us.json | 4 +- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java index 4c9c1dd7..72d56132 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java @@ -6,6 +6,7 @@ import java.util.function.Consumer; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.UTags; +import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; @@ -19,11 +20,15 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.FallingBlockEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; import net.minecraft.text.Text; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.random.Random; import net.minecraft.world.World; /** @@ -41,8 +46,12 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B private static final float MAX_STRENGTH = 120; static void appendTooltip(CustomisedSpellType type, List tooltip) { - float velocity = 0.1F + type.relativeTraits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH); - tooltip.add(SpellAttributes.of(SpellAttributes.VERTICAL_VELOCITY, velocity / 16F)); + float velocity = (float)(0.1F + (type.traits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16D); + tooltip.add(SpellAttributes.of(SpellAttributes.VERTICAL_VELOCITY, velocity)); + int hoverDuration = 50 + (int)type.traits().get(Trait.AIR, 0, 10) * 20; + tooltip.add(SpellAttributes.ofTime(Unicopia.id("hang_time"), hoverDuration)); + float power = 1 + type.traits().get(Trait.POWER, 0, 10) / 10F; + tooltip.add(SpellAttributes.of(Unicopia.id("pushing_power"), power)); } protected CatapultSpell(CustomisedSpellType type) { @@ -52,7 +61,11 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B @Override public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) { if (!projectile.isClient() && projectile instanceof MagicBeamEntity source && source.canModifyAt(hit.getBlockPos())) { - createBlockEntity(projectile.getWorld(), hit.getBlockPos(), e -> apply(source, e)); + createBlockEntity(projectile.getWorld(), hit.getBlockPos(), e -> { + e.setOnGround(true); + apply(source, e); + e.setOnGround(false); + }); } } @@ -75,16 +88,32 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B } protected void apply(Caster caster, Entity e) { - Vec3d vel = caster.asEntity().getVelocity(); - if (Math.abs(e.getVelocity().y) > 0.5) { - e.setVelocity(caster.asEntity().getVelocity()); + + float power = 1 + getTraits().get(Trait.POWER, 0, 10) / 10F; + + if (!e.isOnGround()) { + e.setVelocity(caster.asEntity().getVelocity().multiply(power)); } else { + Random rng = caster.asWorld().random; + double launchSpeed = 0.1F + (getTraits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16D; e.addVelocity( - ((caster.asWorld().random.nextFloat() * HORIZONTAL_VARIANCE) - HORIZONTAL_VARIANCE + vel.x * 0.8F) * 0.1F, - 0.1F + (getTraits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16D, - ((caster.asWorld().random.nextFloat() * HORIZONTAL_VARIANCE) - HORIZONTAL_VARIANCE + vel.z * 0.8F) * 0.1F + rng.nextTriangular(0, HORIZONTAL_VARIANCE) * 0.1F, + launchSpeed, + rng.nextTriangular(0, HORIZONTAL_VARIANCE) * 0.1F ); + + if (e instanceof LivingEntity l) { + int hoverDuration = 50 + (int)getTraits().get(Trait.AIR, 0, 10) * 20; + + if (l.hasStatusEffect(StatusEffects.SLOW_FALLING)) { + l.removeStatusEffect(StatusEffects.SLOW_FALLING); + } + l.addStatusEffect(new StatusEffectInstance(StatusEffects.SLOW_FALLING, hoverDuration, 1)); + } } + + e.velocityDirty = true; + e.velocityModified = true; } static void createBlockEntity(World world, BlockPos bpos, @Nullable Consumer apply) { @@ -109,7 +138,5 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B apply.accept(e); } world.spawnEntity(e); - - e.updateVelocity(HORIZONTAL_VARIANCE, pos); } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 7c75fb3b..6d92a2d4 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -599,7 +599,9 @@ "spell_attribute.unicopia.strength": "Effect Strength", "spell_attribute.unicopia.soapiness": "Soapiness", "spell_attribute.unicopia.velocity": "Velocity", - "spell_attribute.unicopia.vertical_velocity": "Launch Speed", + "spell_attribute.unicopia.vertical_velocity": "Initial Launch Speed", + "spell_attribute.unicopia.hang_time": "Hang Time", + "spell_attribute.unicopia.pushing_power": "Pushing Power", "spell_attribute.unicopia.damage_to_target": "Damage to Target", "spell_attribute.unicopia.simultanious_targets": "Simultanious Targets", "spell_attribute.unicopia.cost_per_individual": "Mana cost per individual", From 1f714b3ed0f455b13fd98c3f53618141e42013df Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 18:48:06 +0100 Subject: [PATCH 71/85] Tooltip details version 2 --- .../ability/magic/spell/SpellAttributes.java | 11 +++ .../magic/spell/attribute/Affects.java | 15 ++++ .../spell/attribute/AttributeFormat.java | 63 +++++++++++++ .../magic/spell/attribute/Permits.java | 8 ++ .../magic/spell/attribute/SpellAttribute.java | 88 +++++++++++++++++++ .../magic/spell/attribute/TooltipFactory.java | 19 ++++ .../magic/spell/effect/CatapultSpell.java | 52 ++++++++--- .../ability/magic/spell/effect/SpellType.java | 2 +- .../unicopia/entity/effect/EffectUtils.java | 9 +- .../resources/assets/unicopia/lang/en_us.json | 7 ++ 10 files changed, 261 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/Affects.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/AttributeFormat.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/Permits.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java index f4b2ffdc..df35b029 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java @@ -26,6 +26,10 @@ public interface SpellAttributes { Identifier STRENGTH = Unicopia.id("strength"); Identifier VELOCITY = Unicopia.id("velocity"); Identifier VERTICAL_VELOCITY = Unicopia.id("vertical_velocity"); + Identifier HANG_TIME = Unicopia.id("hang_time"); + Identifier PUSHING_POWER = Unicopia.id("pushing_power"); + Identifier CAUSES_LEVITATION = Unicopia.id("causes_levitation"); + Identifier AFFECTS = Unicopia.id("affects"); Identifier DAMAGE_TO_TARGET = Unicopia.id("damage_to_target"); Identifier SIMULTANIOUS_TARGETS = Unicopia.id("simultanious_targets"); Identifier COST_PER_INDIVIDUAL = Unicopia.id("cost_per_individual"); @@ -61,4 +65,11 @@ public interface SpellAttributes { Text.translatable(Util.createTranslationKey("spell_attribute", id)) ).formatted(Formatting.LIGHT_PURPLE)); } + + public enum ValueType { + REGULAR, + TIME, + PERCENTAGE, + CONDITIONAL + } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/Affects.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/Affects.java new file mode 100644 index 00000000..dbbe9916 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/Affects.java @@ -0,0 +1,15 @@ +package com.minelittlepony.unicopia.ability.magic.spell.attribute; + +public enum Affects { + BOTH, + ENTITIES, + BLOCKS; + + public boolean allowsBlocks() { + return this == BOTH || this == BLOCKS; + } + + public boolean allowsEntities() { + return this == BOTH || this == ENTITIES; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/AttributeFormat.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/AttributeFormat.java new file mode 100644 index 00000000..eba8db86 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/AttributeFormat.java @@ -0,0 +1,63 @@ +package com.minelittlepony.unicopia.ability.magic.spell.attribute; + +import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; +import com.minelittlepony.unicopia.client.UnicopiaClient; +import com.minelittlepony.unicopia.client.gui.ItemTraitsTooltipRenderer; + +import net.minecraft.item.ItemStack; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.StringHelper; + +public enum AttributeFormat { + REGULAR { + @Override + public String formatValue(float value) { + return ItemStack.MODIFIER_FORMAT.format(value); + } + }, + TIME { + @Override + public String formatValue(float value) { + return StringHelper.formatTicks((int)Math.abs(value)); + } + }, + PERCENTAGE { + @Override + public String formatValue(float value) { + return ItemStack.MODIFIER_FORMAT.format((int)(Math.abs(value) * 100)) + "%"; + } + }; + + public abstract String formatValue(float value); + + public MutableText getBase(Text attributeName, float value, String comparison, Formatting color) { + return formatAttributeLine(Text.translatable("attribute.modifier." + comparison + ".0", formatValue(value), attributeName).formatted(color)); + } + + public Text get(Text attributeName, float value) { + return getBase(attributeName, value, "equals", Formatting.LIGHT_PURPLE); + } + + public Text getRelative(Text attributeName, float baseValue, float currentValue, boolean detrimental) { + float difference = currentValue - baseValue; + return Text.literal(" (" + (difference > 0 ? "+" : "-") + formatValue(this == PERCENTAGE ? difference / baseValue : difference) + ")").formatted((detrimental ? difference : -difference) < 0 ? Formatting.DARK_GREEN : Formatting.RED); + } + + static Text formatTraitDifference(Trait trait, float value) { + boolean known = ItemTraitsTooltipRenderer.isKnown(trait); + boolean canCast = UnicopiaClient.getClientPony() != null && UnicopiaClient.getClientPony().getObservedSpecies().canCast(); + Text name = canCast ? known + ? trait.getName() + : Text.translatable("spell_attribute.unicopia.added_trait.unknown").formatted(Formatting.YELLOW) + : trait.getName().copy().formatted(Formatting.OBFUSCATED, Formatting.YELLOW); + Text count = Text.literal(ItemStack.MODIFIER_FORMAT.format(value)); + return Text.translatable("spell_attribute.unicopia.added_trait." + ((value > 0) ? "plus" : "take"), name, count).formatted(Formatting.DARK_AQUA); + } + + static MutableText formatAttributeLine(Text attributeName) { + return Text.literal(" ").append(attributeName).formatted(Formatting.LIGHT_PURPLE); + } + +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/Permits.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/Permits.java new file mode 100644 index 00000000..c63f1275 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/Permits.java @@ -0,0 +1,8 @@ +package com.minelittlepony.unicopia.ability.magic.spell.attribute; + +public enum Permits { + ITEMS, + PASSIVE, + HOSTILE, + PLAYER +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java new file mode 100644 index 00000000..e450568d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java @@ -0,0 +1,88 @@ +package com.minelittlepony.unicopia.ability.magic.spell.attribute; + +import java.util.List; +import java.util.Locale; +import java.util.function.Function; + +import org.jetbrains.annotations.NotNull; + +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; +import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; + +import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; +import net.minecraft.util.Util; + +public record SpellAttribute ( + Trait trait, + Float2ObjectFunction valueGetter, + TooltipFactory tooltipFactory +) implements TooltipFactory { + @Override + public void appendTooltip(CustomisedSpellType type, List tooltip) { + tooltipFactory.appendTooltip(type, tooltip); + } + + public T get(SpellTraits traits) { + return valueGetter.get(traits.get(trait)); + } + + public static SpellAttribute create(Identifier id, AttributeFormat format, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter) { + return create(id, format, format, trait, valueGetter, false); + } + + public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter) { + return create(id, baseFormat, relativeFormat, trait, valueGetter, false); + } + + public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter, boolean detrimental) { + Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id)); + return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { + float traitAmount = type.traits().get(trait); + float traitDifference = type.relativeTraits().get(trait); + float value = valueGetter.get(traitAmount).floatValue(); + + var b = baseFormat.getBase(name, value, "equals", Formatting.LIGHT_PURPLE); + if (traitDifference != 0) { + tooltip.add(b.append(relativeFormat.getRelative(Text.empty(), valueGetter.get(traitAmount - traitDifference).floatValue(), value, detrimental))); + tooltip.add(AttributeFormat.formatTraitDifference(trait, traitDifference)); + } else { + tooltip.add(b); + } + }); + } + + public static SpellAttribute createConditional(Identifier id, Trait trait, Float2ObjectFunction valueGetter) { + return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { + Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id)); + float difference = type.relativeTraits().get(trait); + Text value = AttributeFormat.formatAttributeLine(name); + if (!valueGetter.get(type.traits().get(trait))) { + value = value.copy().formatted(Formatting.STRIKETHROUGH, Formatting.DARK_GRAY); + } + tooltip.add(value); + if (difference != 0) { + tooltip.add(AttributeFormat.formatTraitDifference(trait, difference)); + } + }); + } + + public static > SpellAttribute createEnumerated(Identifier id, Trait trait, Float2ObjectFunction valueGetter) { + Function cache = Util.memoize(t -> Text.translatable(Util.createTranslationKey("spell_attribute", id.withPath(id.getPath() + "." + t.name().toLowerCase(Locale.ROOT))))); + return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { + T t = valueGetter.get(type.traits().get(trait)); + + if (t != null) { + int max = t.getClass().getEnumConstants().length; + tooltip.add(Text.translatable(" %s (%s/%s)", cache.apply(t), Text.literal("" + (t.ordinal() + 1)).formatted(Formatting.LIGHT_PURPLE), max).formatted(Formatting.DARK_PURPLE)); + } + float difference = type.relativeTraits().get(trait); + if (difference != 0) { + tooltip.add(AttributeFormat.formatTraitDifference(trait, difference)); + } + }); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java new file mode 100644 index 00000000..e4fd5db9 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java @@ -0,0 +1,19 @@ +package com.minelittlepony.unicopia.ability.magic.spell.attribute; + +import java.util.List; + +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; + +import net.minecraft.text.Text; + +public interface TooltipFactory { + void appendTooltip(CustomisedSpellType type, List tooltip); + + static TooltipFactory of(TooltipFactory...lines) { + return (type, tooltip) -> { + for (var line : lines) { + line.appendTooltip(type, tooltip); + } + }; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java index 72d56132..287e55bb 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java @@ -6,10 +6,13 @@ import java.util.function.Consumer; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.UTags; -import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.Affects; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.mixin.MixinFallingBlockEntity; @@ -27,6 +30,7 @@ import net.minecraft.text.Text; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.Random; import net.minecraft.world.World; @@ -45,13 +49,22 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B private static final float HORIZONTAL_VARIANCE = 0.25F; private static final float MAX_STRENGTH = 120; + private static final SpellAttribute LAUNCH_SPEED = SpellAttribute.create(SpellAttributes.VERTICAL_VELOCITY, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> 0.1F + (MathHelper.clamp(strength, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16F); + private static final SpellAttribute HANG_TIME = SpellAttribute.create(SpellAttributes.HANG_TIME, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.AIR, air -> 50 + (int)MathHelper.clamp(air, 0, 10) * 20F); + private static final SpellAttribute PUSHING_POWER = SpellAttribute.create(SpellAttributes.PUSHING_POWER, AttributeFormat.REGULAR, Trait.POWER, power -> 1 + MathHelper.clamp(power, 0, 10) / 10F); + private static final SpellAttribute CAUSES_LEVITATION = SpellAttribute.createConditional(SpellAttributes.CAUSES_LEVITATION, Trait.FOCUS, focus -> focus > 50); + private static final SpellAttribute AFFECTS = SpellAttribute.createEnumerated(SpellAttributes.AFFECTS, Trait.ORDER, order -> { + if (order <= 0) { + return Affects.BOTH; + } else if (order <= 10) { + return Affects.ENTITIES; + } + return Affects.BLOCKS; + }); + static final TooltipFactory TOOLTIP = TooltipFactory.of(LAUNCH_SPEED, HANG_TIME, PUSHING_POWER, CAUSES_LEVITATION, AFFECTS); + static void appendTooltip(CustomisedSpellType type, List tooltip) { - float velocity = (float)(0.1F + (type.traits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16D); - tooltip.add(SpellAttributes.of(SpellAttributes.VERTICAL_VELOCITY, velocity)); - int hoverDuration = 50 + (int)type.traits().get(Trait.AIR, 0, 10) * 20; - tooltip.add(SpellAttributes.ofTime(Unicopia.id("hang_time"), hoverDuration)); - float power = 1 + type.traits().get(Trait.POWER, 0, 10) / 10F; - tooltip.add(SpellAttributes.of(Unicopia.id("pushing_power"), power)); + TOOLTIP.appendTooltip(type, tooltip); } protected CatapultSpell(CustomisedSpellType type) { @@ -60,6 +73,10 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B @Override public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) { + if (!AFFECTS.get(getTraits()).allowsBlocks()) { + return; + } + if (!projectile.isClient() && projectile instanceof MagicBeamEntity source && source.canModifyAt(hit.getBlockPos())) { createBlockEntity(projectile.getWorld(), hit.getBlockPos(), e -> { e.setOnGround(true); @@ -72,6 +89,11 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B @Override public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { if (!projectile.isClient() && projectile instanceof MagicBeamEntity source) { + Entity e = hit.getEntity(); + if (!(e instanceof FallingBlockEntity) && !AFFECTS.get(getTraits()).allowsEntities()) { + return; + } + apply(source, hit.getEntity()); } } @@ -95,21 +117,29 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B e.setVelocity(caster.asEntity().getVelocity().multiply(power)); } else { Random rng = caster.asWorld().random; - double launchSpeed = 0.1F + (getTraits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16D; e.addVelocity( rng.nextTriangular(0, HORIZONTAL_VARIANCE) * 0.1F, - launchSpeed, + LAUNCH_SPEED.get(getTraits()), rng.nextTriangular(0, HORIZONTAL_VARIANCE) * 0.1F ); - if (e instanceof LivingEntity l) { - int hoverDuration = 50 + (int)getTraits().get(Trait.AIR, 0, 10) * 20; + int hoverDuration = HANG_TIME.get(getTraits()).intValue(); + boolean noGravity = CAUSES_LEVITATION.get(getTraits()); + if (e instanceof LivingEntity l) { if (l.hasStatusEffect(StatusEffects.SLOW_FALLING)) { l.removeStatusEffect(StatusEffects.SLOW_FALLING); } l.addStatusEffect(new StatusEffectInstance(StatusEffects.SLOW_FALLING, hoverDuration, 1)); } + + if (noGravity || e instanceof FallingBlockEntity && (!e.getWorld().getBlockState(e.getBlockPos().up()).isReplaceable())) { + if (e instanceof LivingEntity l) { + l.addStatusEffect(new StatusEffectInstance(StatusEffects.LEVITATION, 200, 1)); + } else { + e.setNoGravity(true); + } + } } e.velocityDirty = true; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index c2255509..9ae37a33 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -68,7 +68,7 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType AWKWARD = register("awkward", builder(AwkwardSpell::new).affinity(Affinity.NEUTRAL).color(0x3A59FF).shape(GemstoneItem.Shape.ICE)); public static final SpellType TRANSFORMATION = register("transformation", builder(TransformationSpell::new).color(0x19E48E).shape(GemstoneItem.Shape.BRUSH)); public static final SpellType FEATHER_FALL = register("feather_fall", builder(FeatherFallSpell::new).color(0x00EEFF).shape(GemstoneItem.Shape.LAMBDA).traits(FeatherFallSpell.DEFAULT_TRAITS).tooltip(FeatherFallSpell::appendTooltip)); - public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS).tooltip(CatapultSpell::appendTooltip)); + public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS).tooltip(CatapultSpell.TOOLTIP::appendTooltip)); public static final SpellType FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS).tooltip(FireBoltSpell::appendTooltip)); public static final SpellType LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS).tooltip(LightSpell::appendTooltip)); public static final SpellType DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).stackable().shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS).tooltip(DisplacementSpell::appendTooltip)); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java index 750c1a8e..3a462183 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/EffectUtils.java @@ -52,7 +52,7 @@ public interface EffectUtils { } static Text formatModifierChange(String modifierName, int time, boolean isDetrimental) { - return Text.literal(" ").append(Text.translatable("attribute.modifier.equals.0", + return Text.literal(" ").append(Text.translatable("attribute.modifier." + (time > 0 ? "plus" : "take") + ".0", StringHelper.formatTicks(Math.abs(time)), Text.translatable(modifierName) ).formatted((isDetrimental ? time : -time) < 0 ? Formatting.DARK_GREEN : Formatting.RED)); @@ -64,4 +64,11 @@ public interface EffectUtils { Text.translatable(modifierName) ).formatted((isDetrimental ? change : -change) < 0 ? Formatting.DARK_GREEN : Formatting.RED)); } + + static Text formatModifierChange(Text modifierName, float change, boolean isDetrimental) { + return Text.literal(" ").append(Text.translatable("attribute.modifier." + (change > 0 ? "plus" : "take") + ".0", + ItemStack.MODIFIER_FORMAT.format(Math.abs(change)), + modifierName + ).formatted((isDetrimental ? change : -change) < 0 ? Formatting.DARK_GREEN : Formatting.RED)); + } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 6d92a2d4..4c19c409 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -584,10 +584,17 @@ "spell.unicopia.dispel_evil": "Dispel Evil", "spell.unicopia.dispel_evil.lore": "Casts away any nearby unearthly forces", + "spell_attribute.unicopia.added_trait.plus": " + %s x%s", + "spell_attribute.unicopia.added_trait.take": " - %s x%s", + "spell_attribute.unicopia.added_trait.unknown": "Undiscovered Trait", "spell_attribute.unicopia.cast_on_location": "Applies to location", "spell_attribute.unicopia.cast_on_person": "Applies to self", "spell_attribute.unicopia.focused_entity": "Applies to focused entity", + "spell_attribute.unicopia.affects.both": "Affects blocks and entities", + "spell_attribute.unicopia.affects.entities": "Affects only entities", + "spell_attribute.unicopia.affects.blocks": "Affects only blocks", "spell_attribute.unicopia.follows_target": "Follows target", + "spell_attribute.unicopia.causes_levitation": "Causes Levitation", "spell_attribute.unicopia.permit_items": " Permits Items", "spell_attribute.unicopia.permit_passive": "Permits Passive Mobs", From 66d0dc8750b4c13296ca3c9bbb7a8a73c658cca3 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 23:18:54 +0100 Subject: [PATCH 72/85] Clean up the hud and only show the super bar when it's useful. Also use the xp bar to show level and corruption --- .../client/gui/DismissSpellScreen.java | 8 +- .../unicopia/client/gui/DrawableUtil.java | 98 +++++-------------- .../unicopia/client/gui/ManaRingSlot.java | 51 +++++++--- .../client/gui/SpellIconRenderer.java | 6 +- .../unicopia/client/gui/UHud.java | 4 +- .../SpellbookProfilePageContent.java | 12 +-- .../client/render/spell/SpellRenderer.java | 3 +- 7 files changed, 77 insertions(+), 105 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index d73091c0..cddf13b9 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -84,8 +84,8 @@ public class DismissSpellScreen extends GameGui { matrices.push(); matrices.translate(width - mouseX, height - mouseY, 0); DrawableUtil.drawLine(matrices, 0, 0, relativeMouseX, relativeMouseY, 0xFFFFFF88); - DrawableUtil.drawArc(matrices, 40, 80, 0, DrawableUtil.TAU, 0x00000010, false); - DrawableUtil.drawArc(matrices, 160, 1600, 0, DrawableUtil.TAU, 0x00000020, false); + DrawableUtil.drawArc(matrices, 40, 80, 0, DrawableUtil.TAU, 0x00000010); + DrawableUtil.drawArc(matrices, 160, 1600, 0, DrawableUtil.TAU, 0x00000020); super.render(context, mouseX, mouseY, delta); DrawableUtil.renderRaceIcon(context, pony.getObservedSpecies(), 0, 0, 16); @@ -187,10 +187,10 @@ public class DismissSpellScreen extends GameGui { boolean hovered = isMouseOver(relativeMouseX, relativeMouseY); double radius = (hovered ? 9 + MathHelper.sin((MinecraftClient.getInstance().player.age + tickDelta) / 9F) : 7); - DrawableUtil.drawArc(matrices, radius, radius + 1, 0, DrawableUtil.TAU, color | 0x00000088, false); + DrawableUtil.drawArc(matrices, radius, radius + 1, 0, DrawableUtil.TAU, color | 0x00000088); if (hovered) { - DrawableUtil.drawArc(matrices, 0, 8, 0, DrawableUtil.TAU, color | 0x000000FF, false); + DrawableUtil.drawArc(matrices, 0, 8, 0, DrawableUtil.TAU, color | 0x000000FF); List tooltip = new ArrayList<>(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DrawableUtil.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DrawableUtil.java index 82cd1958..24f5141c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DrawableUtil.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DrawableUtil.java @@ -71,27 +71,41 @@ public interface DrawableUtil { RenderSystem.disableBlend(); } + /** + * Renders a colored arc with notches. + * + * @param mirrorHorizontally Whether or not the arc must be mirrored across the horizontal plane. Will produce a bar that grows from the middle filling both sides. + */ + static void drawNotchedArc(MatrixStack matrices, double innerRadius, double outerRadius, double startAngle, double arcAngle, double notchAngle, double notchSpacing, int color) { + double notchBegin = startAngle; + double endAngle = startAngle + arcAngle; + while (notchBegin < endAngle) { + double notchEnd = Math.min(notchBegin + notchAngle, endAngle); + if (notchEnd <= notchBegin) { + return; + } + drawArc(matrices, innerRadius, outerRadius, notchBegin, notchEnd - notchBegin, color); + notchBegin += notchAngle + notchSpacing; + } + + } + /** * Renders a colored arc. * * @param mirrorHorizontally Whether or not the arc must be mirrored across the horizontal plane. Will produce a bar that grows from the middle filling both sides. */ - static void drawArc(MatrixStack matrices, double innerRadius, double outerRadius, double startAngle, double arcAngle, int color, boolean mirrorHorizontally) { + static void drawArc(MatrixStack matrices, double innerRadius, double outerRadius, double startAngle, double arcAngle, int color) { + if (arcAngle < INCREMENT) { + return; + } float r = (color >> 24 & 255) / 255F; float g = (color >> 16 & 255) / 255F; float b = (color >> 8 & 255) / 255F; float k = (color & 255) / 255F; - if (arcAngle < INCREMENT) { - return; - } - final double maxAngle = MathHelper.clamp(startAngle + arcAngle, 0, TAU - INCREMENT); - if (!mirrorHorizontally) { - startAngle = -startAngle; - } - RenderSystem.setShaderColor(1, 1, 1, 1); RenderSystem.setShader(GameRenderer::getPositionColorProgram); RenderSystem.enableBlend(); @@ -102,7 +116,7 @@ public interface DrawableUtil { BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); - for (double angle = startAngle; angle >= -maxAngle; angle -= INCREMENT) { + for (double angle = -startAngle; angle >= -maxAngle; angle -= INCREMENT) { // center cylendricalVertex(bufferBuilder, model, innerRadius, angle, r, g, b, k); // point one @@ -116,70 +130,6 @@ public interface DrawableUtil { BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()); } - /** - * Renders hollow circle - * - * @param mirrorHorizontally Whether or not the arc must be mirrored across the horizontal plane. Will produce a bar that grows from the middle filling both sides. - */ - static void drawArc(MatrixStack matrices, double radius, double startAngle, double arcAngle, int color, boolean mirrorHorizontally) { - drawCircle(matrices, radius, startAngle, arcAngle, color, mirrorHorizontally, VertexFormat.DrawMode.DEBUG_LINES); - } - - /** - * Renders a filled circle. - * - * @param mirrorHorizontally Whether or not the arc must be mirrored across the horizontal plane. Will produce a bar that grows from the middle filling both sides. - */ - static void drawCircle(MatrixStack matrices, double radius, double startAngle, double arcAngle, int color, boolean mirrorHorizontally) { - drawCircle(matrices, radius, startAngle, arcAngle, color, mirrorHorizontally, VertexFormat.DrawMode.QUADS); - } - - private static void drawCircle(MatrixStack matrices, double radius, double startAngle, double arcAngle, int color, boolean mirrorHorizontally, VertexFormat.DrawMode mode) { - float r = (color >> 24 & 255) / 255F; - float g = (color >> 16 & 255) / 255F; - float b = (color >> 8 & 255) / 255F; - float k = (color & 255) / 255F; - - if (arcAngle < INCREMENT) { - return; - } - - final double maxAngle = MathHelper.clamp(startAngle + arcAngle, 0, TAU - INCREMENT); - - if (!mirrorHorizontally) { - startAngle = -startAngle; - } - - RenderSystem.setShaderColor(1, 1, 1, 1); - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - - Matrix4f model = matrices.peek().getPositionMatrix(); - - BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); - bufferBuilder.begin(mode, VertexFormats.POSITION_COLOR); - - boolean joinEnds = mode == VertexFormat.DrawMode.QUADS; - - // center - - for (double angle = startAngle; angle >= -maxAngle; angle -= INCREMENT) { - if (joinEnds) { - bufferBuilder.vertex(model, 0, 0, 0).color(r, g, b, k).next(); - } - // point one - cylendricalVertex(bufferBuilder, model, radius, angle, r, g, b, k); - // point two - cylendricalVertex(bufferBuilder, model, radius, angle + INCREMENT, r, g, b, k); - if (joinEnds) { - bufferBuilder.vertex(model, 0, 0, 0).color(r, g, b, k).next(); - } - } - - BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()); - } - private static void cylendricalVertex(BufferBuilder bufferBuilder, Matrix4f model, double radius, double angle, float r, float g, float b, float k) { bufferBuilder.vertex(model, (float)(radius * MathHelper.sin((float)angle)), diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/ManaRingSlot.java b/src/main/java/com/minelittlepony/unicopia/client/gui/ManaRingSlot.java index 73ef3bdb..d9e88921 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/ManaRingSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/ManaRingSlot.java @@ -1,6 +1,7 @@ package com.minelittlepony.unicopia.client.gui; import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.entity.player.MagicReserves; @@ -21,19 +22,44 @@ class ManaRingSlot extends Slot { @Override protected void renderContents(DrawContext context, AbilityDispatcher abilities, boolean bSwap, float tickDelta) { MatrixStack matrices = context.getMatrices(); + + + matrices.push(); - matrices.translate(24.5, 25.5, 0); + matrices.translate(24.125, 24.75, 0); Pony pony = Pony.of(uHud.client.player); MagicReserves mana = pony.getMagicalReserves(); - double arcBegin = 0; + boolean canUseSuper = Abilities.RAGE.canUse(pony.getCompositeRace()) || Abilities.RAINBOOM.canUse(pony.getCompositeRace()); - arcBegin = renderRing(matrices, 17, 13, 0, mana.getMana(), 0xFF88FF99, tickDelta); + double maxManaBarSize = canUseSuper ? DrawableUtil.PI : DrawableUtil.TAU; + double arcBegin = renderRing(matrices, 17, 13, 0, maxManaBarSize, mana.getMana(), 0xFF88FF99, tickDelta); + renderRing(matrices, 17, 13, 0, maxManaBarSize, mana.getExhaustion(), 0xFF002299, tickDelta); if (!uHud.client.player.isCreative()) { - renderRing(matrices, 13, 9, 0, mana.getXp(), 0x88880099, tickDelta); - renderRing(matrices, 9, 0, 0, mana.getCharge(), 0x0000FF99, tickDelta); + + int level = pony.getLevel().get(); + int seconds = level % 16; + int minutes = (level / 16) % 16; + int hours = level / 32; + + DrawableUtil.drawNotchedArc(matrices, 10, 13, 0, hours * 0.2, 0.1, 0.1, 0x00AA88FF); + DrawableUtil.drawNotchedArc(matrices, 10, 13, hours * 0.2, minutes * 0.2, 0.1, 0.1, 0x008888AA); + DrawableUtil.drawNotchedArc(matrices, 10, 13, (hours + minutes) * 0.2, seconds * 0.2, 0.1, 0.1, 0x88880099); + + level = pony.getCorruption().get(); + seconds = level % 16; + minutes = (level / 16) % 16; + hours = level / 32; + + DrawableUtil.drawNotchedArc(matrices, 7, 10, DrawableUtil.PI, hours * 0.2, 0.1, 0.1, 0x000088FF); + DrawableUtil.drawNotchedArc(matrices, 7, 10, hours * 0.2 + DrawableUtil.PI, minutes * 0.2, 0.1, 0.1, 0x000088AA); + DrawableUtil.drawNotchedArc(matrices, 7, 10, (hours + minutes) * 0.2 + DrawableUtil.PI, seconds * 0.2, 0.1, 0.1, 0x00008899); + + if (canUseSuper) { + renderRing(matrices, 17, 13, Math.min(arcBegin, DrawableUtil.PI), Math.max(DrawableUtil.PI, DrawableUtil.TAU - arcBegin), mana.getCharge(), 0x88FF9999, tickDelta); + } double cost = abilities.getStats().stream() .mapToDouble(s -> s.getCost(Unicopia.getConfig().hudPage.get())) @@ -53,28 +79,25 @@ class ManaRingSlot extends Slot { double angle = cost * Math.PI * 2; - DrawableUtil.drawArc(matrices, 13, 17, arcBegin - angle, angle, color, false); + DrawableUtil.drawArc(matrices, 13, 17, arcBegin - angle, angle, color); } } - arcBegin = renderRing(matrices, 17, 13, arcBegin, mana.getExhaustion(), 0xFF002299, tickDelta); - matrices.pop(); - super.renderContents(context, abilities, bSwap, tickDelta); } - private double renderRing(MatrixStack matrices, double outerRadius, double innerRadius, double offsetAngle, Bar bar, int color, float tickDelta) { - double fill = bar.getPercentFill(tickDelta) * DrawableUtil.TAU; - double shadow = bar.getShadowFill(tickDelta) * DrawableUtil.TAU; + private double renderRing(MatrixStack matrices, double outerRadius, double innerRadius, double offsetAngle, double maxAngle, Bar bar, int color, float tickDelta) { + double fill = bar.getPercentFill(tickDelta) * maxAngle; + double shadow = bar.getShadowFill(tickDelta) * maxAngle; - DrawableUtil.drawArc(matrices, innerRadius, outerRadius, offsetAngle, fill, color, true); + DrawableUtil.drawArc(matrices, innerRadius, outerRadius, offsetAngle, fill, color); if (shadow > fill) { color = (color & 0xFFFFFF00) | ((color & 0x000000FF) / 2); - DrawableUtil.drawArc(matrices, innerRadius, outerRadius, offsetAngle + fill, shadow - fill, color, false); + DrawableUtil.drawArc(matrices, innerRadius, outerRadius, offsetAngle + fill, shadow - fill, color); } return offsetAngle + fill; } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/SpellIconRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/gui/SpellIconRenderer.java index a113c369..57c383d7 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/SpellIconRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/SpellIconRenderer.java @@ -33,10 +33,10 @@ public interface SpellIconRenderer { int color = spell.type().getColor() | 0x000000FF; double radius = (1.5F + Math.sin(client.player.age / 9D) / 4) * ringScale; - DrawableUtil.drawArc(modelStack, radius, radius + 3, 0, DrawableUtil.TAU, color & 0xFFFFFF2F, false); - DrawableUtil.drawArc(modelStack, radius + 3, radius + 4, 0, DrawableUtil.TAU, color & 0xFFFFFFAF, false); + DrawableUtil.drawArc(modelStack, radius, radius + 3, 0, DrawableUtil.TAU, color & 0xFFFFFF2F); + DrawableUtil.drawArc(modelStack, radius + 3, radius + 4, 0, DrawableUtil.TAU, color & 0xFFFFFFAF); pony.getSpellSlot().get(spell.and(SpellPredicate.IS_TIMED)).map(TimedSpell::getTimer).ifPresent(timer -> { - DrawableUtil.drawArc(modelStack, radius, radius + 3, 0, DrawableUtil.TAU * timer.getPercentTimeRemaining(client.getTickDelta()), 0xFFFFFFFF, false); + DrawableUtil.drawArc(modelStack, radius, radius + 3, 0, DrawableUtil.TAU * timer.getPercentTimeRemaining(client.getTickDelta()), 0xFFFFFFFF); }); long count = pony.getSpellSlot().stream(spell).count(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index f24dd0e5..fb50166e 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -101,7 +101,7 @@ public class UHud { float flapCooldown = pony.getPhysics().getFlapCooldown(tickDelta); if (flapCooldown > 0) { float angle = MathHelper.TAU * flapCooldown; - DrawableUtil.drawArc(context.getMatrices(), 3, 6, -angle / 2F, angle, 0x888888AF, false); + DrawableUtil.drawArc(context.getMatrices(), 3, 6, -angle / 2F, angle, 0x888888AF); } matrices.pop(); @@ -205,7 +205,7 @@ public class UHud { context.fill(RenderLayers.getEndPortal(), 0, 0, scaledWidth, scaledHeight, 0); context.getMatrices().push(); context.getMatrices().translate(scaledWidth / 2, scaledHeight / 2, 0); - DrawableUtil.drawArc(context.getMatrices(), 0, 20, 0, MathHelper.TAU, 0x000000FF, false); + DrawableUtil.drawArc(context.getMatrices(), 0, 20, 0, MathHelper.TAU, 0x000000FF); context.getMatrices().pop(); return; } else if (vortexDistortion > 0) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java index f68d0790..b0fe5fda 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookProfilePageContent.java @@ -110,8 +110,8 @@ public class SpellbookProfilePageContent implements SpellbookChapterList.Content } manaColor |= (int)((0.3F + 0.7F * alphaF) * 0x40) << 16; - DrawableUtil.drawArc(matrices, 0, radius + 24, 0, DrawableUtil.TAU, color, false); - DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, DrawableUtil.TAU, color, false); + DrawableUtil.drawArc(matrices, 0, radius + 24, 0, DrawableUtil.TAU, color); + DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, DrawableUtil.TAU, color); if (currentLevel >= pony.getLevel().getMax()) { int rayCount = 6; @@ -129,14 +129,14 @@ public class SpellbookProfilePageContent implements SpellbookChapterList.Content double rad = (radius + glowSize) * 0.8F + growth - (i % 2) * 5; float rot = (rotate + raySeparation * i) % MathHelper.TAU; - DrawableUtil.drawArc(matrices, 0, rad, rot, 0.2F, bandAColor, false); - DrawableUtil.drawArc(matrices, 0, rad + 0.3F, rot + 0.37F, 0.25F, bandBColor, false); + DrawableUtil.drawArc(matrices, 0, rad, rot, 0.2F, bandAColor); + DrawableUtil.drawArc(matrices, 0, rad + 0.3F, rot + 0.37F, 0.25F, bandBColor); } } - DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, xpPercentage * DrawableUtil.TAU, xpColor, false); + DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, xpPercentage * DrawableUtil.TAU, xpColor); radius += 8; - DrawableUtil.drawArc(matrices, radius, radius + 6 + growth, 0, manaPercentage * DrawableUtil.TAU, manaColor, false); + DrawableUtil.drawArc(matrices, radius, radius + 6 + growth, 0, manaPercentage * DrawableUtil.TAU, manaColor); String manaString = (int)reserves.getMana().get() + "/" + (int)reserves.getMana().getMax(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java index 74e72212..a1171b7c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java @@ -58,8 +58,7 @@ public class SpellRenderer { float timeRemaining = spell.getTimer().getPercentTimeRemaining(tickDelta); DrawableUtil.drawArc(matrices, radius, radius + 0.3F, 0, DrawableUtil.TAU * timeRemaining, - ColorHelper.lerp(MathHelper.clamp(timeRemaining * 4, 0, 1), 0xFF0000FF, 0xFFFFFFFF), - false + ColorHelper.lerp(MathHelper.clamp(timeRemaining * 4, 0, 1), 0xFF0000FF, 0xFFFFFFFF) ); } From aaea2bfbc12dccb131107a3aa1066587ad87d7ce Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 May 2024 23:19:23 +0100 Subject: [PATCH 73/85] Account for the water's depth when determining the amount of lift pegasi should receive --- .../block/cloud/UnstableCloudBlock.java | 4 ++-- .../unicopia/entity/mob/StormCloudEntity.java | 20 +++---------------- .../unicopia/entity/player/Acrobatics.java | 4 ++-- .../entity/player/FlightStuntUtil.java | 4 ++-- .../server/world/WeatherConditions.java | 12 ++++++++++- .../unicopia/util/PosHelper.java | 14 +++++++++++++ 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/UnstableCloudBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/UnstableCloudBlock.java index 30bf49c4..b64c03d6 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/UnstableCloudBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/UnstableCloudBlock.java @@ -2,9 +2,9 @@ package com.minelittlepony.unicopia.block.cloud; import java.util.Optional; -import com.minelittlepony.unicopia.entity.mob.StormCloudEntity; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; +import com.minelittlepony.unicopia.util.PosHelper; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -82,7 +82,7 @@ public class UnstableCloudBlock extends CloudBlock { ); BlockPos shockPosition = lightningRodPos.or(() -> { return sw.getOtherEntities(entity, new Box(pos.down()).expand(5, 0, 5).stretch(0, -10, 0)).stream().findAny().map(Entity::getBlockPos); - }).orElseGet(() -> StormCloudEntity.findSurfaceBelow(sw, pos.add(world.random.nextInt(10) - 5, -world.random.nextInt(10), world.random.nextInt(10) - 5)).toImmutable()); + }).orElseGet(() -> PosHelper.findNearestSurface(sw, pos.add(world.random.nextInt(10) - 5, -world.random.nextInt(10), world.random.nextInt(10) - 5)).toImmutable()); ParticleUtils.spawnParticle(world, new LightningBoltParticleEffect(false, 10, 6, 0.3F, Optional.of(shockPosition.toCenterPos())), diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/StormCloudEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/StormCloudEntity.java index d7f1054f..6bad71e2 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/StormCloudEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/StormCloudEntity.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.server.world.WeatherConditions; +import com.minelittlepony.unicopia.util.PosHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityStatuses; @@ -38,7 +39,6 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.GameRules; @@ -148,7 +148,7 @@ public class StormCloudEntity extends Entity implements MagicImmune { } if (isLogicalSideForUpdatingMovement()) { - float groundY = findSurfaceBelow(getWorld(), getBlockPos()).getY(); + float groundY = PosHelper.findNearestSurface(getWorld(), getBlockPos()).getY(); float targetY = isStormy() ? STORMY_TARGET_ALTITUDE : CLEAR_TARGET_ALTITUDE; float cloudY = (float)getY() - targetY; @@ -271,24 +271,10 @@ public class StormCloudEntity extends Entity implements MagicImmune { private void pickRandomPoints(int count, Consumer action) { BlockPos.iterateRandomly(random, 3, getBlockPos(), getSizeInBlocks()).forEach(pos -> { - action.accept(findSurfaceBelow(getWorld(), pos)); + action.accept(PosHelper.findNearestSurface(getWorld(), pos)); }); } - public static BlockPos findSurfaceBelow(World world, BlockPos pos) { - BlockPos.Mutable mutable = new BlockPos.Mutable(); - mutable.set(pos); - while (mutable.getY() > world.getBottomY() && world.isAir(mutable)) { - mutable.move(Direction.DOWN); - } - while (world.isInBuildLimit(mutable) && !world.isAir(mutable)) { - mutable.move(Direction.UP); - } - mutable.move(Direction.DOWN); - - return mutable; - } - private void spawnLightningStrike(BlockPos pos, boolean cosmetic, boolean infect) { if (infect) { if (!CrystalShardsEntity.infestBlock((ServerWorld)getWorld(), pos)) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java index 2afbc3ca..e86b61c8 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java @@ -7,10 +7,10 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; -import com.minelittlepony.unicopia.entity.mob.StormCloudEntity; import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.NbtSerialisable; +import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.Tickable; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -51,7 +51,7 @@ public class Acrobatics implements Tickable, NbtSerialisable { if (entity.isCreative() && entity.getAbilities().flying) { return false; } - return pony.getCompositeRace().any(Race::isFish) && !entity.isTouchingWater() && !entity.getWorld().isWater(StormCloudEntity.findSurfaceBelow(entity.getWorld(), entity.getBlockPos())); + return pony.getCompositeRace().any(Race::isFish) && !entity.isTouchingWater() && !entity.getWorld().isWater(PosHelper.findNearestSurface(entity.getWorld(), entity.getBlockPos())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/FlightStuntUtil.java b/src/main/java/com/minelittlepony/unicopia/entity/player/FlightStuntUtil.java index c5975dbe..9ff96023 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/FlightStuntUtil.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/FlightStuntUtil.java @@ -1,7 +1,7 @@ package com.minelittlepony.unicopia.entity.player; -import com.minelittlepony.unicopia.entity.mob.StormCloudEntity; import com.minelittlepony.unicopia.util.MutableVector; +import com.minelittlepony.unicopia.util.PosHelper; import net.minecraft.util.math.BlockPos; @@ -14,6 +14,6 @@ public class FlightStuntUtil { public static boolean isFlyingLow(Pony pony, MutableVector velocity) { BlockPos pos = pony.asEntity().getBlockPos(); - return velocity.horizontalLengthSquared() > 0.005F && (pos.getY() - StormCloudEntity.findSurfaceBelow(pony.asWorld(), pos).getY()) < 6; + return velocity.horizontalLengthSquared() > 0.005F && (pos.getY() - PosHelper.findNearestSurface(pony.asWorld(), pos).getY()) < 6; } } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java index d392b684..ec505291 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java @@ -165,6 +165,8 @@ public class WeatherConditions extends PersistentState implements Tickable { final float terrainFactor = getScaledDistanceFromTerrain(probedPosition.set(pos), world, MAX_TERRAIN_HEIGHT); final float windFactor = getScaledDistanceFromTerrain(probedPosition.set(pos), world, MAX_WIND_HEIGHT); + System.out.println(terrainFactor + "/" + windFactor); + Vec3d terrainGradient = LOCAL_ALTITUDE_FIELD.computeAverage(world, pos, probedPosition).multiply(1 - terrainFactor); Vec3d thermalGradient = THERMAL_FIELD.computeAverage(world, pos, probedPosition).multiply(1 - terrainFactor); Vec3d wind = get(world).getWindDirection().multiply(windFactor); @@ -212,7 +214,15 @@ public class WeatherConditions extends PersistentState implements Tickable { } if (state.getFluidState().isIn(FluidTags.WATER)) { - return MeteorlogicalUtil.getSunIntensity(world); + float sunIntensity = MeteorlogicalUtil.getSunIntensity(world); + int depth = 0; + BlockPos.Mutable mutable = pos.mutableCopy(); + while (depth < 15 && world.getFluidState(mutable).isIn(FluidTags.WATER)) { + mutable.move(Direction.DOWN); + depth++; + } + + return sunIntensity * (depth / 15F); } return 0; diff --git a/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java b/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java index f050c796..d7c00444 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java +++ b/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java @@ -28,6 +28,20 @@ public interface PosHelper { return a.add(b.getX(), b.getY(), b.getZ()); } + static BlockPos findNearestSurface(World world, BlockPos pos) { + BlockPos.Mutable mutable = pos.mutableCopy(); + + while (mutable.getY() > world.getBottomY() && world.isAir(mutable)) { + mutable.move(Direction.DOWN); + } + while (world.isInBuildLimit(mutable) && !world.isAir(mutable)) { + mutable.move(Direction.UP); + } + mutable.move(Direction.DOWN); + + return mutable; + } + static BlockPos findSolidGroundAt(World world, BlockPos pos, int signum) { BlockPos.Mutable mutable = pos.mutableCopy(); while (world.isInBuildLimit(mutable) && (world.isAir(mutable) || !world.getBlockState(mutable).canPlaceAt(world, mutable))) { From 92d2bc229f507dddfdad5a2824bbbcae7577960a Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 7 Jun 2024 00:15:15 +0100 Subject: [PATCH 74/85] Configure spell attributes for all the spell types --- .../magic/spell/AbstractAreaEffectSpell.java | 19 ++----- .../ability/magic/spell/SpellAttributes.java | 20 ++++--- .../ability/magic/spell/TimedSpell.java | 16 ++---- .../ability/magic/spell/attribute/CastOn.java | 6 +++ .../magic/spell/attribute/SpellAttribute.java | 33 +++++++++--- .../magic/spell/attribute/TooltipFactory.java | 15 ++++++ .../spell/effect/AreaProtectionSpell.java | 12 ++--- .../magic/spell/effect/AttractiveSpell.java | 39 +++++--------- .../magic/spell/effect/BubbleSpell.java | 16 +++--- .../magic/spell/effect/DispellEvilSpell.java | 14 ++--- .../spell/effect/DisperseIllusionSpell.java | 17 +++--- .../magic/spell/effect/DisplacementSpell.java | 17 +++--- .../magic/spell/effect/FireBoltSpell.java | 43 ++++++++------- .../ability/magic/spell/effect/FireSpell.java | 18 +++---- .../magic/spell/effect/HydrophobicSpell.java | 15 +++--- .../ability/magic/spell/effect/IceSpell.java | 15 ++++-- .../magic/spell/effect/LightSpell.java | 16 +++--- .../magic/spell/effect/MimicSpell.java | 12 ++--- .../magic/spell/effect/NecromancySpell.java | 20 +++---- .../magic/spell/effect/ScorchSpell.java | 2 +- .../magic/spell/effect/ShieldSpell.java | 52 +++++++------------ .../magic/spell/effect/SiphoningSpell.java | 8 +-- .../ability/magic/spell/effect/SpellType.java | 46 +++++++++------- 23 files changed, 233 insertions(+), 238 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/CastOn.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java index 128323a0..edf19a17 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java @@ -1,20 +1,15 @@ package com.minelittlepony.unicopia.ability.magic.spell; -import java.util.List; - import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.effect.*; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; -import net.minecraft.text.Text; public abstract class AbstractAreaEffectSpell extends AbstractSpell { - - public static void appendRangeTooltip(CustomisedSpellType type, List tooltip) { - float addedRange = type.traits().get(Trait.POWER); - if (addedRange != 0) { - tooltip.add(SpellAttributes.ofRelative(SpellAttributes.RANGE, addedRange)); - } - } + protected static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power)); + public static final TooltipFactory TOOLTIP = RANGE; protected AbstractAreaEffectSpell(CustomisedSpellType type) { super(type); @@ -24,8 +19,4 @@ public abstract class AbstractAreaEffectSpell extends AbstractSpell { public Spell prepareForCast(Caster caster, CastingMethod method) { return toPlaceable(); } - - protected final float getAdditionalRange() { - return (int)getTraits().get(Trait.POWER); - } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java index df35b029..012cdc02 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java @@ -13,14 +13,14 @@ import net.minecraft.util.Util; public interface SpellAttributes { Text CAST_ON_LOCATION = of(Unicopia.id("cast_on_location")); Text CAST_ON_PERSON = of(Unicopia.id("cast_on_person")); - Text TARGET_ENTITY = of(Unicopia.id("focused_entity")); - Text FOLLOWS_TARGET = of(Unicopia.id("follows_target")); + Identifier FOLLOWS_TARGET = Unicopia.id("follows_target"); - Text PERMIT_ITEMS = of(Unicopia.id("permit_items")); - Text PERMIT_PASSIVE = of(Unicopia.id("permit_passive")); - Text PERMIT_HOSTILE = of(Unicopia.id("permit_hostile")); - Text PERMIT_PLAYER = of(Unicopia.id("permit_player")); + Identifier PERMIT_ITEMS = Unicopia.id("permit_items"); + Identifier PERMIT_PASSIVE = Unicopia.id("permit_passive"); + Identifier PERMIT_HOSTILE = Unicopia.id("permit_hostile"); + Identifier PERMIT_PLAYER = Unicopia.id("permit_player"); + Identifier FOCUSED_ENTITY = Unicopia.id("focused_entity"); Identifier RANGE = Unicopia.id("range"); Identifier DURATION = Unicopia.id("duration"); Identifier STRENGTH = Unicopia.id("strength"); @@ -38,15 +38,20 @@ public interface SpellAttributes { Identifier ORB_COUNT = Unicopia.id("orb_count"); Identifier WAVE_SIZE = Unicopia.id("wave_size"); Identifier FOLLOW_RANGE = Unicopia.id("follow_range"); + Identifier LIGHT_TARGET = Unicopia.id("light_target"); + Identifier STICK_TO_TARGET = Unicopia.id("stick_to_target"); Identifier SOAPINESS = Unicopia.id("soapiness"); + Identifier CAST_ON = Unicopia.id("cast_on"); Identifier TARGET_PREFERENCE = Unicopia.id("target_preference"); Identifier CASTER_PREFERENCE = Unicopia.id("caster_preference"); + @Deprecated static Text of(Identifier id) { return Text.literal(" ").append(Text.translatable(Util.createTranslationKey("spell_attribute", id))).formatted(Formatting.LIGHT_PURPLE); } + @Deprecated static Text of(Identifier id, float value) { return Text.literal(" ").append( Text.translatable("attribute.modifier.equals.0", @@ -55,10 +60,12 @@ public interface SpellAttributes { ).formatted(Formatting.LIGHT_PURPLE); } + @Deprecated static Text ofRelative(Identifier id, float value) { return EffectUtils.formatModifierChange(Util.createTranslationKey("spell_attribute", id), value, false); } + @Deprecated static Text ofTime(Identifier id, long time) { return Text.literal(" ").append(Text.translatable("attribute.modifier.equals.0", StringHelper.formatTicks((int)Math.abs(time)), @@ -66,6 +73,7 @@ public interface SpellAttributes { ).formatted(Formatting.LIGHT_PURPLE)); } + @Deprecated public enum ValueType { REGULAR, TIME, diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java index 33b2b837..94e13b11 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java @@ -1,15 +1,12 @@ package com.minelittlepony.unicopia.ability.magic.spell; -import java.util.List; - -import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; /** @@ -17,17 +14,10 @@ import net.minecraft.util.math.MathHelper; */ public interface TimedSpell extends Spell { int BASE_DURATION = 120 * 20; + SpellAttribute TIME = SpellAttribute.create(SpellAttributes.SOAPINESS, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> BASE_DURATION + (int)(MathHelper.clamp(focus, 0, 160) * 19) * 20); Timer getTimer(); - static void appendDurationTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.ofTime(SpellAttributes.DURATION, BASE_DURATION + getExtraDuration(type.traits()))); - } - - static int getExtraDuration(SpellTraits traits) { - return (int)(traits.get(Trait.FOCUS, 0, 160) * 19) * 20; - } - class Timer implements Tickable, NbtSerialisable { private int maxDuration; private int duration; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/CastOn.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/CastOn.java new file mode 100644 index 00000000..aded56d9 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/CastOn.java @@ -0,0 +1,6 @@ +package com.minelittlepony.unicopia.ability.magic.spell.attribute; + +public enum CastOn { + LOCATION, + SELF +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java index e450568d..3da4f498 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.attribute; import java.util.List; import java.util.Locale; +import java.util.function.BiFunction; import java.util.function.Function; import org.jetbrains.annotations.NotNull; @@ -18,7 +19,7 @@ import net.minecraft.util.Util; public record SpellAttribute ( Trait trait, - Float2ObjectFunction valueGetter, + BiFunction valueGetter, TooltipFactory tooltipFactory ) implements TooltipFactory { @Override @@ -27,7 +28,11 @@ public record SpellAttribute ( } public T get(SpellTraits traits) { - return valueGetter.get(traits.get(trait)); + return valueGetter.apply(traits, traits.get(trait)); + } + + public static SpellAttribute create(Identifier id, AttributeFormat format, Trait trait, BiFunction valueGetter) { + return create(id, format, format, trait, valueGetter, false); } public static SpellAttribute create(Identifier id, AttributeFormat format, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter) { @@ -38,16 +43,24 @@ public record SpellAttribute ( return create(id, baseFormat, relativeFormat, trait, valueGetter, false); } + public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, BiFunction valueGetter) { + return create(id, baseFormat, relativeFormat, trait, valueGetter, false); + } + public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter, boolean detrimental) { + return create(id, baseFormat, relativeFormat, trait, (traits, value) -> valueGetter.get(value.floatValue()), detrimental); + } + + public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, BiFunction valueGetter, boolean detrimental) { Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id)); return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { float traitAmount = type.traits().get(trait); float traitDifference = type.relativeTraits().get(trait); - float value = valueGetter.get(traitAmount).floatValue(); + float value = valueGetter.apply(type.traits(), traitAmount).floatValue(); var b = baseFormat.getBase(name, value, "equals", Formatting.LIGHT_PURPLE); if (traitDifference != 0) { - tooltip.add(b.append(relativeFormat.getRelative(Text.empty(), valueGetter.get(traitAmount - traitDifference).floatValue(), value, detrimental))); + tooltip.add(b.append(relativeFormat.getRelative(Text.empty(), valueGetter.apply(type.traits(), traitAmount - traitDifference).floatValue(), value, detrimental))); tooltip.add(AttributeFormat.formatTraitDifference(trait, traitDifference)); } else { tooltip.add(b); @@ -56,11 +69,15 @@ public record SpellAttribute ( } public static SpellAttribute createConditional(Identifier id, Trait trait, Float2ObjectFunction valueGetter) { + return createConditional(id, trait, (traits, value) -> valueGetter.get(value.floatValue())); + } + + public static SpellAttribute createConditional(Identifier id, Trait trait, BiFunction valueGetter) { return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id)); float difference = type.relativeTraits().get(trait); Text value = AttributeFormat.formatAttributeLine(name); - if (!valueGetter.get(type.traits().get(trait))) { + if (!valueGetter.apply(type.traits(), type.traits().get(trait))) { value = value.copy().formatted(Formatting.STRIKETHROUGH, Formatting.DARK_GRAY); } tooltip.add(value); @@ -71,9 +88,13 @@ public record SpellAttribute ( } public static > SpellAttribute createEnumerated(Identifier id, Trait trait, Float2ObjectFunction valueGetter) { + return createEnumerated(id, trait, (traits, value) -> valueGetter.get(value.floatValue())); + } + + public static > SpellAttribute createEnumerated(Identifier id, Trait trait, BiFunction valueGetter) { Function cache = Util.memoize(t -> Text.translatable(Util.createTranslationKey("spell_attribute", id.withPath(id.getPath() + "." + t.name().toLowerCase(Locale.ROOT))))); return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { - T t = valueGetter.get(type.traits().get(trait)); + T t = valueGetter.apply(type.traits(), type.traits().get(trait)); if (t != null) { int max = t.getClass().getEnumConstants().length; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java index e4fd5db9..8b7e69dd 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java @@ -1,8 +1,10 @@ package com.minelittlepony.unicopia.ability.magic.spell.attribute; import java.util.List; +import java.util.function.Predicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import net.minecraft.text.Text; @@ -16,4 +18,17 @@ public interface TooltipFactory { } }; } + + static TooltipFactory of(Text line) { + return (type, tooltip) -> tooltip.add(line); + } + + default TooltipFactory conditionally(Predicate condition) { + TooltipFactory self = this; + return (type, tooltip) -> { + if (condition.test(type.traits())) { + self.appendTooltip(type, tooltip); + } + }; + } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java index b239cad6..b44547a7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java @@ -1,11 +1,10 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; - import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.mob.UEntities; @@ -16,7 +15,6 @@ import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; -import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -26,11 +24,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { .with(Trait.STRENGTH, 30) .build(); - - static void appendTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.CAST_ON_LOCATION); - tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); - } + static final TooltipFactory TOOLTIP = TooltipFactory.of(TooltipFactory.of(SpellAttributes.CAST_ON_LOCATION), RANGE); protected AreaProtectionSpell(CustomisedSpellType type) { super(type); @@ -71,7 +65,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { private double getRange(Caster source) { float multiplier = source instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2; - float min = 4 + getAdditionalRange(); + float min = RANGE.get(getTraits()); double range = (min + (source.getLevel().getScaled(4) * 2)) / multiplier; if (source instanceof Pony && range > 2) { range = Math.sqrt(range); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java index 04a0185d..5cabfa21 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java @@ -1,9 +1,9 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; - import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.Living; @@ -17,31 +17,23 @@ import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; -import net.minecraft.text.Text; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSpell, ProjectileDelegate.EntityHitListener { + static final SpellAttribute TARGET_FOCUSED_ENTITY = SpellAttribute.createConditional(SpellAttributes.FOCUSED_ENTITY, Trait.ORDER, order -> order >= 20); + static final SpellAttribute STICK_TO_TARGET = SpellAttribute.createConditional(SpellAttributes.STICK_TO_TARGET, Trait.CHAOS, chaos -> chaos > 0); + static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_FOCUSED_ENTITY.get(type.traits()) ? TARGET_FOCUSED_ENTITY : ShieldSpell.TARGET).appendTooltip(type, tooltip); + static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, RANGE, TARGET, STICK_TO_TARGET, CAST_ON); private final EntityReference target = new EntityReference<>(); private final Timer timer; - public static void appendTooltip2(CustomisedSpellType type, List tooltip) { - TimedSpell.appendDurationTooltip(type, tooltip); - AbstractAreaEffectSpell.appendRangeTooltip(type, tooltip); - if (type.traits().get(Trait.ORDER) >= 20) { - tooltip.add(SpellAttributes.TARGET_ENTITY); - } else { - appendValidTargetsTooltip(type, tooltip); - } - appendCastLocationTooltip(type, tooltip); - } - protected AttractiveSpell(CustomisedSpellType type) { super(type); - timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); + timer = new Timer(TIME.get(getTraits())); dataTracker.startTracking(target); } @@ -52,12 +44,10 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp @Override public boolean tick(Caster caster, Situation situation) { - if (getType() != SpellType.DARK_VORTEX) { - timer.tick(); + timer.tick(); - if (timer.getTicksRemaining() <= 0) { - return false; - } + if (timer.getTicksRemaining() <= 0) { + return false; } target.getOrEmpty(caster.asWorld()) @@ -87,10 +77,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp @Override protected boolean isValidTarget(Caster source, Entity entity) { - if (target.referenceEquals(entity)) { - return true; - } - return super.isValidTarget(source, entity); + return target.referenceEquals(entity) || super.isValidTarget(source, entity); } @Override @@ -140,7 +127,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp @Override public boolean setTarget(Entity target) { - if (getTraits().get(Trait.ORDER) >= 20) { + if (TARGET_FOCUSED_ENTITY.get(getTraits())) { this.target.set(target); target.setGlowing(true); return true; @@ -156,7 +143,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp @Override public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { - if (!isDead() && getTraits().get(Trait.CHAOS) > 0) { + if (!isDead() && STICK_TO_TARGET.get(getTraits())) { setDead(); Caster.of(hit.getEntity()).ifPresent(caster -> getTypeAndTraits().apply(caster, CastingMethod.INDIRECT)); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index bd24dfae..f63f575c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -1,12 +1,14 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; import java.util.Map; import java.util.UUID; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.*; @@ -25,7 +27,6 @@ import net.minecraft.entity.attribute.*; import net.minecraft.entity.attribute.EntityAttributeModifier.Operation; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; -import net.minecraft.text.Text; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -50,10 +51,9 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, .with(Trait.POWER, 1) .build(); - static void appendTooltip(CustomisedSpellType type, List tooltip) { - TimedSpell.appendDurationTooltip(type, tooltip); - tooltip.add(SpellAttributes.of(SpellAttributes.SOAPINESS, (int)(type.traits().get(Trait.POWER) * 2))); - } + private static final SpellAttribute SOAPINESS = SpellAttribute.create(SpellAttributes.SOAPINESS, AttributeFormat.REGULAR, Trait.POWER, power -> (int)(power * 2)); + + static final TooltipFactory TOOLTIP = TooltipFactory.of(TimedSpell.TIME, SOAPINESS); private final Timer timer; @@ -63,9 +63,9 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, protected BubbleSpell(CustomisedSpellType type) { super(type); - timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); + timer = new Timer(TIME.get(getTraits())); radius = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); - struggles = dataTracker.startTracking(TrackableDataType.INT, (int)(getTraits().get(Trait.POWER) * 2)); + struggles = dataTracker.startTracking(TrackableDataType.INT, SOAPINESS.get(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java index 760f222f..ac3040f5 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java @@ -1,9 +1,10 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; - import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; @@ -13,7 +14,6 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; -import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegate.HitListener { @@ -21,9 +21,9 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat .with(Trait.POWER, 1) .build(); - static void appendTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, (1 + type.relativeTraits().get(Trait.POWER)) * 10)); - } + private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.POWER, power -> (1 + power) * 10D); + + static final TooltipFactory TOOLTIP = RANGE; protected DispellEvilSpell(CustomisedSpellType type) { super(type); @@ -35,7 +35,7 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat return !isDead(); } - source.findAllEntitiesInRange((1 + getTraits().get(Trait.POWER)) * 10, e -> e.getType() == EntityType.PHANTOM).forEach(entity -> { + source.findAllEntitiesInRange(RANGE.get(getTraits()), e -> e.getType() == EntityType.PHANTOM).forEach(entity -> { entity.damage(entity.getDamageSources().magic(), 50); if (entity instanceof LivingEntity l) { double d = source.getOriginVector().getX() - entity.getX(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java index f67ceb2b..1e4bc8b6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java @@ -1,28 +1,27 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; - import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.util.shape.Sphere; -import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; /** * An area-effect spell that disperses illusions. */ public class DisperseIllusionSpell extends AbstractAreaEffectSpell { - public static void appendTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 15 + type.traits().get(Trait.POWER))); - tooltip.add(SpellAttributes.ofTime(SpellAttributes.DURATION, (1 + (long)type.traits().get(Trait.STRENGTH)) * 100)); - } + private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 15 + power)); + private static final SpellAttribute DURATION = SpellAttribute.create(SpellAttributes.DURATION, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> (1 + (long)strength) * 100); + static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, DURATION); protected DisperseIllusionSpell(CustomisedSpellType type) { super(type); @@ -31,7 +30,7 @@ public class DisperseIllusionSpell extends AbstractAreaEffectSpell { @Override public boolean tick(Caster source, Situation situation) { - float range = Math.max(0, 15 + getAdditionalRange()); + float range = RANGE.get(getTraits()); if (range == 0) { return false; @@ -50,7 +49,7 @@ public class DisperseIllusionSpell extends AbstractAreaEffectSpell { e.getSpellSlot().get(SpellPredicate.CAN_SUPPRESS) .filter(spell -> spell.isVulnerable(source, this)) .ifPresent(spell -> { - spell.onSuppressed(source, 100 * (1 + getTraits().get(Trait.STRENGTH))); + spell.onSuppressed(source, DURATION.get(getTraits())); e.playSound(USounds.SPELL_ILLUSION_DISPERSE, 0.2F, 0.5F); }); }); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java index 923701ce..3ea6df59 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java @@ -1,10 +1,11 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; - import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; @@ -13,18 +14,14 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import net.minecraft.entity.Entity; import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.Text; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.Vec3d; public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.EntityHitListener { - static void appendTooltip(CustomisedSpellType type, List tooltip) { - float damage = type.traits().get(Trait.BLOOD); - if (damage > 0) { - tooltip.add(SpellAttributes.ofRelative(SpellAttributes.DAMAGE_TO_TARGET, damage)); - } - } + private static final SpellAttribute DAMAGE_TO_TARGET = SpellAttribute.create(SpellAttributes.DAMAGE_TO_TARGET, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.BLOOD, blood -> blood); + + static final TooltipFactory TOOLTIP = DAMAGE_TO_TARGET; private final EntityReference target = new EntityReference<>(); @@ -81,7 +78,7 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro entity.setGlowing(false); entity.playSound(USounds.SPELL_DISPLACEMENT_TELEPORT, 1, 1); - float damage = getTraits().get(Trait.BLOOD); + float damage = DAMAGE_TO_TARGET.get(getTraits()); if (damage > 0) { entity.damage(source.damageOf(UDamageTypes.EXHAUSTION, source), damage); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java index 47bdf918..0821e0f3 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java @@ -1,12 +1,13 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; - import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; @@ -17,8 +18,8 @@ import net.minecraft.entity.Entity; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.predicate.entity.EntityPredicates; -import net.minecraft.text.Text; import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.math.MathHelper; public class FireBoltSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.ConfigurationListener, ProjectileDelegate.EntityHitListener { @@ -35,18 +36,14 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell, .with(Trait.FIRE, 60) .build(); - public static void appendTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.of(SpellAttributes.EXPLOSION_STRENGTH, type.traits().get(Trait.POWER, 0, type.traits().get(Trait.FOCUS) >= 50 ? 500 : 50) / 10F)); - tooltip.add(SpellAttributes.of(SpellAttributes.VELOCITY, 1.3F + type.traits().get(Trait.STRENGTH) / 11F)); - tooltip.add(SpellAttributes.of(SpellAttributes.PROJECTILE_COUNT, 1 + (int)type.traits().get(Trait.EARTH) * 3)); + private static final SpellAttribute VELOCITY = SpellAttribute.create(SpellAttributes.VELOCITY, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> 1.3F + (strength / 11F)); + private static final SpellAttribute PROJECTILE_COUNT = SpellAttribute.create(SpellAttributes.PROJECTILE_COUNT, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.EARTH, earth -> 11 + (int)earth * 3); + private static final SpellAttribute FOLLOWS_TARGET = SpellAttribute.createConditional(SpellAttributes.FOLLOWS_TARGET, Trait.FOCUS, focus -> focus >= 50); + private static final SpellAttribute FOLLOW_RANGE = SpellAttribute.create(SpellAttributes.FOLLOW_RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> Math.max(0F, focus - 49)); + private static final SpellAttribute MAX_EXPLOSION_STRENGTH = SpellAttribute.create(SpellAttributes.EXPLOSION_STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> focus >= 50 ? 10F : 1F); + private static final SpellAttribute EXPLOSION_STRENGTH = SpellAttribute.create(SpellAttributes.EXPLOSION_STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, (traits, focus) -> MathHelper.clamp(focus / 50, 0, MAX_EXPLOSION_STRENGTH.get(traits))); - float homingRange = type.traits().get(Trait.FOCUS); - - if (homingRange >= 50) { - tooltip.add(SpellAttributes.FOLLOWS_TARGET); - tooltip.add(SpellAttributes.of(SpellAttributes.FOLLOW_RANGE, homingRange - 50)); - } - } + static final TooltipFactory TOOLTIP = TooltipFactory.of(MAX_EXPLOSION_STRENGTH, EXPLOSION_STRENGTH, VELOCITY, PROJECTILE_COUNT, FOLLOWS_TARGET, FOLLOW_RANGE.conditionally(FOLLOWS_TARGET::get)); private final EntityReference target = new EntityReference<>(); @@ -61,10 +58,12 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell, @Override public boolean tick(Caster caster, Situation situation) { + boolean followTarget = FOLLOWS_TARGET.get(getTraits()); + float followRage = FOLLOW_RANGE.get(getTraits()); if (situation == Situation.PROJECTILE) { - if (caster instanceof MagicProjectileEntity projectile && getTraits().get(Trait.FOCUS) >= 50) { + if (caster instanceof MagicProjectileEntity projectile && followTarget) { caster.findAllEntitiesInRange( - getTraits().get(Trait.FOCUS) - 49, + followRage, EntityPredicates.VALID_LIVING_ENTITY.and(TargetSelecter.validTarget(this, caster)) ).findFirst().ifPresent(target -> projectile.setHomingTarget(target)); } @@ -72,9 +71,9 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell, return true; } - if (getTraits().get(Trait.FOCUS) >= 50 && target.getOrEmpty(caster.asWorld()).isEmpty()) { + if (followTarget && target.getOrEmpty(caster.asWorld()).isEmpty()) { target.set(caster.findAllEntitiesInRange( - getTraits().get(Trait.FOCUS) - 49, + followRage, EntityPredicates.VALID_LIVING_ENTITY.and(TargetSelecter.validTarget(this, caster)) ).findFirst().orElse(null)); } @@ -92,18 +91,18 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell, @Override public void configureProjectile(MagicProjectileEntity projectile, Caster caster) { projectile.setItem(Items.FIRE_CHARGE.getDefaultStack()); - projectile.addThrowDamage(getTraits().get(Trait.POWER, 0, getTraits().get(Trait.FOCUS) >= 50 ? 500 : 50) / 10F); + projectile.addThrowDamage(EXPLOSION_STRENGTH.get(getTraits())); projectile.setFireTicks(900000); - projectile.setVelocity(projectile.getVelocity().multiply(1.3 + getTraits().get(Trait.STRENGTH) / 11F)); + projectile.setVelocity(projectile.getVelocity().multiply(VELOCITY.get(getTraits()))); } protected int getNumberOfBalls(Caster caster) { - return 1 + caster.asWorld().random.nextInt(3) + (int)getTraits().get(Trait.EARTH) * 3; + return PROJECTILE_COUNT.get(getTraits()) + caster.asWorld().random.nextInt(3); } @Override public boolean setTarget(Entity target) { - if (getTraits().get(Trait.FOCUS) >= 50) { + if (FOLLOWS_TARGET.get(getTraits())) { this.target.set(target); return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireSpell.java index f633c952..d7b9568c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireSpell.java @@ -1,12 +1,9 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; - import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -28,7 +25,6 @@ import net.minecraft.entity.damage.DamageTypes; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.particle.ParticleTypes; import net.minecraft.sound.SoundCategory; -import net.minecraft.text.Text; import net.minecraft.registry.tag.BlockTags; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; @@ -45,10 +41,6 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele .with(Trait.FIRE, 15) .build(); - public static void appendTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); - } - protected FireSpell(CustomisedSpellType type) { super(type); } @@ -75,14 +67,14 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele generateParticles(source); } - return new Sphere(false, Math.max(0, 4 + getAdditionalRange())).translate(source.getOrigin()).getBlockPositions().reduce(false, + return new Sphere(false, RANGE.get(getTraits())).translate(source.getOrigin()).getBlockPositions().reduce(false, (r, i) -> source.canModifyAt(i) && applyBlocks(source.asWorld(), i), (a, b) -> a || b) || applyEntities(source, source.getOriginVector()); } protected void generateParticles(Caster source) { - source.spawnParticles(new Sphere(false, Math.max(0, 4 + getAdditionalRange())), (int)(1 + source.getLevel().getScaled(8)) * 6, pos -> { + source.spawnParticles(new Sphere(false, RANGE.get(getTraits())), (int)(1 + source.getLevel().getScaled(8)) * 6, pos -> { source.addParticle(ParticleTypes.LARGE_SMOKE, pos, Vec3d.ZERO); }); } @@ -129,8 +121,12 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele return false; } + protected float getEntityEffectRange() { + return Math.max(0, RANGE.get(getTraits()) - 1); + } + protected boolean applyEntities(Caster source, Vec3d pos) { - return source.findAllEntitiesInRange(Math.max(0, 3 + getAdditionalRange()), e -> { + return source.findAllEntitiesInRange(getEntityEffectRange(), e -> { LivingEntity master = source.getMaster(); return (!(e.equals(source.asEntity()) || e.equals(master)) || (master instanceof PlayerEntity && !EquinePredicates.PLAYER_UNICORN.test(master))) && !(e instanceof ItemEntity) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java index 6ec3554e..cd6a198c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/HydrophobicSpell.java @@ -1,7 +1,6 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; import java.util.HashSet; -import java.util.List; import java.util.Set; import com.minelittlepony.unicopia.USounds; @@ -9,7 +8,8 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.CastOn; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.advancement.UCriteria; @@ -24,7 +24,6 @@ import net.minecraft.block.*; import net.minecraft.fluid.*; import net.minecraft.nbt.*; import net.minecraft.state.property.Properties; -import net.minecraft.text.Text; import net.minecraft.registry.tag.TagKey; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; @@ -37,10 +36,8 @@ public class HydrophobicSpell extends AbstractSpell { .with(Trait.FOCUS, 5) .with(Trait.KNOWLEDGE, 1) .build(); - static void appendTooltip(CustomisedSpellType type, List tooltip) { - ShieldSpell.appendCastLocationTooltip(type, tooltip); - tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); - } + + static final TooltipFactory TOOLTIP = TooltipFactory.of(ShieldSpell.CAST_ON, ShieldSpell.RANGE); private final TagKey affectedFluid; @@ -53,7 +50,7 @@ public class HydrophobicSpell extends AbstractSpell { @Override public Spell prepareForCast(Caster caster, CastingMethod method) { - if ((method == CastingMethod.DIRECT || method == CastingMethod.STAFF) && getTraits().get(Trait.GENEROSITY) > 0) { + if ((method == CastingMethod.DIRECT || method == CastingMethod.STAFF) && ShieldSpell.CAST_ON.get(getTraits()) == CastOn.LOCATION) { return toPlaceable(); } return this; @@ -148,7 +145,7 @@ public class HydrophobicSpell extends AbstractSpell { */ public double getRange(Caster source) { float multiplier = 1; - float min = (source instanceof Pony ? 4 : 6) + getTraits().get(Trait.POWER); + float min = (source instanceof Pony ? 0 : 2) + ShieldSpell.RANGE.get(getTraits()); boolean isLimitedRange = source instanceof Pony || source instanceof MagicProjectileEntity; double range = (min + (source.getLevel().getScaled(isLimitedRange ? 4 : 40) * (isLimitedRange ? 2 : 10))) / multiplier; return range; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java index f5065ff2..ae4cf7d7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java @@ -5,6 +5,10 @@ import java.util.List; import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.block.state.StateMaps; @@ -12,7 +16,6 @@ import com.minelittlepony.unicopia.block.state.StatePredicate; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.VecHelper; -import com.minelittlepony.unicopia.util.shape.Shape; import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.block.*; @@ -33,8 +36,9 @@ public class IceSpell extends AbstractSpell { .with(Trait.ICE, 15) .build(); - private static final int RADIUS = 3; - private static final Shape OUTER_RANGE = new Sphere(false, RADIUS); + private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 3 + power)); + + static final TooltipFactory TOOLTIP = RANGE; protected IceSpell(CustomisedSpellType type) { super(type); @@ -43,11 +47,12 @@ public class IceSpell extends AbstractSpell { @Override public boolean tick(Caster source, Situation situation) { boolean submerged = source.asEntity().isSubmergedInWater() || source.asEntity().isSubmergedIn(FluidTags.LAVA); + float radius = RANGE.get(getTraits()); - long blocksAffected = OUTER_RANGE.translate(source.getOrigin()).getBlockPositions().filter(i -> { + long blocksAffected = new Sphere(false, radius).translate(source.getOrigin()).getBlockPositions().filter(i -> { if (source.canModifyAt(i) && applyBlockSingle(source.asEntity(), source.asWorld(), i, situation)) { - if (submerged & source.getOrigin().isWithinDistance(i, RADIUS - 1)) { + if (submerged & source.getOrigin().isWithinDistance(i, RANGE.get(getTraits()) - 1)) { BlockState state = source.asWorld().getBlockState(i); if (state.isIn(BlockTags.ICE) || state.isOf(Blocks.OBSIDIAN)) { source.asWorld().setBlockState(i, Blocks.AIR.getDefaultState(), Block.NOTIFY_NEIGHBORS); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java index 6825df24..0d96a52b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java @@ -8,6 +8,9 @@ import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; @@ -21,7 +24,7 @@ import com.minelittlepony.unicopia.util.VecHelper; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; -import net.minecraft.text.Text; +import net.minecraft.util.math.MathHelper; public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileDelegate.HitListener { public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() @@ -31,10 +34,9 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD .with(Trait.ORDER, 25) .build(); - public static void appendTooltip(CustomisedSpellType type, List tooltip) { - TimedSpell.appendDurationTooltip(type, tooltip); - tooltip.add(SpellAttributes.of(SpellAttributes.ORB_COUNT, 2 + (int)(type.relativeTraits().get(Trait.LIFE, 10, 20) / 10F))); - } + private static final SpellAttribute ORB_COUNT = SpellAttribute.create(SpellAttributes.ORB_COUNT, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.LIFE, life -> 2 + (int)(MathHelper.clamp(life, 10, 20) / 10F)); + + static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, ORB_COUNT); private final Timer timer; @@ -42,7 +44,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD protected LightSpell(CustomisedSpellType type) { super(type); - timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); + timer = new Timer(TIME.get(getTraits())); } @Override @@ -65,7 +67,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD if (!caster.isClient()) { if (lights.isEmpty()) { - int size = 2 + caster.asWorld().random.nextInt(2) + (int)(getTraits().get(Trait.LIFE, 10, 20) - 10)/10; + int size = caster.asWorld().random.nextInt(2) + ORB_COUNT.get(getTraits()); while (lights.size() < size) { lights.add(new EntityReference<>()); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java index 0e599e8d..57b984c1 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java @@ -1,25 +1,21 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; - import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; + import net.minecraft.entity.Entity; import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.Text; public class MimicSpell extends AbstractDisguiseSpell implements HomingSpell, TimedSpell { - static final int BASE_DURATION = 120 * 20; - public static void appendTooltip(CustomisedSpellType type, List tooltip) { - TimedSpell.appendDurationTooltip(type, tooltip); - } + static final TooltipFactory TOOLTIP = TimedSpell.TIME; private final Timer timer; protected MimicSpell(CustomisedSpellType type) { super(type); - timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); + timer = new Timer(TIME.get(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java index c2063211..00401bdb 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java @@ -9,6 +9,9 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.EntityReference; @@ -32,7 +35,6 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; import net.minecraft.particle.ParticleTypes; -import net.minecraft.text.Text; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.BlockPos; @@ -81,10 +83,8 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti return e -> e.getType() == type; } - static void appendTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); - tooltip.add(SpellAttributes.of(SpellAttributes.WAVE_SIZE, 10 + (int)type.traits().get(Trait.CHAOS, 0, 10))); - } + static final SpellAttribute WAVE_SIZE = SpellAttribute.create(SpellAttributes.WAVE_SIZE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.CHAOS, chaos -> 10 + (int)MathHelper.clamp(chaos, 0, 10)); + static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, WAVE_SIZE); private final List> summonedEntities = new ArrayList<>(); @@ -97,7 +97,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti @Override public boolean tick(Caster source, Situation situation) { - float radius = 4 + source.getLevel().getScaled(4) * 4 + getAdditionalRange(); + float radius = source.getLevel().getScaled(4) * 4 + RANGE.get(getTraits()); if (radius <= 0) { return false; @@ -129,14 +129,16 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti return true; }).isEmpty()); - float additional = source.asWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty() + getTraits().get(Trait.CHAOS, 0, 10); - if (--spawnCountdown > 0 && !summonedEntities.isEmpty()) { return true; } + // TODO: refactory speed attribute + // TODO: weather resistant attribute spawnCountdown = 1200 + source.asWorld().random.nextInt(rainy ? 2000 : 1000); - if (summonedEntities.size() > 10 + additional) { + float additional = source.asWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty() + WAVE_SIZE.get(getTraits()); + + if (summonedEntities.size() > additional) { return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ScorchSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ScorchSpell.java index e64aa6fa..d4292c7c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ScorchSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ScorchSpell.java @@ -36,7 +36,7 @@ public class ScorchSpell extends FireSpell implements ProjectileDelegate.Configu BlockPos pos = PosHelper.findSolidGroundAt(source.asWorld(), source.getOrigin(), source.getPhysics().getGravitySignum()); if (source.canModifyAt(pos) && StateMaps.FIRE_AFFECTED.convert(source.asWorld(), pos)) { - source.spawnParticles(new Sphere(false, Math.max(1, getAdditionalRange())), 5, p -> { + source.spawnParticles(new Sphere(false, RANGE.get(getTraits())), 5, p -> { source.addParticle(ParticleTypes.SMOKE, PosHelper.offset(p, pos), Vec3d.ZERO); }); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java index 705fb4b0..b95f344a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java @@ -1,17 +1,19 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; import java.util.Optional; import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.CastOn; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; @@ -38,7 +40,6 @@ import net.minecraft.entity.passive.PassiveEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity; import net.minecraft.entity.vehicle.BoatEntity; -import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -50,31 +51,18 @@ public class ShieldSpell extends AbstractSpell { .with(Trait.AIR, 9) .build(); - static void appendTooltip(CustomisedSpellType type, List tooltip) { - AbstractAreaEffectSpell.appendRangeTooltip(type, tooltip); - appendValidTargetsTooltip(type, tooltip); - appendCastLocationTooltip(type, tooltip); - } + static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power)); + protected static final SpellAttribute CAST_ON = SpellAttribute.createEnumerated(SpellAttributes.CAST_ON, Trait.GENEROSITY, generosity -> generosity > 0 ? CastOn.LOCATION : CastOn.SELF); - static void appendValidTargetsTooltip(CustomisedSpellType type, List tooltip) { - if (type.traits().get(Trait.KNOWLEDGE) > 10) { - tooltip.add(SpellAttributes.PERMIT_ITEMS); - } else { - if (type.traits().get(Trait.LIFE) > 0) { - tooltip.add(SpellAttributes.PERMIT_PASSIVE); - } - if (type.traits().get(Trait.BLOOD) > 0) { - tooltip.add(SpellAttributes.PERMIT_HOSTILE); - } - if (type.traits().get(Trait.ICE) > 0) { - tooltip.add(SpellAttributes.PERMIT_PLAYER); - } - } - } + static final SpellAttribute TARGET_ITEMS = SpellAttribute.createConditional(SpellAttributes.PERMIT_ITEMS, Trait.KNOWLEDGE, knowledge -> knowledge > 10); + static final SpellAttribute PERMIT_PASSIVE = SpellAttribute.createConditional(SpellAttributes.PERMIT_PASSIVE, Trait.LIFE, l -> l > 0); + static final SpellAttribute PERMIT_HOSTILE = SpellAttribute.createConditional(SpellAttributes.PERMIT_HOSTILE, Trait.BLOOD, l -> l > 0); + static final SpellAttribute PERMIT_PLAYER = SpellAttribute.createConditional(SpellAttributes.PERMIT_PLAYER, Trait.ICE, l -> l > 0); - static void appendCastLocationTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(type.traits().get(Trait.GENEROSITY) > 0 ? SpellAttributes.CAST_ON_LOCATION : SpellAttributes.CAST_ON_PERSON); - } + static final TooltipFactory PERMIT_ENTITY = TooltipFactory.of(PERMIT_PASSIVE, PERMIT_HOSTILE, PERMIT_PLAYER); + static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_ITEMS.get(type.traits()) ? TARGET_ITEMS : PERMIT_ENTITY).appendTooltip(type, tooltip); + + static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, TARGET, CAST_ON); protected final TargetSelecter targetSelecter = new TargetSelecter(this).setFilter(this::isValidTarget); @@ -90,7 +78,7 @@ public class ShieldSpell extends AbstractSpell { @Override public Spell prepareForCast(Caster caster, CastingMethod method) { - return method == CastingMethod.STAFF || getTraits().get(Trait.GENEROSITY) > 0 ? toPlaceable() : this; + return method == CastingMethod.STAFF || CAST_ON.get(getTraits()) == CastOn.LOCATION ? toPlaceable() : this; } @Override @@ -176,7 +164,7 @@ public class ShieldSpell extends AbstractSpell { * Calculates the maximum radius of the shield. aka The area of effect. */ public double getDrawDropOffRange(Caster source) { - float min = (source instanceof Pony ? 4 : 6) + getTraits().get(Trait.POWER); + float min = (source instanceof Pony ? 0 : 2) + RANGE.get(getTraits()); double range = (min + (source.getLevel().getScaled(source instanceof Pony ? 4 : 40) * (source instanceof Pony ? 2 : 10))) / rangeMultiplier.getValue(); return range; @@ -184,7 +172,7 @@ public class ShieldSpell extends AbstractSpell { protected boolean isValidTarget(Caster source, Entity entity) { - if (getTraits().get(Trait.KNOWLEDGE) > 10) { + if (TARGET_ITEMS.get(getTraits())) { return entity instanceof ItemEntity; } @@ -198,13 +186,13 @@ public class ShieldSpell extends AbstractSpell { || entity instanceof BoatEntity ); - if (getTraits().get(Trait.LIFE) > 0) { + if (PERMIT_PASSIVE.get(getTraits())) { valid &= !(entity instanceof PassiveEntity); } - if (getTraits().get(Trait.BLOOD) > 0) { + if (PERMIT_HOSTILE.get(getTraits())) { valid &= !(entity instanceof HostileEntity); } - if (getTraits().get(Trait.ICE) > 0) { + if (PERMIT_PLAYER.get(getTraits())) { valid &= !(entity instanceof PlayerEntity); } return valid; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java index a7e1cbfd..d844c066 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SiphoningSpell.java @@ -12,7 +12,6 @@ import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.player.Pony; @@ -31,7 +30,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; import net.minecraft.predicate.entity.EntityPredicates; -import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -41,10 +39,6 @@ import net.minecraft.util.math.Vec3d; public class SiphoningSpell extends AbstractAreaEffectSpell { static final Predicate TARGET_PREDICATE = EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.and(EntityPredicates.VALID_LIVING_ENTITY); - static void appendTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4)); - } - private final DataTracker.Entry upset = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private int ticksUpset; @@ -65,7 +59,7 @@ public class SiphoningSpell extends AbstractAreaEffectSpell { } if (source.isClient()) { - float radius = 4 + source.getLevel().getScaled(5) + getAdditionalRange(); + float radius = source.getLevel().getScaled(5) + RANGE.get(getTraits()); int direction = isFriendlyTogether(source) ? 1 : -1; source.spawnParticles(new Sphere(true, radius, 1, 0, 1), 1, pos -> { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index 9ae37a33..0ca190f8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -9,6 +9,7 @@ import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; +import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell; import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell; @@ -17,6 +18,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.RageAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell; import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.UItems; @@ -53,31 +55,31 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType RAGE = register("rage", builder(RageAbilitySpell::new).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.FLAME)); public static final SpellType TIME_CONTROL = register("time_control", builder(TimeControlAbilitySpell::new).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.STAR)); - public static final SpellType FROST = register("frost", builder(IceSpell::new).color(0xEABBFF).shape(GemstoneItem.Shape.TRIANGLE).traits(IceSpell.DEFAULT_TRAITS)); + public static final SpellType FROST = register("frost", builder(IceSpell::new).color(0xEABBFF).shape(GemstoneItem.Shape.TRIANGLE).traits(IceSpell.DEFAULT_TRAITS).tooltip(IceSpell.TOOLTIP)); public static final SpellType CHILLING_BREATH = register("chilling_breath", builder(ChillingBreathSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEAFF).shape(GemstoneItem.Shape.TRIANGLE).traits(ChillingBreathSpell.DEFAULT_TRAITS)); - public static final SpellType SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).stackable().shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip)); - public static final SpellType FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip)); - public static final SpellType INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip)); - public static final SpellType SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS).tooltip(ShieldSpell::appendTooltip)); - public static final SpellType ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS).tooltip(AreaProtectionSpell::appendTooltip)); - public static final SpellType VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS).tooltip(AttractiveSpell::appendTooltip2)); + public static final SpellType SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).stackable().shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS).tooltip(AbstractAreaEffectSpell.TOOLTIP)); + public static final SpellType FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS).tooltip(AbstractAreaEffectSpell.TOOLTIP)); + public static final SpellType INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS).tooltip(AbstractAreaEffectSpell.TOOLTIP)); + public static final SpellType SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS).tooltip(ShieldSpell.TOOLTIP)); + public static final SpellType ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS).tooltip(AreaProtectionSpell.TOOLTIP)); + public static final SpellType VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS).tooltip(AttractiveSpell.TOOLTIP)); public static final SpellType DARK_VORTEX = register("dark_vortex", builder(DarkVortexSpell::new).affinity(Affinity.BAD).color(0xA33333).stackable().shape(GemstoneItem.Shape.VORTEX).traits(DarkVortexSpell.DEFAULT_TRAITS)); - public static final SpellType NECROMANCY = register("necromancy", builder(NecromancySpell::new).affinity(Affinity.BAD).color(0xFA3A3A).shape(GemstoneItem.Shape.SKULL).tooltip(NecromancySpell::appendTooltip)); - public static final SpellType SIPHONING = register("siphoning", builder(SiphoningSpell::new).affinity(Affinity.NEUTRAL).color(0xFFA3AA).shape(GemstoneItem.Shape.LAMBDA).tooltip(SiphoningSpell::appendTooltip)); - public static final SpellType REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS).tooltip(DisperseIllusionSpell::appendTooltip)); + public static final SpellType NECROMANCY = register("necromancy", builder(NecromancySpell::new).affinity(Affinity.BAD).color(0xFA3A3A).shape(GemstoneItem.Shape.SKULL).tooltip(NecromancySpell.TOOLTIP)); + public static final SpellType SIPHONING = register("siphoning", builder(SiphoningSpell::new).affinity(Affinity.NEUTRAL).color(0xFFA3AA).shape(GemstoneItem.Shape.LAMBDA).tooltip(AbstractAreaEffectSpell.TOOLTIP)); + public static final SpellType REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS).tooltip(DisperseIllusionSpell.TOOLTIP)); public static final SpellType AWKWARD = register("awkward", builder(AwkwardSpell::new).affinity(Affinity.NEUTRAL).color(0x3A59FF).shape(GemstoneItem.Shape.ICE)); public static final SpellType TRANSFORMATION = register("transformation", builder(TransformationSpell::new).color(0x19E48E).shape(GemstoneItem.Shape.BRUSH)); public static final SpellType FEATHER_FALL = register("feather_fall", builder(FeatherFallSpell::new).color(0x00EEFF).shape(GemstoneItem.Shape.LAMBDA).traits(FeatherFallSpell.DEFAULT_TRAITS).tooltip(FeatherFallSpell::appendTooltip)); - public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS).tooltip(CatapultSpell.TOOLTIP::appendTooltip)); - public static final SpellType FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS).tooltip(FireBoltSpell::appendTooltip)); - public static final SpellType LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS).tooltip(LightSpell::appendTooltip)); - public static final SpellType DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).stackable().shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS).tooltip(DisplacementSpell::appendTooltip)); + public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS).tooltip(CatapultSpell.TOOLTIP)); + public static final SpellType FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS).tooltip(FireBoltSpell.TOOLTIP)); + public static final SpellType LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS).tooltip(LightSpell.TOOLTIP)); + public static final SpellType DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).stackable().shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS).tooltip(DisplacementSpell.TOOLTIP)); public static final SpellType PORTAL = register("portal", builder(PortalSpell::new).color(0x99FFFF).shape(GemstoneItem.Shape.RING).traits(PortalSpell.DEFAULT_TRAITS)); - public static final SpellType MIMIC = register("mimic", builder(MimicSpell::new).color(0xFFFF00).shape(GemstoneItem.Shape.ARROW).tooltip(MimicSpell::appendTooltip)); - public static final SpellType MIND_SWAP = register("mind_swap", builder(MindSwapSpell::new).affinity(Affinity.BAD).color(0xF9FF99).shape(GemstoneItem.Shape.WAVE).tooltip(MimicSpell::appendTooltip)); - public static final SpellType HYDROPHOBIC = register("hydrophobic", SpellType.builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).stackable().shape(GemstoneItem.Shape.ROCKET).tooltip(HydrophobicSpell::appendTooltip)); - public static final SpellType BUBBLE = register("bubble", builder(BubbleSpell::new).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.DONUT).traits(BubbleSpell.DEFAULT_TRAITS).tooltip(BubbleSpell::appendTooltip)); - public static final SpellType DISPEL_EVIL = register("dispel_evil", builder(DispellEvilSpell::new).color(0x00FF00).shape(GemstoneItem.Shape.CROSS).traits(DispellEvilSpell.DEFAULT_TRAITS).tooltip(DispellEvilSpell::appendTooltip)); + public static final SpellType MIMIC = register("mimic", builder(MimicSpell::new).color(0xFFFF00).shape(GemstoneItem.Shape.ARROW).tooltip(MimicSpell.TOOLTIP)); + public static final SpellType MIND_SWAP = register("mind_swap", builder(MindSwapSpell::new).affinity(Affinity.BAD).color(0xF9FF99).shape(GemstoneItem.Shape.WAVE).tooltip(MimicSpell.TOOLTIP)); + public static final SpellType HYDROPHOBIC = register("hydrophobic", SpellType.builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).stackable().shape(GemstoneItem.Shape.ROCKET).tooltip(HydrophobicSpell.TOOLTIP)); + public static final SpellType BUBBLE = register("bubble", builder(BubbleSpell::new).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.DONUT).traits(BubbleSpell.DEFAULT_TRAITS).tooltip(BubbleSpell.TOOLTIP)); + public static final SpellType DISPEL_EVIL = register("dispel_evil", builder(DispellEvilSpell::new).color(0x00FF00).shape(GemstoneItem.Shape.CROSS).traits(DispellEvilSpell.DEFAULT_TRAITS).tooltip(DispellEvilSpell.TOOLTIP)); public static void bootstrap() {} @@ -274,6 +276,12 @@ public final class SpellType implements Affine, SpellPredicate< return this; } + public Builder tooltip(TooltipFactory tooltipFunction) { + this.tooltipFunction = tooltipFunction::appendTooltip; + return this; + } + + @Deprecated public Builder tooltip(BiConsumer, List> tooltipFunction) { this.tooltipFunction = tooltipFunction; return this; From 4dd3b2fb2671285352d9963f5e1630f2a630b246 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 22 Jun 2024 18:29:44 +0100 Subject: [PATCH 75/85] Fixed error when applying the bubble spell to entities --- .../unicopia/ability/magic/spell/effect/BubbleSpell.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index f63f575c..1e93a979 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -88,7 +88,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, if (entity instanceof LivingEntity l) { MODIFIERS.forEach((attribute, modifier) -> { - if (l.getAttributes().hasAttribute(attribute)) { + if (!l.getAttributes().hasAttribute(attribute)) { l.getAttributeInstance(attribute).addPersistentModifier(modifier); } }); From b30e9c5f1f9a5eec591be59c7b1c4f7b42cd6613 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 22 Jun 2024 18:48:50 +0100 Subject: [PATCH 76/85] Move entity attribute stuff to a separate class --- .../magic/spell/effect/BubbleSpell.java | 18 ++--- .../unicopia/entity/AttributeContainer.java | 71 +++++++++++++++++++ .../unicopia/entity/Living.java | 30 ++------ .../unicopia/item/AlicornAmuletItem.java | 11 +-- 4 files changed, 87 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/AttributeContainer.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index 1e93a979..abeedff2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.*; +import com.minelittlepony.unicopia.entity.AttributeContainer; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.network.track.DataTracker; @@ -22,7 +23,6 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; import net.minecraft.entity.attribute.*; import net.minecraft.entity.attribute.EntityAttributeModifier.Operation; import net.minecraft.nbt.NbtCompound; @@ -86,12 +86,8 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, Entity entity = source.asEntity(); - if (entity instanceof LivingEntity l) { - MODIFIERS.forEach((attribute, modifier) -> { - if (!l.getAttributes().hasAttribute(attribute)) { - l.getAttributeInstance(attribute).addPersistentModifier(modifier); - } - }); + if (source instanceof AttributeContainer l) { + l.applyAttributeModifiers(MODIFIERS, false, true); } radius.set(Math.max(entity.getHeight(), entity.getWidth()) * 1.2F); source.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1); @@ -148,12 +144,8 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, @Override protected void onDestroyed(Caster source) { super.onDestroyed(source); - if (source.asEntity() instanceof LivingEntity l) { - MODIFIERS.forEach((attribute, modifier) -> { - if (l.getAttributes().hasAttribute(attribute)) { - l.getAttributeInstance(attribute).removeModifier(modifier); - } - }); + if (source instanceof AttributeContainer l) { + l.applyAttributeModifiers(MODIFIERS, false, false); } source.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/AttributeContainer.java b/src/main/java/com/minelittlepony/unicopia/entity/AttributeContainer.java new file mode 100644 index 00000000..8f94a440 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/AttributeContainer.java @@ -0,0 +1,71 @@ +package com.minelittlepony.unicopia.entity; + +import java.util.Map; +import java.util.UUID; + +import org.jetbrains.annotations.Nullable; + +import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; +import net.minecraft.entity.attribute.EntityAttribute; +import net.minecraft.entity.attribute.EntityAttributeInstance; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.util.math.MathHelper; + +public interface AttributeContainer { + @Nullable + EntityAttributeInstance getAttributeInstance(EntityAttribute attribute); + + default void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction modifierSupplier, boolean permanent) { + @Nullable + EntityAttributeInstance instance = getAttributeInstance(attribute); + if (instance == null) { + return; + } + + @Nullable + EntityAttributeModifier modifier = instance.getModifier(id); + + if (!MathHelper.approximatelyEquals(desiredValue, modifier == null ? 0 : modifier.getValue())) { + if (modifier != null) { + instance.removeModifier(modifier); + } + + if (desiredValue != 0) { + if (permanent) { + instance.addPersistentModifier(modifierSupplier.get(desiredValue)); + } else { + instance.addTemporaryModifier(modifierSupplier.get(desiredValue)); + } + } + } + } + + default void applyAttributeModifiers(Map modifiers, boolean permanent, boolean apply) { + modifiers.forEach((attribute, modifier) -> { + applyAttributeModifier(attribute, modifier, permanent, apply); + }); + } + + default void applyAttributeModifier(EntityAttribute attribute, EntityAttributeModifier modifier, boolean permanent, boolean apply) { + @Nullable + EntityAttributeInstance instance = getAttributeInstance(attribute); + if (instance == null) { + return; + } + + @Nullable + boolean present = instance.hasModifier(modifier); + + if (present != apply) { + if (apply) { + if (permanent) { + instance.addPersistentModifier(modifier); + } else { + instance.addTemporaryModifier(modifier); + } + } else { + instance.removeModifier(modifier); + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index f5c82baf..ba453869 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -40,7 +40,6 @@ import com.minelittlepony.unicopia.projectile.ProjectileImpactListener; import com.minelittlepony.unicopia.server.world.DragonBreathStore; import com.minelittlepony.unicopia.util.*; -import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.BlockState; import net.minecraft.enchantment.Enchantment; @@ -48,7 +47,6 @@ import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.*; import net.minecraft.entity.attribute.EntityAttribute; import net.minecraft.entity.attribute.EntityAttributeInstance; -import net.minecraft.entity.attribute.EntityAttributeModifier; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageTypes; import net.minecraft.entity.mob.HostileEntity; @@ -73,7 +71,7 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -public abstract class Living implements Equine, Caster { +public abstract class Living implements Equine, Caster, AttributeContainer { protected final T entity; private final SpellInventory spells; @@ -253,29 +251,9 @@ public abstract class Living implements Equine, Caste transportation.tick(); } - public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction modifierSupplier, boolean permanent) { - @Nullable - EntityAttributeInstance instance = asEntity().getAttributeInstance(attribute); - if (instance == null) { - return; - } - - @Nullable - EntityAttributeModifier modifier = instance.getModifier(id); - - if (!MathHelper.approximatelyEquals(desiredValue, modifier == null ? 0 : modifier.getValue())) { - if (modifier != null) { - instance.removeModifier(modifier); - } - - if (desiredValue != 0) { - if (permanent) { - instance.addPersistentModifier(modifierSupplier.get(desiredValue)); - } else { - instance.addTemporaryModifier(modifierSupplier.get(desiredValue)); - } - } - } + @Override + public final @Nullable EntityAttributeInstance getAttributeInstance(EntityAttribute attribute) { + return asEntity().getAttributeInstance(attribute); } public boolean canBeSeenBy(Entity entity) { diff --git a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java index ea861cb0..f3c16ffa 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java @@ -23,6 +23,9 @@ import com.minelittlepony.unicopia.server.world.UnicopiaWorldProperties; import com.minelittlepony.unicopia.util.VecHelper; import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; +import it.unimi.dsi.fastutil.objects.Object2FloatMap; +import it.unimi.dsi.fastutil.objects.Object2FloatMaps; +import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.item.v1.FabricItemSettings; @@ -56,13 +59,13 @@ import net.minecraft.world.World.ExplosionSourceType; public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackable, ItemImpl.ClingyItem, ItemImpl.GroundTickCallback { private static final UUID EFFECT_UUID = UUID.fromString("c0a870f5-99ef-4716-a23e-f320ee834b26"); - private static final Map EFFECT_SCALES = Map.of( + private static final Object2FloatMap EFFECT_SCALES = Object2FloatMaps.unmodifiable(new Object2FloatOpenHashMap<>(Map.of( EntityAttributes.GENERIC_ATTACK_DAMAGE, 0.2F, EntityAttributes.GENERIC_ATTACK_KNOCKBACK, 0.05F, EntityAttributes.GENERIC_ATTACK_SPEED, 0.2F, EntityAttributes.GENERIC_ARMOR_TOUGHNESS, 0.001F, EntityAttributes.GENERIC_ARMOR, 0.01F - ); + ))); private static final Float2ObjectFunction EFFECT_FACTORY = v -> { return new EntityAttributeModifier(EFFECT_UUID, "Alicorn Amulet Modifier", v, EntityAttributeModifier.Operation.ADDITION); }; @@ -173,8 +176,8 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab } public static void updateAttributes(Living wearer, float effectScale) { - EFFECT_SCALES.entrySet().forEach(attribute -> { - wearer.updateAttributeModifier(EFFECT_UUID, attribute.getKey(), attribute.getValue() * effectScale, EFFECT_FACTORY, false); + EFFECT_SCALES.object2FloatEntrySet().forEach(entry -> { + wearer.updateAttributeModifier(EFFECT_UUID, entry.getKey(), entry.getFloatValue() * effectScale, EFFECT_FACTORY, false); }); } From 9ee81c961c33d28da8c244aac09be1873d59b0e1 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 22 Jun 2024 19:40:49 +0100 Subject: [PATCH 77/85] Finish porting spell attributes to the new system --- .../magic/spell/AbstractAreaEffectSpell.java | 3 +- .../ability/magic/spell/SpellAttributes.java | 83 ------------------- .../ability/magic/spell/TimedSpell.java | 3 +- .../spell/attribute/AttributeFormat.java | 2 +- .../magic/spell/attribute/SpellAttribute.java | 29 +++---- .../spell/attribute/SpellAttributeType.java | 59 +++++++++++++ .../magic/spell/attribute/TooltipFactory.java | 2 + .../spell/effect/AreaProtectionSpell.java | 16 ++-- .../magic/spell/effect/AttractiveSpell.java | 5 +- .../magic/spell/effect/BubbleSpell.java | 3 +- .../magic/spell/effect/CatapultSpell.java | 12 +-- .../spell/effect/CustomisedSpellType.java | 2 +- .../magic/spell/effect/DispellEvilSpell.java | 3 +- .../spell/effect/DisperseIllusionSpell.java | 6 +- .../magic/spell/effect/DisplacementSpell.java | 3 +- .../magic/spell/effect/FeatherFallSpell.java | 75 ++++++++--------- .../magic/spell/effect/FireBoltSpell.java | 14 ++-- .../ability/magic/spell/effect/IceSpell.java | 4 +- .../magic/spell/effect/LightSpell.java | 4 +- .../magic/spell/effect/NecromancySpell.java | 4 +- .../magic/spell/effect/ShieldSpell.java | 14 ++-- .../ability/magic/spell/effect/SpellType.java | 18 ++-- .../resources/assets/unicopia/lang/en_us.json | 6 +- 23 files changed, 172 insertions(+), 198 deletions(-) delete mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttributeType.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java index edf19a17..1425a6ae 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java @@ -3,12 +3,13 @@ package com.minelittlepony.unicopia.ability.magic.spell; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.effect.*; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; public abstract class AbstractAreaEffectSpell extends AbstractSpell { - protected static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power)); + protected static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power)); public static final TooltipFactory TOOLTIP = RANGE; protected AbstractAreaEffectSpell(CustomisedSpellType type) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java deleted file mode 100644 index 012cdc02..00000000 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellAttributes.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.minelittlepony.unicopia.ability.magic.spell; - -import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.entity.effect.EffectUtils; - -import net.minecraft.item.ItemStack; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.Identifier; -import net.minecraft.util.StringHelper; -import net.minecraft.util.Util; - -public interface SpellAttributes { - Text CAST_ON_LOCATION = of(Unicopia.id("cast_on_location")); - Text CAST_ON_PERSON = of(Unicopia.id("cast_on_person")); - Identifier FOLLOWS_TARGET = Unicopia.id("follows_target"); - - Identifier PERMIT_ITEMS = Unicopia.id("permit_items"); - Identifier PERMIT_PASSIVE = Unicopia.id("permit_passive"); - Identifier PERMIT_HOSTILE = Unicopia.id("permit_hostile"); - Identifier PERMIT_PLAYER = Unicopia.id("permit_player"); - - Identifier FOCUSED_ENTITY = Unicopia.id("focused_entity"); - Identifier RANGE = Unicopia.id("range"); - Identifier DURATION = Unicopia.id("duration"); - Identifier STRENGTH = Unicopia.id("strength"); - Identifier VELOCITY = Unicopia.id("velocity"); - Identifier VERTICAL_VELOCITY = Unicopia.id("vertical_velocity"); - Identifier HANG_TIME = Unicopia.id("hang_time"); - Identifier PUSHING_POWER = Unicopia.id("pushing_power"); - Identifier CAUSES_LEVITATION = Unicopia.id("causes_levitation"); - Identifier AFFECTS = Unicopia.id("affects"); - Identifier DAMAGE_TO_TARGET = Unicopia.id("damage_to_target"); - Identifier SIMULTANIOUS_TARGETS = Unicopia.id("simultanious_targets"); - Identifier COST_PER_INDIVIDUAL = Unicopia.id("cost_per_individual"); - Identifier EXPLOSION_STRENGTH = Unicopia.id("explosion_strength"); - Identifier PROJECTILE_COUNT = Unicopia.id("projectile_count"); - Identifier ORB_COUNT = Unicopia.id("orb_count"); - Identifier WAVE_SIZE = Unicopia.id("wave_size"); - Identifier FOLLOW_RANGE = Unicopia.id("follow_range"); - Identifier LIGHT_TARGET = Unicopia.id("light_target"); - Identifier STICK_TO_TARGET = Unicopia.id("stick_to_target"); - Identifier SOAPINESS = Unicopia.id("soapiness"); - Identifier CAST_ON = Unicopia.id("cast_on"); - - Identifier TARGET_PREFERENCE = Unicopia.id("target_preference"); - Identifier CASTER_PREFERENCE = Unicopia.id("caster_preference"); - - @Deprecated - static Text of(Identifier id) { - return Text.literal(" ").append(Text.translatable(Util.createTranslationKey("spell_attribute", id))).formatted(Formatting.LIGHT_PURPLE); - } - - @Deprecated - static Text of(Identifier id, float value) { - return Text.literal(" ").append( - Text.translatable("attribute.modifier.equals.0", - ItemStack.MODIFIER_FORMAT.format(value), - Text.translatable(Util.createTranslationKey("spell_attribute", id))) - ).formatted(Formatting.LIGHT_PURPLE); - } - - @Deprecated - static Text ofRelative(Identifier id, float value) { - return EffectUtils.formatModifierChange(Util.createTranslationKey("spell_attribute", id), value, false); - } - - @Deprecated - static Text ofTime(Identifier id, long time) { - return Text.literal(" ").append(Text.translatable("attribute.modifier.equals.0", - StringHelper.formatTicks((int)Math.abs(time)), - Text.translatable(Util.createTranslationKey("spell_attribute", id)) - ).formatted(Formatting.LIGHT_PURPLE)); - } - - @Deprecated - public enum ValueType { - REGULAR, - TIME, - PERCENTAGE, - CONDITIONAL - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java index 94e13b11..18546975 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; @@ -14,7 +15,7 @@ import net.minecraft.util.math.MathHelper; */ public interface TimedSpell extends Spell { int BASE_DURATION = 120 * 20; - SpellAttribute TIME = SpellAttribute.create(SpellAttributes.SOAPINESS, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> BASE_DURATION + (int)(MathHelper.clamp(focus, 0, 160) * 19) * 20); + SpellAttribute TIME = SpellAttribute.create(SpellAttributeType.SOAPINESS, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> BASE_DURATION + (int)(MathHelper.clamp(focus, 0, 160) * 19) * 20); Timer getTimer(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/AttributeFormat.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/AttributeFormat.java index eba8db86..2312e8f0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/AttributeFormat.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/AttributeFormat.java @@ -56,7 +56,7 @@ public enum AttributeFormat { return Text.translatable("spell_attribute.unicopia.added_trait." + ((value > 0) ? "plus" : "take"), name, count).formatted(Formatting.DARK_AQUA); } - static MutableText formatAttributeLine(Text attributeName) { + public static MutableText formatAttributeLine(Text attributeName) { return Text.literal(" ").append(attributeName).formatted(Formatting.LIGHT_PURPLE); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java index 3da4f498..0baacd85 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttribute.java @@ -14,7 +14,6 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import net.minecraft.util.Identifier; import net.minecraft.util.Util; public record SpellAttribute ( @@ -31,34 +30,33 @@ public record SpellAttribute ( return valueGetter.apply(traits, traits.get(trait)); } - public static SpellAttribute create(Identifier id, AttributeFormat format, Trait trait, BiFunction valueGetter) { + public static SpellAttribute create(SpellAttributeType id, AttributeFormat format, Trait trait, BiFunction valueGetter) { return create(id, format, format, trait, valueGetter, false); } - public static SpellAttribute create(Identifier id, AttributeFormat format, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter) { + public static SpellAttribute create(SpellAttributeType id, AttributeFormat format, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter) { return create(id, format, format, trait, valueGetter, false); } - public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter) { + public static SpellAttribute create(SpellAttributeType id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter) { return create(id, baseFormat, relativeFormat, trait, valueGetter, false); } - public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, BiFunction valueGetter) { + public static SpellAttribute create(SpellAttributeType id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, BiFunction valueGetter) { return create(id, baseFormat, relativeFormat, trait, valueGetter, false); } - public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter, boolean detrimental) { + public static SpellAttribute create(SpellAttributeType id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter, boolean detrimental) { return create(id, baseFormat, relativeFormat, trait, (traits, value) -> valueGetter.get(value.floatValue()), detrimental); } - public static SpellAttribute create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, BiFunction valueGetter, boolean detrimental) { - Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id)); + public static SpellAttribute create(SpellAttributeType id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, BiFunction valueGetter, boolean detrimental) { return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { float traitAmount = type.traits().get(trait); float traitDifference = type.relativeTraits().get(trait); float value = valueGetter.apply(type.traits(), traitAmount).floatValue(); - var b = baseFormat.getBase(name, value, "equals", Formatting.LIGHT_PURPLE); + var b = baseFormat.getBase(id.name(), value, "equals", Formatting.LIGHT_PURPLE); if (traitDifference != 0) { tooltip.add(b.append(relativeFormat.getRelative(Text.empty(), valueGetter.apply(type.traits(), traitAmount - traitDifference).floatValue(), value, detrimental))); tooltip.add(AttributeFormat.formatTraitDifference(trait, traitDifference)); @@ -68,15 +66,14 @@ public record SpellAttribute ( }); } - public static SpellAttribute createConditional(Identifier id, Trait trait, Float2ObjectFunction valueGetter) { + public static SpellAttribute createConditional(SpellAttributeType id, Trait trait, Float2ObjectFunction valueGetter) { return createConditional(id, trait, (traits, value) -> valueGetter.get(value.floatValue())); } - public static SpellAttribute createConditional(Identifier id, Trait trait, BiFunction valueGetter) { + public static SpellAttribute createConditional(SpellAttributeType id, Trait trait, BiFunction valueGetter) { return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { - Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id)); float difference = type.relativeTraits().get(trait); - Text value = AttributeFormat.formatAttributeLine(name); + Text value = AttributeFormat.formatAttributeLine(id.name()); if (!valueGetter.apply(type.traits(), type.traits().get(trait))) { value = value.copy().formatted(Formatting.STRIKETHROUGH, Formatting.DARK_GRAY); } @@ -87,12 +84,12 @@ public record SpellAttribute ( }); } - public static > SpellAttribute createEnumerated(Identifier id, Trait trait, Float2ObjectFunction valueGetter) { + public static > SpellAttribute createEnumerated(SpellAttributeType id, Trait trait, Float2ObjectFunction valueGetter) { return createEnumerated(id, trait, (traits, value) -> valueGetter.get(value.floatValue())); } - public static > SpellAttribute createEnumerated(Identifier id, Trait trait, BiFunction valueGetter) { - Function cache = Util.memoize(t -> Text.translatable(Util.createTranslationKey("spell_attribute", id.withPath(id.getPath() + "." + t.name().toLowerCase(Locale.ROOT))))); + public static > SpellAttribute createEnumerated(SpellAttributeType id, Trait trait, BiFunction valueGetter) { + Function cache = Util.memoize(t -> Text.translatable(Util.createTranslationKey("spell_attribute", id.id().withPath(p -> p + "." + t.name().toLowerCase(Locale.ROOT))))); return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType type, List tooltip) -> { T t = valueGetter.apply(type.traits(), type.traits().get(trait)); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttributeType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttributeType.java new file mode 100644 index 00000000..51394786 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/SpellAttributeType.java @@ -0,0 +1,59 @@ +package com.minelittlepony.unicopia.ability.magic.spell.attribute; + +import java.util.ArrayList; +import java.util.List; + +import com.minelittlepony.unicopia.Unicopia; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.Util; + +public record SpellAttributeType(Identifier id, Text name) { + public static final List REGISTRY = new ArrayList<>(); + + @Deprecated + public static final SpellAttributeType CAST_ON_LOCATION = register("cast_on.location"); + public static final SpellAttributeType FOLLOWS_TARGET = register("follows_target"); + + public static final SpellAttributeType PERMIT_ITEMS = register("permit_items"); + public static final SpellAttributeType PERMIT_PASSIVE = register("permit_passive"); + public static final SpellAttributeType PERMIT_HOSTILE = register("permit_hostile"); + public static final SpellAttributeType PERMIT_PLAYER = register("permit_player"); + + public static final SpellAttributeType FOCUSED_ENTITY = register("focused_entity"); + public static final SpellAttributeType RANGE = register("range"); + public static final SpellAttributeType DURATION = register("duration"); + public static final SpellAttributeType STRENGTH = register("strength"); + public static final SpellAttributeType VELOCITY = register("velocity"); + public static final SpellAttributeType VERTICAL_VELOCITY = register("vertical_velocity"); + public static final SpellAttributeType HANG_TIME = register("hang_time"); + public static final SpellAttributeType PUSHING_POWER = register("pushing_power"); + public static final SpellAttributeType CAUSES_LEVITATION = register("causes_levitation"); + public static final SpellAttributeType AFFECTS = register("affects"); + public static final SpellAttributeType DAMAGE_TO_TARGET = register("damage_to_target"); + public static final SpellAttributeType SIMULTANIOUS_TARGETS = register("simultanious_targets"); + public static final SpellAttributeType COST_PER_INDIVIDUAL = register("cost_per_individual"); + public static final SpellAttributeType EXPLOSION_STRENGTH = register("explosion_strength"); + public static final SpellAttributeType PROJECTILE_COUNT = register("projectile_count"); + public static final SpellAttributeType ORB_COUNT = register("orb_count"); + public static final SpellAttributeType WAVE_SIZE = register("wave_size"); + public static final SpellAttributeType FOLLOW_RANGE = register("follow_range"); + public static final SpellAttributeType LIGHT_TARGET = register("light_target"); + public static final SpellAttributeType STICK_TO_TARGET = register("stick_to_target"); + public static final SpellAttributeType SOAPINESS = register("soapiness"); + public static final SpellAttributeType CAST_ON = register("cast_on"); + + public static final SpellAttributeType TARGET_PREFERENCE = register("target_preference"); + public static final SpellAttributeType CASTER_PREFERENCE = register("caster_preference"); + public static final SpellAttributeType NEGATES_FALL_DAMAGE = register("negates_fall_damage"); + + public SpellAttributeType(Identifier id) { + this(id, Text.translatable(Util.createTranslationKey("spell_attribute", id))); + } + + public static SpellAttributeType register(String name) { + SpellAttributeType type = new SpellAttributeType(Unicopia.id(name)); + REGISTRY.add(type); + return type; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java index 8b7e69dd..3be2ff4c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/attribute/TooltipFactory.java @@ -9,6 +9,8 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import net.minecraft.text.Text; public interface TooltipFactory { + TooltipFactory EMPTY = (type, tooltip) -> {}; + void appendTooltip(CustomisedSpellType type, List tooltip); static TooltipFactory of(TooltipFactory...lines) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java index b44547a7..cdc9e012 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AreaProtectionSpell.java @@ -2,8 +2,12 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; +import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; +import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.CastOn; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -24,16 +28,18 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell { .with(Trait.STRENGTH, 30) .build(); - static final TooltipFactory TOOLTIP = TooltipFactory.of(TooltipFactory.of(SpellAttributes.CAST_ON_LOCATION), RANGE); + private static final SpellAttribute CAST_ON = SpellAttribute.createEnumerated(SpellAttributeType.CAST_ON, Trait.FOCUS, focus -> focus > 0 ? CastOn.SELF : CastOn.LOCATION); + + static final TooltipFactory TOOLTIP = TooltipFactory.of(CAST_ON, RANGE); protected AreaProtectionSpell(CustomisedSpellType type) { super(type); } - /*@Override + @Override public Spell prepareForCast(Caster caster, CastingMethod method) { - return method == CastingMethod.STAFF || getTraits().get(Trait.GENEROSITY) > 0 ? toPlaceable() : this; - }*/ + return method == CastingMethod.STAFF || CAST_ON.get(getTraits()) == CastOn.LOCATION ? toPlaceable() : this; + } @Override public boolean tick(Caster source, Situation situation) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java index 5cabfa21..7bf39425 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java @@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; @@ -22,8 +23,8 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSpell, ProjectileDelegate.EntityHitListener { - static final SpellAttribute TARGET_FOCUSED_ENTITY = SpellAttribute.createConditional(SpellAttributes.FOCUSED_ENTITY, Trait.ORDER, order -> order >= 20); - static final SpellAttribute STICK_TO_TARGET = SpellAttribute.createConditional(SpellAttributes.STICK_TO_TARGET, Trait.CHAOS, chaos -> chaos > 0); + static final SpellAttribute TARGET_FOCUSED_ENTITY = SpellAttribute.createConditional(SpellAttributeType.FOCUSED_ENTITY, Trait.ORDER, order -> order >= 20); + static final SpellAttribute STICK_TO_TARGET = SpellAttribute.createConditional(SpellAttributeType.STICK_TO_TARGET, Trait.CHAOS, chaos -> chaos > 0); static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_FOCUSED_ENTITY.get(type.traits()) ? TARGET_FOCUSED_ENTITY : ShieldSpell.TARGET).appendTooltip(type, tooltip); static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, RANGE, TARGET, STICK_TO_TARGET, CAST_ON); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index abeedff2..df1e9c92 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -8,6 +8,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -51,7 +52,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, .with(Trait.POWER, 1) .build(); - private static final SpellAttribute SOAPINESS = SpellAttribute.create(SpellAttributes.SOAPINESS, AttributeFormat.REGULAR, Trait.POWER, power -> (int)(power * 2)); + private static final SpellAttribute SOAPINESS = SpellAttribute.create(SpellAttributeType.SOAPINESS, AttributeFormat.REGULAR, Trait.POWER, power -> (int)(power * 2)); static final TooltipFactory TOOLTIP = TooltipFactory.of(TimedSpell.TIME, SOAPINESS); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java index 287e55bb..036cc8f8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java @@ -8,10 +8,10 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.attribute.Affects; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -49,11 +49,11 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B private static final float HORIZONTAL_VARIANCE = 0.25F; private static final float MAX_STRENGTH = 120; - private static final SpellAttribute LAUNCH_SPEED = SpellAttribute.create(SpellAttributes.VERTICAL_VELOCITY, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> 0.1F + (MathHelper.clamp(strength, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16F); - private static final SpellAttribute HANG_TIME = SpellAttribute.create(SpellAttributes.HANG_TIME, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.AIR, air -> 50 + (int)MathHelper.clamp(air, 0, 10) * 20F); - private static final SpellAttribute PUSHING_POWER = SpellAttribute.create(SpellAttributes.PUSHING_POWER, AttributeFormat.REGULAR, Trait.POWER, power -> 1 + MathHelper.clamp(power, 0, 10) / 10F); - private static final SpellAttribute CAUSES_LEVITATION = SpellAttribute.createConditional(SpellAttributes.CAUSES_LEVITATION, Trait.FOCUS, focus -> focus > 50); - private static final SpellAttribute AFFECTS = SpellAttribute.createEnumerated(SpellAttributes.AFFECTS, Trait.ORDER, order -> { + private static final SpellAttribute LAUNCH_SPEED = SpellAttribute.create(SpellAttributeType.VERTICAL_VELOCITY, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> 0.1F + (MathHelper.clamp(strength, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16F); + private static final SpellAttribute HANG_TIME = SpellAttribute.create(SpellAttributeType.HANG_TIME, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.AIR, air -> 50 + (int)MathHelper.clamp(air, 0, 10) * 20F); + private static final SpellAttribute PUSHING_POWER = SpellAttribute.create(SpellAttributeType.PUSHING_POWER, AttributeFormat.REGULAR, Trait.POWER, power -> 1 + MathHelper.clamp(power, 0, 10) / 10F); + private static final SpellAttribute CAUSES_LEVITATION = SpellAttribute.createConditional(SpellAttributeType.CAUSES_LEVITATION, Trait.FOCUS, focus -> focus > 50); + private static final SpellAttribute AFFECTS = SpellAttribute.createEnumerated(SpellAttributeType.AFFECTS, Trait.ORDER, order -> { if (order <= 0) { return Affects.BOTH; } else if (order <= 10) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java index 8c7f1b61..48aac638 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java @@ -94,7 +94,7 @@ public record CustomisedSpellType ( lines.addAll(TextHelper.wrap(lore, 180).toList()); float corruption = ((int)traits().getCorruption() * 10) + type().getAffinity().getCorruption(); List modifiers = new ArrayList<>(); - type.getTooltip().accept(this, modifiers); + type.getTooltip().appendTooltip(this, modifiers); if (corruption != 0) { modifiers.add(EffectUtils.formatModifierChange("affinity.unicopia.corruption", corruption, true)); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java index ac3040f5..137e21a1 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DispellEvilSpell.java @@ -4,6 +4,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -21,7 +22,7 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat .with(Trait.POWER, 1) .build(); - private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.POWER, power -> (1 + power) * 10D); + private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.POWER, power -> (1 + power) * 10D); static final TooltipFactory TOOLTIP = RANGE; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java index 1e4bc8b6..af56953e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisperseIllusionSpell.java @@ -5,9 +5,9 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.particle.MagicParticleEffect; @@ -19,8 +19,8 @@ import net.minecraft.util.math.Vec3d; * An area-effect spell that disperses illusions. */ public class DisperseIllusionSpell extends AbstractAreaEffectSpell { - private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 15 + power)); - private static final SpellAttribute DURATION = SpellAttribute.create(SpellAttributes.DURATION, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> (1 + (long)strength) * 100); + private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 15 + power)); + private static final SpellAttribute DURATION = SpellAttribute.create(SpellAttributeType.DURATION, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> (1 + (long)strength) * 100); static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, DURATION); protected DisperseIllusionSpell(CustomisedSpellType type) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java index 3ea6df59..1afef18f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java @@ -5,6 +5,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; @@ -19,7 +20,7 @@ import net.minecraft.util.math.Vec3d; public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.EntityHitListener { - private static final SpellAttribute DAMAGE_TO_TARGET = SpellAttribute.create(SpellAttributes.DAMAGE_TO_TARGET, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.BLOOD, blood -> blood); + private static final SpellAttribute DAMAGE_TO_TARGET = SpellAttribute.create(SpellAttributeType.DAMAGE_TO_TARGET, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.BLOOD, blood -> blood); static final TooltipFactory TOOLTIP = DAMAGE_TO_TARGET; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java index 59491f8f..e90558d0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java @@ -5,8 +5,11 @@ import java.util.stream.Stream; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.item.FriendshipBraceletItem; @@ -16,7 +19,6 @@ import com.minelittlepony.unicopia.particle.ParticleUtils; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -30,6 +32,25 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { private static final float POWERS_RANGE_WEIGHT = 0.3F; private static final float MAX_GENEROSITY_FACTOR = 19F; + private static final SpellAttribute DURATION = SpellAttribute.create(SpellAttributeType.DURATION, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> 10 + (int)(MathHelper.clamp(focus, 0, 160))); + private static final SpellAttribute STRENGTH = SpellAttribute.create(SpellAttributeType.STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> MathHelper.clamp(strength, 2, 9)); + private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> MathHelper.clamp((power - 10) * POWERS_RANGE_WEIGHT, MIN_RANGE, MAX_RANGE)); + private static final SpellAttribute SIMULTANIOUS_TARGETS = SpellAttribute.create(SpellAttributeType.SIMULTANIOUS_TARGETS, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.GENEROSITY, (traits, generosity) -> { + return (long)(generosity + traits.get(Trait.FOCUS, MIN_TARGETS, MAX_TARGETS) * 2); + }); + private static final SpellAttribute COST_PER_INDIVIDUAL = SpellAttribute.create(SpellAttributeType.COST_PER_INDIVIDUAL, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, (traits, power) -> { + return MathHelper.clamp(((Math.max(power, 10) - 10) * POWERS_RANGE_WEIGHT) - ((Math.max(traits.get(Trait.FOCUS), 80) - 80) * FOCUS_RANGE_WEIGHT), 1, 7); + }); + private static final SpellAttribute TARGET_PREFERENCE = SpellAttribute.create(SpellAttributeType.TARGET_PREFERENCE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.GENEROSITY, generosity -> { + return MathHelper.clamp(generosity, 1, MAX_GENEROSITY_FACTOR) / MAX_GENEROSITY_FACTOR; + }); + private static final SpellAttribute CASTER_PREFERENCE = SpellAttribute.create(SpellAttributeType.CASTER_PREFERENCE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.GENEROSITY, (traits, generosity) -> { + return 1 - TARGET_PREFERENCE.get(traits); + }); + private static final SpellAttribute NEGATES_FALL_DAMAGE = SpellAttribute.createConditional(SpellAttributeType.NEGATES_FALL_DAMAGE, Trait.GENEROSITY, (generosity) -> generosity > 0.5F); + + static final TooltipFactory TOOLTIP = TooltipFactory.of(DURATION, STRENGTH, RANGE, SIMULTANIOUS_TARGETS, COST_PER_INDIVIDUAL, TARGET_PREFERENCE, CASTER_PREFERENCE, NEGATES_FALL_DAMAGE); + public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() .with(Trait.FOCUS, 80) .with(Trait.POWER, 10) @@ -38,22 +59,11 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { .with(Trait.ORDER, 15) .build(); - public static void appendTooltip(CustomisedSpellType type, List tooltip) { - tooltip.add(SpellAttributes.ofTime(SpellAttributes.DURATION, 10 + (int)(type.traits().get(Trait.FOCUS, 0, 160)))); - tooltip.add(SpellAttributes.of(SpellAttributes.STRENGTH, type.traits().get(Trait.STRENGTH, 2, 9))); - tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, (float)getEffectRange(type.traits()))); - tooltip.add(SpellAttributes.of(SpellAttributes.SIMULTANIOUS_TARGETS, getMaxTargets(type.traits()))); - tooltip.add(SpellAttributes.of(SpellAttributes.COST_PER_INDIVIDUAL, (float)getCostPerEntity(type.traits()))); - float generosity = type.traits().get(Trait.GENEROSITY, 1, MAX_GENEROSITY_FACTOR) / MAX_GENEROSITY_FACTOR; - tooltip.add(SpellAttributes.of(SpellAttributes.TARGET_PREFERENCE, (int)(generosity * 100))); - tooltip.add(SpellAttributes.of(SpellAttributes.CASTER_PREFERENCE, (int)((1 - generosity) * 100))); - } - private final Timer timer; protected FeatherFallSpell(CustomisedSpellType type) { super(type); - timer = new Timer(10 + (int)(getTraits().get(Trait.FOCUS, 0, 160))); + timer = new Timer(DURATION.get(getTraits())); } @Override @@ -75,18 +85,16 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { return true; } - final float strength = 1F / (getTraits().get(Trait.STRENGTH, 2, 9) / targets.size()); - final float generosity = getTraits().get(Trait.GENEROSITY, 1, MAX_GENEROSITY_FACTOR) / MAX_GENEROSITY_FACTOR; + final float strength = 1F / (STRENGTH.get(getTraits()) / targets.size()); + final float targetPreference = TARGET_PREFERENCE.get(getTraits()); + final float casterPreference = 1 - targetPreference; + final boolean negateFallDamage = NEGATES_FALL_DAMAGE.get(getTraits()); Entity entity = caster.asEntity(); Vec3d masterVelocity = entity.getVelocity().multiply(0.1); targets.forEach(target -> { if (target.getVelocity().y < 0) { - - boolean isSelf = caster.isOwnedBy(target) || target == entity; - float delta = strength * (isSelf ? (1F - generosity) : generosity); - - if (!isSelf || generosity < 0.5F) { + if (negateFallDamage) { target.verticalCollision = true; target.setOnGround(true); target.fallDistance = 0; @@ -94,6 +102,8 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { if (target instanceof PlayerEntity) { ((PlayerEntity)target).getAbilities().flying = false; } + + float delta = strength * ((caster.isOwnedBy(target) || target == entity) ? casterPreference : targetPreference); target.setVelocity(target.getVelocity().multiply(1, delta, 1)); if (situation == Situation.PROJECTILE && target != entity) { target.addVelocity(masterVelocity.x, 0, masterVelocity.z); @@ -102,33 +112,16 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { ParticleUtils.spawnParticles(new MagicParticleEffect(getType().getColor()), target, 7); }); - return caster.subtractEnergyCost(timer.getTicksRemaining() % 50 == 0 ? getCostPerEntity(getTraits()) * targets.size() : 0); - } - - protected static double getCostPerEntity(SpellTraits traits) { - float focus = Math.max(traits.get(Trait.FOCUS), 80) - 80; - float power = Math.max(traits.get(Trait.POWER), 10) - 10; - - return MathHelper.clamp((power * POWERS_RANGE_WEIGHT) - (focus * FOCUS_RANGE_WEIGHT), 1, 7); - } - - protected static double getEffectRange(SpellTraits traits) { - return MathHelper.clamp((traits.get(Trait.POWER) - 10) * POWERS_RANGE_WEIGHT, MIN_RANGE, MAX_RANGE); - } - - protected static long getMaxTargets(SpellTraits traits) { - long generosity = (long)traits.get(Trait.GENEROSITY) * 2L; - long focus = (long)traits.get(Trait.FOCUS, MIN_TARGETS, MAX_TARGETS) * 2L; - return generosity + focus; + return caster.subtractEnergyCost(timer.getTicksRemaining() % 50 == 0 ? COST_PER_INDIVIDUAL.get(getTraits()) * targets.size() : 0); } protected Stream getTargets(Caster caster) { - return Stream.concat(Stream.of(caster.asEntity()), caster.findAllEntitiesInRange(getEffectRange(getTraits())).sorted((a, b) -> { + return Stream.concat(Stream.of(caster.asEntity()), caster.findAllEntitiesInRange(RANGE.get(getTraits())).sorted((a, b) -> { return Integer.compare( FriendshipBraceletItem.isComrade(caster, a) ? 1 : 0, FriendshipBraceletItem.isComrade(caster, b) ? 1 : 0 ); - }).distinct()).limit(getMaxTargets(getTraits())); + }).distinct()).limit(SIMULTANIOUS_TARGETS.get(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java index 0821e0f3..346a652f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java @@ -4,9 +4,9 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -36,12 +36,12 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell, .with(Trait.FIRE, 60) .build(); - private static final SpellAttribute VELOCITY = SpellAttribute.create(SpellAttributes.VELOCITY, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> 1.3F + (strength / 11F)); - private static final SpellAttribute PROJECTILE_COUNT = SpellAttribute.create(SpellAttributes.PROJECTILE_COUNT, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.EARTH, earth -> 11 + (int)earth * 3); - private static final SpellAttribute FOLLOWS_TARGET = SpellAttribute.createConditional(SpellAttributes.FOLLOWS_TARGET, Trait.FOCUS, focus -> focus >= 50); - private static final SpellAttribute FOLLOW_RANGE = SpellAttribute.create(SpellAttributes.FOLLOW_RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> Math.max(0F, focus - 49)); - private static final SpellAttribute MAX_EXPLOSION_STRENGTH = SpellAttribute.create(SpellAttributes.EXPLOSION_STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> focus >= 50 ? 10F : 1F); - private static final SpellAttribute EXPLOSION_STRENGTH = SpellAttribute.create(SpellAttributes.EXPLOSION_STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, (traits, focus) -> MathHelper.clamp(focus / 50, 0, MAX_EXPLOSION_STRENGTH.get(traits))); + private static final SpellAttribute VELOCITY = SpellAttribute.create(SpellAttributeType.VELOCITY, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> 1.3F + (strength / 11F)); + private static final SpellAttribute PROJECTILE_COUNT = SpellAttribute.create(SpellAttributeType.PROJECTILE_COUNT, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.EARTH, earth -> 11 + (int)earth * 3); + private static final SpellAttribute FOLLOWS_TARGET = SpellAttribute.createConditional(SpellAttributeType.FOLLOWS_TARGET, Trait.FOCUS, focus -> focus >= 50); + private static final SpellAttribute FOLLOW_RANGE = SpellAttribute.create(SpellAttributeType.FOLLOW_RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> Math.max(0F, focus - 49)); + private static final SpellAttribute MAX_EXPLOSION_STRENGTH = SpellAttribute.create(SpellAttributeType.EXPLOSION_STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> focus >= 50 ? 10F : 1F); + private static final SpellAttribute EXPLOSION_STRENGTH = SpellAttribute.create(SpellAttributeType.EXPLOSION_STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, (traits, focus) -> MathHelper.clamp(focus / 50, 0, MAX_EXPLOSION_STRENGTH.get(traits))); static final TooltipFactory TOOLTIP = TooltipFactory.of(MAX_EXPLOSION_STRENGTH, EXPLOSION_STRENGTH, VELOCITY, PROJECTILE_COUNT, FOLLOWS_TARGET, FOLLOW_RANGE.conditionally(FOLLOWS_TARGET::get)); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java index ae4cf7d7..679b8e59 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java @@ -5,9 +5,9 @@ import java.util.List; import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -36,7 +36,7 @@ public class IceSpell extends AbstractSpell { .with(Trait.ICE, 15) .build(); - private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 3 + power)); + private static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 3 + power)); static final TooltipFactory TOOLTIP = RANGE; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java index 0d96a52b..2c14e4f8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java @@ -6,10 +6,10 @@ import java.util.List; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -34,7 +34,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD .with(Trait.ORDER, 25) .build(); - private static final SpellAttribute ORB_COUNT = SpellAttribute.create(SpellAttributes.ORB_COUNT, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.LIFE, life -> 2 + (int)(MathHelper.clamp(life, 10, 20) / 10F)); + private static final SpellAttribute ORB_COUNT = SpellAttribute.create(SpellAttributeType.ORB_COUNT, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.LIFE, life -> 2 + (int)(MathHelper.clamp(life, 10, 20) / 10F)); static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, ORB_COUNT); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java index 00401bdb..2ad5cce3 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java @@ -8,9 +8,9 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.Creature; @@ -83,7 +83,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti return e -> e.getType() == type; } - static final SpellAttribute WAVE_SIZE = SpellAttribute.create(SpellAttributes.WAVE_SIZE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.CHAOS, chaos -> 10 + (int)MathHelper.clamp(chaos, 0, 10)); + static final SpellAttribute WAVE_SIZE = SpellAttribute.create(SpellAttributeType.WAVE_SIZE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.CHAOS, chaos -> 10 + (int)MathHelper.clamp(chaos, 0, 10)); static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, WAVE_SIZE); private final List> summonedEntities = new ArrayList<>(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java index b95f344a..484e4473 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java @@ -9,10 +9,10 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; -import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat; import com.minelittlepony.unicopia.ability.magic.spell.attribute.CastOn; import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute; +import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttributeType; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; @@ -51,13 +51,13 @@ public class ShieldSpell extends AbstractSpell { .with(Trait.AIR, 9) .build(); - static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power)); - protected static final SpellAttribute CAST_ON = SpellAttribute.createEnumerated(SpellAttributes.CAST_ON, Trait.GENEROSITY, generosity -> generosity > 0 ? CastOn.LOCATION : CastOn.SELF); + static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power)); + protected static final SpellAttribute CAST_ON = SpellAttribute.createEnumerated(SpellAttributeType.CAST_ON, Trait.GENEROSITY, generosity -> generosity > 0 ? CastOn.LOCATION : CastOn.SELF); - static final SpellAttribute TARGET_ITEMS = SpellAttribute.createConditional(SpellAttributes.PERMIT_ITEMS, Trait.KNOWLEDGE, knowledge -> knowledge > 10); - static final SpellAttribute PERMIT_PASSIVE = SpellAttribute.createConditional(SpellAttributes.PERMIT_PASSIVE, Trait.LIFE, l -> l > 0); - static final SpellAttribute PERMIT_HOSTILE = SpellAttribute.createConditional(SpellAttributes.PERMIT_HOSTILE, Trait.BLOOD, l -> l > 0); - static final SpellAttribute PERMIT_PLAYER = SpellAttribute.createConditional(SpellAttributes.PERMIT_PLAYER, Trait.ICE, l -> l > 0); + static final SpellAttribute TARGET_ITEMS = SpellAttribute.createConditional(SpellAttributeType.PERMIT_ITEMS, Trait.KNOWLEDGE, knowledge -> knowledge > 10); + static final SpellAttribute PERMIT_PASSIVE = SpellAttribute.createConditional(SpellAttributeType.PERMIT_PASSIVE, Trait.LIFE, l -> l > 0); + static final SpellAttribute PERMIT_HOSTILE = SpellAttribute.createConditional(SpellAttributeType.PERMIT_HOSTILE, Trait.BLOOD, l -> l > 0); + static final SpellAttribute PERMIT_PLAYER = SpellAttribute.createConditional(SpellAttributeType.PERMIT_PLAYER, Trait.ICE, l -> l > 0); static final TooltipFactory PERMIT_ENTITY = TooltipFactory.of(PERMIT_PASSIVE, PERMIT_HOSTILE, PERMIT_PLAYER); static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_ITEMS.get(type.traits()) ? TARGET_ITEMS : PERMIT_ENTITY).appendTooltip(type, tooltip); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index 0ca190f8..7937120a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -1,7 +1,5 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.List; -import java.util.function.BiConsumer; import org.jetbrains.annotations.Nullable; import com.google.common.base.Suppliers; @@ -69,7 +67,7 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS).tooltip(DisperseIllusionSpell.TOOLTIP)); public static final SpellType AWKWARD = register("awkward", builder(AwkwardSpell::new).affinity(Affinity.NEUTRAL).color(0x3A59FF).shape(GemstoneItem.Shape.ICE)); public static final SpellType TRANSFORMATION = register("transformation", builder(TransformationSpell::new).color(0x19E48E).shape(GemstoneItem.Shape.BRUSH)); - public static final SpellType FEATHER_FALL = register("feather_fall", builder(FeatherFallSpell::new).color(0x00EEFF).shape(GemstoneItem.Shape.LAMBDA).traits(FeatherFallSpell.DEFAULT_TRAITS).tooltip(FeatherFallSpell::appendTooltip)); + public static final SpellType FEATHER_FALL = register("feather_fall", builder(FeatherFallSpell::new).color(0x00EEFF).shape(GemstoneItem.Shape.LAMBDA).traits(FeatherFallSpell.DEFAULT_TRAITS).tooltip(FeatherFallSpell.TOOLTIP)); public static final SpellType CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS).tooltip(CatapultSpell.TOOLTIP)); public static final SpellType FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS).tooltip(FireBoltSpell.TOOLTIP)); public static final SpellType LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS).tooltip(LightSpell.TOOLTIP)); @@ -100,9 +98,9 @@ public final class SpellType implements Affine, SpellPredicate< private final ItemStack defaultStack; - private final BiConsumer, List> tooltipFunction; + private final TooltipFactory tooltipFunction; - private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, boolean stackable, GemstoneItem.Shape shape, SpellTraits traits, BiConsumer, List> tooltipFunction, Factory factory) { + private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, boolean stackable, GemstoneItem.Shape shape, SpellTraits traits, TooltipFactory tooltipFunction, Factory factory) { this.id = id; this.affinity = affinity; this.color = color; @@ -175,7 +173,7 @@ public final class SpellType implements Affine, SpellPredicate< return factory; } - public BiConsumer, List> getTooltip() { + public TooltipFactory getTooltip() { return tooltipFunction; } @@ -240,7 +238,7 @@ public final class SpellType implements Affine, SpellPredicate< private boolean stackable = false; private GemstoneItem.Shape shape = GemstoneItem.Shape.ROUND; private SpellTraits traits = SpellTraits.EMPTY; - private BiConsumer, List> tooltipFunction = (t, l) -> {}; + private TooltipFactory tooltipFunction = TooltipFactory.EMPTY; Builder(Factory factory) { this.factory = factory; @@ -277,12 +275,6 @@ public final class SpellType implements Affine, SpellPredicate< } public Builder tooltip(TooltipFactory tooltipFunction) { - this.tooltipFunction = tooltipFunction::appendTooltip; - return this; - } - - @Deprecated - public Builder tooltip(BiConsumer, List> tooltipFunction) { this.tooltipFunction = tooltipFunction; return this; } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 4c19c409..af76a3ba 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -587,8 +587,8 @@ "spell_attribute.unicopia.added_trait.plus": " + %s x%s", "spell_attribute.unicopia.added_trait.take": " - %s x%s", "spell_attribute.unicopia.added_trait.unknown": "Undiscovered Trait", - "spell_attribute.unicopia.cast_on_location": "Applies to location", - "spell_attribute.unicopia.cast_on_person": "Applies to self", + "spell_attribute.unicopia.cast_on.location": "Applies to location", + "spell_attribute.unicopia.cast_on.self": "Applies to self", "spell_attribute.unicopia.focused_entity": "Applies to focused entity", "spell_attribute.unicopia.affects.both": "Affects blocks and entities", "spell_attribute.unicopia.affects.entities": "Affects only entities", @@ -615,10 +615,12 @@ "spell_attribute.unicopia.explosion_strength": "Blast Strength", "spell_attribute.unicopia.projectile_count": "Projectile Count", "spell_attribute.unicopia.follow_range": "Following Range", + "spell_attribute.unicopia.stick_to_target": "Attaches to Target", "spell_attribute.unicopia.orb_count": "Orb Count", "spell_attribute.unicopia.wave_size": "Wave Size", "spell_attribute.unicopia.target_preference": "Target Preference", "spell_attribute.unicopia.caster_preference": "Caster Preference", + "spell_attribute.unicopia.negates_fall_damage": "Negates Fall Damage", "trait.unicopia.strength.name": "Strength", "trait.unicopia.strength.description": "Imparts physical strength or enhances endurance.\nSpells with more of the strength trait hit harder and last longer.", From e2f2b83003896e6cfaa1f16942071a1bc7330791 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 23 Jun 2024 14:41:21 +0100 Subject: [PATCH 78/85] Make pearl necklaces less common when fishing. This is literally the lowest it will go. #388 --- .../UChestAdditionsLootTableProvider.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestAdditionsLootTableProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestAdditionsLootTableProvider.java index 0d6beac9..2c6b18bd 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestAdditionsLootTableProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/loot/UChestAdditionsLootTableProvider.java @@ -16,6 +16,7 @@ import net.minecraft.loot.context.LootContextTypes; import net.minecraft.loot.entry.ItemEntry; import net.minecraft.loot.entry.TagEntry; import net.minecraft.loot.function.SetCountLootFunction; +import net.minecraft.loot.provider.number.ConstantLootNumberProvider; import net.minecraft.loot.provider.number.UniformLootNumberProvider; import net.minecraft.util.Identifier; @@ -115,34 +116,28 @@ public class UChestAdditionsLootTableProvider extends SimpleFabricLootTableProvi .with(ItemEntry.builder(UItems.MUSIC_DISC_CRUSADE).weight(1)) )); exporter.accept(LootTables.OCEAN_RUIN_WARM_ARCHAEOLOGY, LootTable.builder().pool(LootPool.builder() - .rolls(UniformLootNumberProvider.create(1, 4)) - .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(1)) + .rolls(UniformLootNumberProvider.create(1, 2)) + .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(2)) .with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1)) - .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1)) + .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(2)) )); exporter.accept(LootTables.FISHING_GAMEPLAY, LootTable.builder().pool(LootPool.builder() - .rolls(UniformLootNumberProvider.create(1, 4)) + .rolls(UniformLootNumberProvider.create(1, 2)) .with(TagEntry.expandBuilder(UTags.Items.SHELLS).weight(2)) .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1)) )); exporter.accept(LootTables.FISHING_JUNK_GAMEPLAY, LootTable.builder().pool(LootPool.builder() - .rolls(UniformLootNumberProvider.create(1, 4)) + .rolls(UniformLootNumberProvider.create(1, 2)) .with(ItemEntry.builder(UItems.BROKEN_SUNGLASSES).weight(2)) .with(ItemEntry.builder(UItems.WHEAT_WORMS).weight(2)) .with(TagEntry.expandBuilder(UConventionalTags.Items.ROTTEN_FISH).weight(1)) .with(ItemEntry.builder(UItems.BOTCHED_GEM).weight(4)) )); - exporter.accept(LootTables.FISHING_TREASURE_GAMEPLAY, LootTable.builder().pool(LootPool.builder() - .rolls(UniformLootNumberProvider.create(1, 4)) - .with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1)) - .with(ItemEntry.builder(UItems.SHELLY).weight(1)) - )); - exporter.accept(LootTables.HERO_OF_THE_VILLAGE_FISHERMAN_GIFT_GAMEPLAY, LootTable.builder().pool(LootPool.builder() - .rolls(UniformLootNumberProvider.create(1, 4)) + .rolls(ConstantLootNumberProvider.create(1)) .with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1)) .with(ItemEntry.builder(UItems.SHELLY).weight(1)) )); From 498ec2bca072bf4a643027e1881b97fd2b3210df Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 23 Jun 2024 14:41:44 +0100 Subject: [PATCH 79/85] The pearl necklace now has 4 durability --- .../unicopia/ability/ChangeFormAbility.java | 7 +++ .../unicopia/client/gui/UHud.java | 4 +- .../client/minelittlepony/AmuletGear.java | 4 +- .../client/minelittlepony/BangleGear.java | 6 +-- .../client/minelittlepony/GlassesGear.java | 4 +- .../unicopia/client/minelittlepony/Main.java | 4 +- .../client/render/AmuletFeatureRenderer.java | 2 +- .../render/BraceletFeatureRenderer.java | 14 ++--- .../client/render/GlassesFeatureRenderer.java | 2 +- .../unicopia/client/render/PlayerPoser.java | 2 +- .../compat/trinkets/TrinketsDelegate.java | 51 +++++++++++++------ .../compat/trinkets/TrinketsDelegateImpl.java | 17 ++++++- .../container/SpellbookScreenHandler.java | 4 +- .../unicopia/entity/Living.java | 6 +-- .../effect/SunBlindnessStatusEffect.java | 5 +- .../unicopia/entity/mob/SombraEntity.java | 10 ++-- .../unicopia/entity/player/PlayerPhysics.java | 11 ++-- .../unicopia/entity/player/Pony.java | 5 +- .../unicopia/item/AlicornAmuletItem.java | 2 +- .../unicopia/item/AmuletItem.java | 13 +++-- .../unicopia/item/BellItem.java | 2 +- .../unicopia/item/FriendshipBraceletItem.java | 29 +++++++---- .../unicopia/item/GlassesItem.java | 9 ++-- .../unicopia/item/PegasusAmuletItem.java | 5 -- .../minelittlepony/unicopia/item/UItems.java | 1 + .../unicopia/network/Channel.java | 1 + .../unicopia/network/MsgTrinketBroken.java | 22 ++++++++ .../handler/ClientNetworkHandlerImpl.java | 38 ++++++++++++++ 28 files changed, 194 insertions(+), 86 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/network/MsgTrinketBroken.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangeFormAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangeFormAbility.java index 67aa667f..6f4cc3e0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ChangeFormAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangeFormAbility.java @@ -10,8 +10,10 @@ import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.advancement.UCriteria; +import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.FriendshipBraceletItem; +import com.minelittlepony.unicopia.item.UItems; import net.minecraft.particle.ParticleTypes; import net.minecraft.sound.SoundCategory; @@ -73,6 +75,11 @@ public class ChangeFormAbility implements Ability { List targets = getTargets(player).toList(); player.subtractEnergyCost(5 * targets.size()); + TrinketsDelegate.EquippedStack amulet = UItems.PEARL_NECKLACE.getForEntity(player.asEntity()); + if (!amulet.stack().isEmpty()) { + amulet.stack().damage(1, player.asEntity(), amulet.breakStatusSender()); + } + boolean isTransforming = player.getSuppressedRace().isUnset(); targets.forEach(target -> { Race supressed = target.getSuppressedRace(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index fb50166e..1dd0ae28 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -214,8 +214,8 @@ public class UHud { boolean hasEffect = client.player.hasStatusEffect(UEffects.SUN_BLINDNESS); - ItemStack glasses = GlassesItem.getForEntity(client.player); - boolean hasSunglasses = glasses.getItem() == UItems.SUNGLASSES; + ItemStack glasses = GlassesItem.getForEntity(client.player).stack(); + boolean hasSunglasses = glasses.isOf(UItems.SUNGLASSES); if (hasEffect || (!hasSunglasses && pony.getObservedSpecies() == Race.BAT && SunBlindnessStatusEffect.hasSunExposure(client.player))) { float i = hasEffect ? (client.player.getStatusEffect(UEffects.SUN_BLINDNESS).getDuration() - tickDelta) / SunBlindnessStatusEffect.MAX_DURATION : 0; diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/AmuletGear.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/AmuletGear.java index fad07825..68589a6a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/AmuletGear.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/AmuletGear.java @@ -31,7 +31,7 @@ class AmuletGear extends AmuletModel implements IGear { @Override public boolean canRender(IModel model, Entity entity) { - return entity instanceof LivingEntity living && !AmuletItem.getForEntity(living).isEmpty(); + return entity instanceof LivingEntity living && !AmuletItem.get(living).stack().isEmpty(); } @Override @@ -41,7 +41,7 @@ class AmuletGear extends AmuletModel implements IGear { @Override public Identifier getTexture(T entity, Context context) { - return textures.computeIfAbsent(Registries.ITEM.getId(AmuletItem.getForEntity((LivingEntity)entity).getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); + return textures.computeIfAbsent(Registries.ITEM.getId(AmuletItem.get((LivingEntity)entity).stack().getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BangleGear.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BangleGear.java index 5346192a..d223b502 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BangleGear.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BangleGear.java @@ -67,8 +67,8 @@ class BangleGear implements IGear { public void pose(IModel model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) { alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim"); FriendshipBraceletItem.getWornBangles((LivingEntity)entity, slot).findFirst().ifPresent(bracelet -> { - color = ((DyeableItem)bracelet.getItem()).getColor(bracelet); - glowing = ((GlowableItem)bracelet.getItem()).isGlowing(bracelet); + color = ((DyeableItem)bracelet.stack().getItem()).getColor(bracelet.stack()); + glowing = ((GlowableItem)bracelet.stack().getItem()).isGlowing(bracelet.stack()); }); BraceletModel m = alex ? alexModel : steveModel; @@ -76,7 +76,7 @@ class BangleGear implements IGear { m.setAngles(biped); } Arm mainArm = ((LivingEntity)entity).getMainArm(); - m.setVisible(slot == TrinketsDelegate.MAINHAND ? mainArm : mainArm.getOpposite()); + m.setVisible(slot == TrinketsDelegate.MAIN_GLOVE ? mainArm : mainArm.getOpposite()); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/GlassesGear.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/GlassesGear.java index ab06f473..3f582a09 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/GlassesGear.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/GlassesGear.java @@ -28,7 +28,7 @@ class GlassesGear extends GlassesModel implements IGear { @Override public boolean canRender(IModel model, Entity entity) { - return entity instanceof LivingEntity living && !GlassesItem.getForEntity(living).isEmpty(); + return entity instanceof LivingEntity living && !GlassesItem.getForEntity(living).stack().isEmpty(); } @Override @@ -38,7 +38,7 @@ class GlassesGear extends GlassesModel implements IGear { @Override public Identifier getTexture(T entity, Context context) { - return textures.computeIfAbsent(Registries.ITEM.getId(GlassesItem.getForEntity((LivingEntity)entity).getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); + return textures.computeIfAbsent(Registries.ITEM.getId(GlassesItem.getForEntity((LivingEntity)entity).stack().getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java index abb6659e..229fb3ed 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java @@ -44,8 +44,8 @@ public class Main extends MineLPDelegate implements ClientModInitializer { public void onInitializeClient() { INSTANCE = this; PonyModelPrepareCallback.EVENT.register(this::onPonyModelPrepared); - IGear.register(() -> new BangleGear(TrinketsDelegate.MAINHAND)); - IGear.register(() -> new BangleGear(TrinketsDelegate.OFFHAND)); + IGear.register(() -> new BangleGear(TrinketsDelegate.MAIN_GLOVE)); + IGear.register(() -> new BangleGear(TrinketsDelegate.SECONDARY_GLOVE)); IGear.register(HeldEntityGear::new); IGear.register(BodyPartGear::pegasusWings); IGear.register(BodyPartGear::batWings); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java index f2a2c54f..99bce334 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java @@ -42,7 +42,7 @@ public class AmuletFeatureRenderer implements AccessoryF @Override public void render(MatrixStack matrices, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { - ItemStack stack = AmuletItem.getForEntity(entity); + ItemStack stack = AmuletItem.get(entity).stack(); if (!stack.isEmpty()) { Identifier texture = textures.computeIfAbsent(Registries.ITEM.getId(stack.getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java index 017e0f8c..aa5c3b1a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java @@ -48,11 +48,11 @@ public class BraceletFeatureRenderer implements Accessor @Override public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { - FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.MAINHAND).findFirst().ifPresent(bangle -> { - renderBangleThirdPerson(bangle, stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm()); + FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.MAIN_GLOVE).findFirst().ifPresent(bangle -> { + renderBangleThirdPerson(bangle.stack(), stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm()); }); - FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.OFFHAND).findFirst().ifPresent(bangle -> { - renderBangleThirdPerson(bangle, stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm().getOpposite()); + FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.SECONDARY_GLOVE).findFirst().ifPresent(bangle -> { + renderBangleThirdPerson(bangle.stack(), stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm().getOpposite()); }); } @@ -82,14 +82,14 @@ public class BraceletFeatureRenderer implements Accessor @Override public void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, ModelPart armModel, Arm side) { - FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAINHAND : TrinketsDelegate.OFFHAND).findFirst().ifPresent(item -> { - int j = ((DyeableItem)item.getItem()).getColor(item); + FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAIN_GLOVE : TrinketsDelegate.SECONDARY_GLOVE).findFirst().ifPresent(item -> { + int j = ((DyeableItem)item.stack().getItem()).getColor(item.stack()); boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim"); BraceletModel model = alex ? alexModel : steveModel; - boolean glowing = ((GlowableItem)item.getItem()).isGlowing(item); + boolean glowing = ((GlowableItem)item.stack().getItem()).isGlowing(item.stack()); if (MineLPDelegate.getInstance().getPlayerPonyRace((ClientPlayerEntity)entity).isEquine()) { stack.translate(side == Arm.LEFT ? 0.06 : -0.06, 0.3, 0); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/GlassesFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/GlassesFeatureRenderer.java index 40771191..7a0ca70d 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/GlassesFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/GlassesFeatureRenderer.java @@ -36,7 +36,7 @@ public class GlassesFeatureRenderer implements Accessory @Override public void render(MatrixStack matrices, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { - ItemStack stack = GlassesItem.getForEntity(entity); + ItemStack stack = GlassesItem.getForEntity(entity).stack(); if (!stack.isEmpty()) { Identifier texture = textures.computeIfAbsent(Registries.ITEM.getId(stack.getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java b/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java index 2402dfab..6c21e24c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java @@ -42,7 +42,7 @@ public class PlayerPoser { boolean liftLeftArm = mainArm == Arm.LEFT || !ponyRace.isEquine(); boolean liftRightArm = mainArm == Arm.RIGHT || !ponyRace.isEquine(); - ItemStack glasses = GlassesItem.getForEntity(player); + ItemStack glasses = GlassesItem.getForEntity(player).stack(); ModelPart head = model.getHead(); if (context == Context.THIRD_PERSON && !player.isSneaking()) { diff --git a/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegate.java b/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegate.java index c9e17eb8..f19d592a 100644 --- a/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegate.java @@ -1,6 +1,8 @@ package com.minelittlepony.unicopia.compat.trinkets; import java.util.*; +import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -16,16 +18,17 @@ import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.registry.tag.TagKey; import net.minecraft.screen.slot.Slot; import net.minecraft.util.Identifier; public interface TrinketsDelegate { - Identifier MAINHAND = new Identifier("hand:glove"); - Identifier OFFHAND = new Identifier("offhand:glove"); + Identifier MAIN_GLOVE = new Identifier("hand:glove"); + Identifier SECONDARY_GLOVE = new Identifier("offhand:glove"); Identifier NECKLACE = new Identifier("chest:necklace"); Identifier FACE = new Identifier("head:face"); - Set ALL = new TreeSet<>(List.of(MAINHAND, OFFHAND, NECKLACE, FACE)); + Set ALL = new TreeSet<>(List.of(MAIN_GLOVE, SECONDARY_GLOVE, NECKLACE, FACE)); TrinketsDelegate EMPTY = new TrinketsDelegate() {}; @@ -61,8 +64,8 @@ public interface TrinketsDelegate { default void setEquippedStack(LivingEntity entity, Identifier slot, ItemStack stack) { EquipmentSlot eq = slot == FACE ? EquipmentSlot.HEAD : slot == NECKLACE ? EquipmentSlot.CHEST - : slot == MAINHAND ? EquipmentSlot.CHEST - : slot == OFFHAND ? EquipmentSlot.OFFHAND + : slot == MAIN_GLOVE ? EquipmentSlot.CHEST + : slot == SECONDARY_GLOVE ? EquipmentSlot.OFFHAND : null; if (eq != null) { entity.equipStack(eq, stack); @@ -70,19 +73,27 @@ public interface TrinketsDelegate { } default Set getAvailableTrinketSlots(LivingEntity entity, Set probedSlots) { - return probedSlots.stream().filter(slot -> getEquipped(entity, slot).anyMatch(ItemStack::isEmpty)).collect(Collectors.toSet()); + return probedSlots.stream().filter(slot -> getEquipped(entity, slot).map(EquippedStack::stack).anyMatch(ItemStack::isEmpty)).collect(Collectors.toSet()); } - default Stream getEquipped(LivingEntity entity, Identifier slot) { + default Stream getEquipped(LivingEntity entity, Identifier slot, TagKey tag) { + return getEquipped(entity, slot, stack -> stack.isIn(tag)); + } - if (slot == FACE) { - return Stream.of(entity.getEquippedStack(EquipmentSlot.HEAD)); + default Stream getEquipped(LivingEntity entity, Identifier slot) { + return getEquipped(entity, slot, (Predicate)null); + } + + default Stream getEquipped(LivingEntity entity, Identifier slot, @Nullable Predicate predicate) { + + if (slot == FACE && (predicate == null || predicate.test(entity.getEquippedStack(EquipmentSlot.HEAD)))) { + return Stream.of(new EquippedStack(entity, EquipmentSlot.HEAD)); } - if (slot == NECKLACE || slot == MAINHAND) { - return Stream.of(entity.getEquippedStack(EquipmentSlot.CHEST)); + if ((slot == NECKLACE || slot == MAIN_GLOVE) && (predicate == null || predicate.test(entity.getEquippedStack(EquipmentSlot.CHEST)))) { + return Stream.of(new EquippedStack(entity, EquipmentSlot.CHEST)); } - if (slot == OFFHAND) { - return Stream.of(entity.getOffHandStack()); + if (slot == SECONDARY_GLOVE && (predicate == null || predicate.test(entity.getEquippedStack(EquipmentSlot.OFFHAND)))) { + return Stream.of(new EquippedStack(entity, EquipmentSlot.OFFHAND)); } return Stream.empty(); @@ -102,16 +113,24 @@ public interface TrinketsDelegate { interface Inventory extends EntityConvertable { - default Stream getEquippedStacks(Identifier slot) { + default Stream getEquippedStacks(Identifier slot) { return TrinketsDelegate.getInstance(asEntity()).getEquipped(asEntity(), slot); } - default ItemStack getEquippedStack(Identifier slot) { - return getEquippedStacks(slot).findFirst().orElse(ItemStack.EMPTY); + default EquippedStack getEquippedStack(Identifier slot) { + return getEquippedStacks(slot).findFirst().orElse(EquippedStack.EMPTY); } default void equipStack(Identifier slot, ItemStack stack) { TrinketsDelegate.getInstance(asEntity()).setEquippedStack(asEntity(), slot, stack); } } + + record EquippedStack(ItemStack stack, Runnable sendUpdate, Consumer breakStatusSender) { + public static EquippedStack EMPTY = new EquippedStack(ItemStack.EMPTY, () -> {}, l -> {}); + + EquippedStack(LivingEntity entity, EquipmentSlot slot) { + this(entity.getEquippedStack(slot), () -> {}, l -> l.sendEquipmentBreakStatus(slot)); + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegateImpl.java b/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegateImpl.java index f8f0ec24..edbe0274 100644 --- a/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegateImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegateImpl.java @@ -1,11 +1,16 @@ package com.minelittlepony.unicopia.compat.trinkets; import java.util.*; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jetbrains.annotations.Nullable; + import com.minelittlepony.unicopia.container.SpellbookScreenHandler; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; +import com.minelittlepony.unicopia.network.Channel; +import com.minelittlepony.unicopia.network.MsgTrinketBroken; import com.minelittlepony.unicopia.util.InventoryUtil; import dev.emi.trinkets.TrinketSlot; import dev.emi.trinkets.api.*; @@ -80,8 +85,16 @@ public class TrinketsDelegateImpl implements TrinketsDelegate { } @Override - public Stream getEquipped(LivingEntity entity, Identifier slot) { - return getInventory(entity, slot).stream().flatMap(InventoryUtil::stream).filter(s -> !s.isEmpty()); + public Stream getEquipped(LivingEntity entity, Identifier slot, @Nullable Predicate predicate) { + return getInventory(entity, slot).stream().flatMap(inventory -> { + return InventoryUtil.stream(inventory).filter(s -> !s.isEmpty() && (predicate == null || predicate.test(s))).map(stack -> { + ItemStack oldStack = stack.copy(); + return new EquippedStack(stack, inventory::markUpdate, l -> { + inventory.markUpdate(); + Channel.SERVER_TRINKET_BROKEN.sendToSurroundingPlayers(new MsgTrinketBroken(oldStack, l.getId()), l); + }); + }); + }); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java index de69aacf..8f5f112a 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java @@ -147,8 +147,8 @@ public class SpellbookScreenHandler extends ScreenHandler { TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.FACE, 0, rightHandX, inventoryY + slotSpacing * 6).ifPresent(this::addSlot); TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.NECKLACE, 0, leftHandX, equipmentY + slotSpacing).ifPresent(this::addSlot); - TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.MAINHAND, 0, leftHandX, equipmentY).ifPresent(this::addSlot); - TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.OFFHAND, 0, rightHandX, equipmentY).ifPresent(this::addSlot); + TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.MAIN_GLOVE, 0, leftHandX, equipmentY).ifPresent(this::addSlot); + TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.SECONDARY_GLOVE, 0, rightHandX, equipmentY).ifPresent(this::addSlot); addSlot(outputSlot = new OutputSlot(this, inventory.player, input, result, 0, gemPos.get(0))); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index ba453869..756a4491 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -371,8 +371,8 @@ public abstract class Living implements Equine, Caste } if (magical.isIn(UTags.DamageTypes.BREAKS_SUNGLASSES)) { - ItemStack glasses = GlassesItem.getForEntity(entity); - if (glasses.getItem() == UItems.SUNGLASSES) { + ItemStack glasses = GlassesItem.getForEntity(entity).stack(); + if (glasses.isOf(UItems.SUNGLASSES)) { ItemStack broken = UItems.BROKEN_SUNGLASSES.getDefaultStack(); broken.setNbt(glasses.getNbt()); TrinketsDelegate.getInstance(entity).setEquippedStack(entity, TrinketsDelegate.FACE, broken); @@ -417,7 +417,7 @@ public abstract class Living implements Equine, Caste return StreamSupport.stream(entity.getArmorItems().spliterator(), false); } return Stream.concat( - TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE), + TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE).map(TrinketsDelegate.EquippedStack::stack), StreamSupport.stream(entity.getArmorItems().spliterator(), false) ); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java index 10e607a9..57f91ed4 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java @@ -11,7 +11,6 @@ import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.util.MeteorlogicalUtil; import net.minecraft.entity.Entity; -import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.effect.StatusEffect; import net.minecraft.entity.effect.StatusEffectInstance; @@ -72,9 +71,7 @@ public class SunBlindnessStatusEffect extends StatusEffect { return true; } - if (entity.getEquippedStack(EquipmentSlot.HEAD).isIn(UTags.Items.SHADES) - || TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.Items.SHADES)) - || entity.isSubmergedInWater()) { + if (entity.isSubmergedInWater() || TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE, i -> i.isIn(UTags.Items.SHADES)).findAny().isPresent()) { return false; } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/SombraEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/SombraEntity.java index 26714449..b673037c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/SombraEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/SombraEntity.java @@ -11,11 +11,11 @@ import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; import com.minelittlepony.unicopia.advancement.UCriteria; +import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate; import com.minelittlepony.unicopia.entity.AmuletSelectors; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.ai.ArenaAttackGoal; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.item.AmuletItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.ParticleSource; @@ -63,7 +63,6 @@ import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.passive.IronGolemEntity; import net.minecraft.entity.passive.MerchantEntity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtHelper; @@ -484,9 +483,10 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti player.sendMessage(Text.translatable("entity.unicopia.sombra.taunt")); } } - ItemStack amulet = AmuletItem.getForEntity(player); - if (amulet.isOf(UItems.ALICORN_AMULET)) { - amulet.decrement(1); + TrinketsDelegate.EquippedStack amulet = UItems.ALICORN_AMULET.getForEntity(player); + if (!amulet.stack().isEmpty()) { + amulet.stack().decrement(1); + amulet.sendUpdate(); } } boolean damaged = super.damage(source, amount); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index 1dc7851f..c2789be6 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.compat.ad_astra.OxygenApi; +import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate; import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; @@ -38,12 +39,10 @@ import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBlockTags; import net.minecraft.block.*; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.EntityType; -import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LightningEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.damage.DamageSource; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; import net.minecraft.predicate.entity.EntityPredicates; @@ -499,8 +498,8 @@ public class PlayerPhysics extends EntityPhysics implements Tickab private void tickArtificialFlight(MutableVector velocity) { if (ticksInAir % 10 == 0 && !entity.getWorld().isClient) { - ItemStack stack = AmuletItem.getForEntity(entity); - if (ChargeableItem.getEnergy(stack) < 9) { + TrinketsDelegate.EquippedStack stack = AmuletItem.get(entity); + if (ChargeableItem.getEnergy(stack.stack()) < 9) { playSound(USounds.ITEM_ICARUS_WINGS_WARN, 0.13F, 0.5F); } @@ -517,10 +516,10 @@ public class PlayerPhysics extends EntityPhysics implements Tickab minDamage *= 3; } - ChargeableItem.consumeEnergy(stack, energyConsumed); + ChargeableItem.consumeEnergy(stack.stack(), energyConsumed); if (entity.getWorld().random.nextInt(damageInterval) == 0) { - stack.damage(minDamage + entity.getWorld().random.nextInt(50), entity, e -> e.sendEquipmentBreakStatus(EquipmentSlot.CHEST)); + stack.stack().damage(minDamage + entity.getWorld().random.nextInt(50), (LivingEntity)entity, stack.breakStatusSender()); } if (!lastFlightType.canFly()) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 6c55a3be..845cb09c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -484,6 +484,9 @@ public class Pony extends Living implements Copyable, Update AmuletSelectors.PEARL_NECKLACE.test(entity) ? suppressedRace.or(Race.SEAPONY) : null ); UCriteria.PLAYER_CHANGE_RACE.trigger(entity); + + var hasNecklace = AmuletSelectors.PEARL_NECKLACE.test(entity); + System.out.println(hasNecklace); } @Override @@ -526,7 +529,7 @@ public class Pony extends Living implements Copyable, Update } if (getObservedSpecies() == Race.BAT && !entity.hasPortalCooldown()) { - boolean hasShades = TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(s -> s.isIn(UTags.Items.SHADES)); + boolean hasShades = TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(s -> s.stack().isIn(UTags.Items.SHADES)); if (!this.hasShades && hasShades && getObservedSpecies() == Race.BAT) { UCriteria.WEAR_SHADES.trigger(entity); } diff --git a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java index f3c16ffa..6cb64651 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java @@ -247,7 +247,7 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab // bind to the player after 3 days if (daysAttached >= 3 && !pony.asEntity().isCreative()) { - stack = living.getArmour().getEquippedStack(TrinketsDelegate.NECKLACE); + stack = living.getArmour().getEquippedStack(TrinketsDelegate.NECKLACE).stack(); if (stack.getItem() == this && !EnchantmentHelper.hasBindingCurse(stack)) { pony.playSound(USounds.ITEM_ALICORN_AMULET_HALLUCINATION, 3, 1); stack = stack.copy(); diff --git a/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java index cb3426d5..8e0673f7 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java @@ -86,7 +86,13 @@ public class AmuletItem extends WearableItem implements ChargeableItem { } public final boolean isApplicable(LivingEntity entity) { - return isApplicable(getForEntity(entity)); + return !getForEntity(entity).stack().isEmpty(); + } + + public TrinketsDelegate.EquippedStack getForEntity(LivingEntity entity) { + return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE, this::isApplicable) + .findFirst() + .orElse(TrinketsDelegate.EquippedStack.EMPTY); } @Override @@ -94,11 +100,10 @@ public class AmuletItem extends WearableItem implements ChargeableItem { return maxEnergy; } - public static ItemStack getForEntity(LivingEntity entity) { + public static TrinketsDelegate.EquippedStack get(LivingEntity entity) { return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE) - .filter(stack -> stack.getItem() instanceof AmuletItem) .findFirst() - .orElse(ItemStack.EMPTY); + .orElse(TrinketsDelegate.EquippedStack.EMPTY); } public static class ModifiersBuilder { diff --git a/src/main/java/com/minelittlepony/unicopia/item/BellItem.java b/src/main/java/com/minelittlepony/unicopia/item/BellItem.java index cf9af687..2b5f4d99 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/BellItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/BellItem.java @@ -69,7 +69,7 @@ public class BellItem extends Item implements ChargeableItem { @Override public TypedActionResult use(World world, PlayerEntity player, Hand hand) { ItemStack stack = player.getStackInHand(hand); - ItemStack offhandStack = AmuletItem.getForEntity(player); + ItemStack offhandStack = AmuletItem.get(player).stack(); if (!(offhandStack.getItem() instanceof ChargeableItem)) { offhandStack = player.getStackInHand(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND); diff --git a/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java b/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java index 1828f66d..6fe650ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.item; import java.util.List; import java.util.UUID; +import java.util.function.Predicate; import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; @@ -120,28 +121,36 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem, public static boolean isComrade(Owned caster, Entity entity) { return entity instanceof LivingEntity l && caster.getMasterId() - .filter(id -> getWornBangles(l).anyMatch(stack -> isSignedBy(stack, id))) + .filter(id -> getWornBangles(l).anyMatch(stack -> isSignedBy(stack.stack(), id))) .isPresent(); } public static boolean isComrade(UUID signator, Entity entity) { - return entity instanceof LivingEntity l && getWornBangles(l).anyMatch(stack -> isSignedBy(stack, signator)); + return entity instanceof LivingEntity l && getWornBangles(l, stack -> isSignedBy(stack, signator)).findAny().isPresent(); } public static Stream getPartyMembers(Caster caster, double radius) { return Pony.stream(caster.findAllEntitiesInRange(radius, entity -> isComrade(caster, entity))); } - public static Stream getWornBangles(LivingEntity entity) { + private static final Predicate IS_BANGLE = stack -> stack.isOf(UItems.FRIENDSHIP_BRACELET); + + public static Stream getWornBangles(LivingEntity entity) { return Stream.concat( - TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAINHAND), - TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.OFFHAND) - ).filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET); + TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAIN_GLOVE, IS_BANGLE), + TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.SECONDARY_GLOVE, IS_BANGLE) + ); } - public static Stream getWornBangles(LivingEntity entity, Identifier slot) { - return TrinketsDelegate.getInstance(entity) - .getEquipped(entity, slot) - .filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET); + public static Stream getWornBangles(LivingEntity entity, @Nullable Predicate predicate) { + predicate = predicate == null ? IS_BANGLE : IS_BANGLE.and(predicate); + return Stream.concat( + TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAIN_GLOVE, predicate), + TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.SECONDARY_GLOVE, predicate) + ); + } + + public static Stream getWornBangles(LivingEntity entity, Identifier slot) { + return TrinketsDelegate.getInstance(entity).getEquipped(entity, slot, IS_BANGLE); } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/GlassesItem.java b/src/main/java/com/minelittlepony/unicopia/item/GlassesItem.java index 3c49931e..0e88bead 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/GlassesItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/GlassesItem.java @@ -25,13 +25,12 @@ public class GlassesItem extends WearableItem { } public boolean isApplicable(LivingEntity entity) { - return getForEntity(entity).getItem() == this; + return getForEntity(entity).stack().isOf(this); } - public static ItemStack getForEntity(LivingEntity entity) { - return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE) - .filter(stack -> stack.getItem() instanceof GlassesItem) + public static TrinketsDelegate.EquippedStack getForEntity(LivingEntity entity) { + return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE, stack -> stack.getItem() instanceof GlassesItem) .findFirst() - .orElse(ItemStack.EMPTY); + .orElse(TrinketsDelegate.EquippedStack.EMPTY); } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/PegasusAmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/PegasusAmuletItem.java index b80e5f94..65cdb292 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/PegasusAmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/PegasusAmuletItem.java @@ -25,11 +25,6 @@ public class PegasusAmuletItem extends AmuletItem implements ItemTracker.Trackab } - @Override - public boolean isApplicable(ItemStack stack) { - return super.isApplicable(stack); - } - @Override public int getDefaultCharge() { return getMaxCharge() / 2; diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 6b012f20..ce6b0bcf 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -220,6 +220,7 @@ public interface UItems { .rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS); AmuletItem PEARL_NECKLACE = register("pearl_necklace", new AmuletItem(new FabricItemSettings() .maxCount(1) + .maxDamage(4) .rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS); GlassesItem SUNGLASSES = register("sunglasses", new GlassesItem(new FabricItemSettings().maxCount(1)), ItemGroups.COMBAT); diff --git a/src/main/java/com/minelittlepony/unicopia/network/Channel.java b/src/main/java/com/minelittlepony/unicopia/network/Channel.java index f7464deb..ee3b3025 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/Channel.java +++ b/src/main/java/com/minelittlepony/unicopia/network/Channel.java @@ -37,6 +37,7 @@ public interface Channel { S2CPacketType SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new); S2CPacketType CONFIGURATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("config"), MsgConfigurationChange::new); S2CPacketType SERVER_ZAP_STAGE = SimpleNetworking.serverToClient(Unicopia.id("zap_stage"), MsgZapAppleStage::new); + S2CPacketType SERVER_TRINKET_BROKEN = SimpleNetworking.serverToClient(Unicopia.id("trinket_broken"), MsgTrinketBroken::new); static void bootstrap() { ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgTrinketBroken.java b/src/main/java/com/minelittlepony/unicopia/network/MsgTrinketBroken.java new file mode 100644 index 00000000..d2d38104 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgTrinketBroken.java @@ -0,0 +1,22 @@ +package com.minelittlepony.unicopia.network; + +import com.sollace.fabwork.api.packets.Packet; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketByteBuf; + +/** + * Sent to the client when an item equipped in a trinket slot breaks + */ +public record MsgTrinketBroken (ItemStack stack, int entityId) implements Packet { + public MsgTrinketBroken(PacketByteBuf buffer) { + this(buffer.readItemStack(), buffer.readInt()); + } + + @Override + public void toBuffer(PacketByteBuf buffer) { + buffer.writeItemStack(stack); + buffer.writeInt(entityId); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/handler/ClientNetworkHandlerImpl.java b/src/main/java/com/minelittlepony/unicopia/network/handler/ClientNetworkHandlerImpl.java index e17dc1ff..c014bce5 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/handler/ClientNetworkHandlerImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/network/handler/ClientNetworkHandlerImpl.java @@ -20,8 +20,14 @@ import com.minelittlepony.unicopia.network.*; import com.minelittlepony.unicopia.network.MsgCasterLookRequest.Reply; import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.particle.ItemStackParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.sound.SoundEvents; import net.minecraft.util.Identifier; +import net.minecraft.util.math.Vec3d; public class ClientNetworkHandlerImpl { private final MinecraftClient client = MinecraftClient.getInstance(); @@ -36,6 +42,7 @@ public class ClientNetworkHandlerImpl { Channel.SERVER_ZAP_STAGE.receiver().addPersistentListener(this::handleZapStage); Channel.SERVER_PLAYER_ANIMATION_CHANGE.receiver().addPersistentListener(this::handlePlayerAnimation); Channel.SERVER_REQUEST_PLAYER_LOOK.receiver().addPersistentListener(this::handleCasterLookRequest); + Channel.SERVER_TRINKET_BROKEN.receiver().addPersistentListener(this::handleTrinketBroken); Channel.CONFIGURATION_CHANGE.receiver().addPersistentListener(this::handleConfigurationChange); } @@ -96,6 +103,37 @@ public class ClientNetworkHandlerImpl { Channel.CLIENT_CASTER_LOOK.sendToServer(new Reply(packet.spellId(), Rot.of(player))); } + private void handleTrinketBroken(PlayerEntity player, MsgTrinketBroken packet) { + if (player.getWorld().getEntityById(packet.entityId()) instanceof LivingEntity sender) { + ItemStack stack = packet.stack(); + if (!stack.isEmpty()) { + if (!sender.isSilent()) { + sender.getWorld().playSound( + sender.getX(), sender.getY(), sender.getZ(), + SoundEvents.ENTITY_ITEM_BREAK, sender.getSoundCategory(), + 0.8F, + 0.8F + sender.getWorld().random.nextFloat() * 0.4F, + false + ); + } + + int count = 5; + + for (int i = 0; i < count; ++i) { + Vec3d vec3d = new Vec3d((sender.getWorld().random.nextFloat() - 0.5) * 0.1, Math.random() * 0.1 + 0.1, 0.0); + vec3d = vec3d.rotateX(-sender.getPitch() * (float) (Math.PI / 180.0)); + vec3d = vec3d.rotateY(-sender.getYaw() * (float) (Math.PI / 180.0)); + double d = (-sender.getWorld().random.nextFloat()) * 0.6 - 0.3; + Vec3d vec3d2 = new Vec3d((sender.getWorld().random.nextFloat() - 0.5) * 0.3, d, 0.6); + vec3d2 = vec3d2.rotateX(-sender.getPitch() * (float) (Math.PI / 180.0)); + vec3d2 = vec3d2.rotateY(-sender.getYaw() * (float) (Math.PI / 180.0)); + vec3d2 = vec3d2.add(sender.getX(), sender.getEyeY(), sender.getZ()); + sender.getWorld().addParticle(new ItemStackParticleEffect(ParticleTypes.ITEM, stack), vec3d2.x, vec3d2.y, vec3d2.z, vec3d.x, vec3d.y + 0.05, vec3d.z); + } + } + } + } + private void handleConfigurationChange(PlayerEntity sender, MsgConfigurationChange packet) { InteractionManager.getInstance().setSyncedConfig(packet.config()); } From 302a0337104b497ca743e1b9f42dc16599ae0d51 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 23 Jun 2024 15:37:24 +0100 Subject: [PATCH 80/85] Don't allow flying whilst in a boat. Fixes #377 --- .../minelittlepony/unicopia/ability/ToggleFlightAbility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java index 66aa0050..d1a45aa2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java @@ -27,7 +27,7 @@ public class ToggleFlightAbility implements Ability { @Nullable @Override public Optional prepare(Pony player) { - return Hit.of(!player.asEntity().isCreative() && !player.getPhysics().getFlightType().isGrounded()); + return Hit.of(!player.asEntity().hasVehicle() && !player.asEntity().isCreative() && !player.getPhysics().getFlightType().isGrounded()); } @Override From 86b0530f4552c51f4886f77f3985ee6a19a8a317 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 23 Jun 2024 15:42:13 +0100 Subject: [PATCH 81/85] Make nuts and seeds less nutricious to other races. Fixes #363 --- .../unicopia/datagen/providers/FoodGroupsGenerator.java | 2 +- .../java/com/minelittlepony/unicopia/item/UFoodComponents.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java index 0b6e6fa5..5a804f43 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java @@ -39,7 +39,7 @@ public class FoodGroupsGenerator { )))); exporter.accept(Unicopia.id("nuts_and_seeds"), new FoodGroupEffects.Builder() .tag(UConventionalTags.Items.GRAIN).tag(UConventionalTags.Items.NUTS).tag(UConventionalTags.Items.SEEDS) - .food(UFoodComponents.BANANA) + .food(UFoodComponents.SEEDS) ); exporter.accept(Unicopia.id("pinecone"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.PINECONES).food(UFoodComponents.PINECONE).ailment(new HealingAffliction(1))); diff --git a/src/main/java/com/minelittlepony/unicopia/item/UFoodComponents.java b/src/main/java/com/minelittlepony/unicopia/item/UFoodComponents.java index 165425f5..f278d3ad 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UFoodComponents.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UFoodComponents.java @@ -67,6 +67,7 @@ public interface UFoodComponents { FoodComponent ACORN = builder(1, 0.01F).snack().alwaysEdible().build(); FoodComponent MANGO = builder(8, 0.8F).alwaysEdible().build(); FoodComponent BANANA = builder(6, 0.9F).build(); + FoodComponent SEEDS = builder(1, 0.2F).build(); FoodComponent CANDY = builder(7, 0.9F).alwaysEdible().build(); FoodComponent SALT_CUBE = builder(0, 2.9F).alwaysEdible().build(); From bf5a29e8d51b575e965cc0bf25bdeff429e00e66 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 23 Jun 2024 15:45:57 +0100 Subject: [PATCH 82/85] Reduce saturation from leaves and nerf hay bales again. Fixes #371 --- .../unicopia/datagen/providers/FoodGroupsGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java index 5a804f43..a30de498 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java @@ -61,9 +61,9 @@ public class FoodGroupsGenerator { new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 12) ))); exporter.accept(Unicopia.id("foraging/dangerous"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_DANGEROUS).food(3, 0.3F).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(250), Range.of(2), 4))); - exporter.accept(Unicopia.id("foraging/edible_filling"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_FILLING).food(17, 0.6F)); + exporter.accept(Unicopia.id("foraging/edible_filling"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_FILLING).food(7, 0.1F)); exporter.accept(Unicopia.id("foraging/edible"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SAFE).food(2, 1)); - exporter.accept(Unicopia.id("foraging/leafy_greens"), new FoodGroupEffects.Builder().tag(ItemTags.LEAVES).food(1, 1.4F)); + exporter.accept(Unicopia.id("foraging/leafy_greens"), new FoodGroupEffects.Builder().tag(ItemTags.LEAVES).food(1, 0)); exporter.accept(Unicopia.id("foraging/nauseating"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_NAUSEATING).food(5, 0.5F).ailment(CompoundAffliction.of( new StatusEffectAffliction(StatusEffects.WEAKNESS, Range.of(200), Range.of(1), 30), new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(200), Range.of(2), 0) From d4e3feacee8469b865538102ce339c44fba99174 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 23 Jun 2024 16:57:47 +0100 Subject: [PATCH 83/85] Fixed ability cooldown not ticking when there is not ability in the slot. Fixes #366 --- .../unicopia/ability/AbilityDispatcher.java | 10 ++++++++++ .../unicopia/client/gui/ManaRingSlot.java | 2 -- .../com/minelittlepony/unicopia/client/gui/Slot.java | 11 +++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java b/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java index 457abd1c..93eacb89 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java @@ -172,6 +172,16 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable { } public void tick() { + Optional> activeAbility = getActiveAbility(); + + if (activeAbility.isEmpty()) { + if (warmup > 0) { + warmup--; + } + if (cooldown > 0) { + cooldown--; + } + } getActiveAbility().ifPresent(ability -> { if (warmup > 0) { warmup--; diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/ManaRingSlot.java b/src/main/java/com/minelittlepony/unicopia/client/gui/ManaRingSlot.java index d9e88921..fa9f3d05 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/ManaRingSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/ManaRingSlot.java @@ -23,8 +23,6 @@ class ManaRingSlot extends Slot { protected void renderContents(DrawContext context, AbilityDispatcher abilities, boolean bSwap, float tickDelta) { MatrixStack matrices = context.getMatrices(); - - matrices.push(); matrices.translate(24.125, 24.75, 0); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java b/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java index 4d1e0ec0..80b7ef78 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java @@ -89,10 +89,15 @@ class Slot { bSwap &= abilities.isFilled(bSlot); } + int page = Unicopia.getConfig().hudPage.get(); AbilityDispatcher.Stat stat = abilities.getStat(bSwap ? bSlot : aSlot); - if (stat.getAbility(Unicopia.getConfig().hudPage.get()).isEmpty()) { - return; + if (stat.getAbility(page).isEmpty()) { + if (aSlot != AbilitySlot.PRIMARY + || (!abilities.getStat(AbilitySlot.SECONDARY).getAbility(page).isEmpty() + && !abilities.getStat(AbilitySlot.TERTIARY).getAbility(page).isEmpty())) { + return; + } } RenderSystem.setShaderColor(1, 1, 1, 1); @@ -104,8 +109,6 @@ class Slot { // background context.drawTexture(UHud.HUD_TEXTURE, 0, 0, backgroundU, backgroundV, size, size, 128, 128); - - int iconPosition = ((size - iconSize + slotPadding + 1) / 2); int sz = iconSize - slotPadding; uHud.renderAbilityIcon(context, stat, iconPosition, iconPosition, sz, sz, sz, sz); From f6668eff72237e9b5155f92b44f2d07138a35404 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 23 Jun 2024 16:59:02 +0100 Subject: [PATCH 84/85] Added seapony's grace/seapony's ire status effects. Mining blocks in a monument will cause seaponies to lose their grace. Fixes #390 --- .../com/minelittlepony/unicopia/UTags.java | 1 + .../com/minelittlepony/unicopia/Unicopia.java | 3 + .../providers/tag/UBlockTagProvider.java | 6 ++ .../effect/SeaponyGraceStatusEffect.java | 85 ++++++++++++++++++ .../unicopia/entity/effect/UEffects.java | 3 + .../unicopia/entity/player/Pony.java | 6 +- .../mixin/MixinGuardianTargetPredicate.java | 20 +++-- .../unicopia/mixin/MixinPufferfishEntity.java | 16 ++-- .../resources/assets/unicopia/lang/en_us.json | 2 + .../textures/mob_effect/seaponys_grace.png | Bin 0 -> 9502 bytes .../textures/mob_effect/seaponys_ire.png | Bin 0 -> 9781 bytes 11 files changed, 119 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/effect/SeaponyGraceStatusEffect.java create mode 100644 src/main/resources/assets/unicopia/textures/mob_effect/seaponys_grace.png create mode 100644 src/main/resources/assets/unicopia/textures/mob_effect/seaponys_ire.png diff --git a/src/main/java/com/minelittlepony/unicopia/UTags.java b/src/main/java/com/minelittlepony/unicopia/UTags.java index 0dc7cec4..7d16f2bc 100644 --- a/src/main/java/com/minelittlepony/unicopia/UTags.java +++ b/src/main/java/com/minelittlepony/unicopia/UTags.java @@ -107,6 +107,7 @@ public interface UTags { TagKey MIMIC_CHESTS = block("mimic_chests"); TagKey BUTTERFLIES_SPAWNABLE_ON = block("butterflies_spawn_on"); + TagKey ANGERS_GUARDIANS = block("angers_guardians"); private static TagKey block(String name) { return TagKey.of(RegistryKeys.BLOCK, Unicopia.id(name)); diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index 29c01867..8142560d 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; @@ -22,6 +23,7 @@ import com.minelittlepony.unicopia.container.UScreenHandlers; import com.minelittlepony.unicopia.diet.DietsLoader; import com.minelittlepony.unicopia.diet.affliction.AfflictionType; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; +import com.minelittlepony.unicopia.entity.effect.SeaponyGraceStatusEffect; import com.minelittlepony.unicopia.entity.effect.UPotions; import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.item.UItems; @@ -76,6 +78,7 @@ public class Unicopia implements ModInitializer { Debug.runTests(w); } }); + PlayerBlockBreakEvents.AFTER.register(SeaponyGraceStatusEffect::processBlockChange); NocturnalSleepManager.bootstrap(); registerServerDataReloaders(ResourceManagerHelper.get(ResourceType.SERVER_DATA)); diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java index 0908bbc6..66ea54f0 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java @@ -49,6 +49,12 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider { Blocks.COMMAND_BLOCK, Blocks.CHAIN_COMMAND_BLOCK, Blocks.REPEATING_COMMAND_BLOCK, Blocks.LIGHT, Blocks.JIGSAW, Blocks.BARRIER, Blocks.BEDROCK ).forceAddTag(BlockTags.DOORS).forceAddTag(BlockTags.TRAPDOORS); + getOrCreateTagBuilder(UTags.Blocks.ANGERS_GUARDIANS).add( + Blocks.PRISMARINE, Blocks.PRISMARINE_SLAB, Blocks.PRISMARINE_STAIRS, Blocks.PRISMARINE_WALL, + Blocks.PRISMARINE_BRICKS, Blocks.PRISMARINE_BRICK_SLAB, Blocks.PRISMARINE_BRICK_STAIRS, + Blocks.DARK_PRISMARINE, Blocks.DARK_PRISMARINE_SLAB, Blocks.DARK_PRISMARINE_STAIRS, + Blocks.SEA_LANTERN, Blocks.SPONGE + ); getOrCreateTagBuilder(UTags.Blocks.BUTTERFLIES_SPAWNABLE_ON).forceAddTag(BlockTags.ANIMALS_SPAWNABLE_ON).forceAddTag(BlockTags.LEAVES).forceAddTag(BlockTags.FLOWERS).forceAddTag(BlockTags.FLOWER_POTS); getOrCreateTagBuilder(UTags.Blocks.JARS).add(UBlocks.JAR, UBlocks.CLOUD_JAR, UBlocks.STORM_JAR, UBlocks.LIGHTNING_JAR, UBlocks.ZAP_JAR); getOrCreateTagBuilder(BlockTags.CROPS).add(crops); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/SeaponyGraceStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/SeaponyGraceStatusEffect.java new file mode 100644 index 00000000..46eee096 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/SeaponyGraceStatusEffect.java @@ -0,0 +1,85 @@ +package com.minelittlepony.unicopia.entity.effect; + +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.USounds; +import com.minelittlepony.unicopia.UTags; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.mob.GuardianEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.structure.StructureStart; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.StructureKeys; + +public class SeaponyGraceStatusEffect { + + public static void update(LivingEntity entity) { + if (entity.getWorld().isClient) { + return; + } + if (EquinePredicates.PLAYER_SEAPONY.test(entity)) { + if (!entity.hasStatusEffect(UEffects.SEAPONYS_GRACE) && !entity.hasStatusEffect(UEffects.SEAPONYS_IRE)) { + entity.addStatusEffect(new StatusEffectInstance(UEffects.SEAPONYS_GRACE, StatusEffectInstance.INFINITE, 0, false, true)); + } + } else if (entity.hasStatusEffect(UEffects.SEAPONYS_GRACE)) { + entity.removeStatusEffect(UEffects.SEAPONYS_GRACE); + } + } + + public static boolean hasIre(LivingEntity entity, MobEntity enemy) { + return enemy.getAttacker() == entity || hasIre(entity); + } + + public static boolean hasGrace(LivingEntity entity) { + boolean isSeapony = EquinePredicates.PLAYER_SEAPONY.test(entity); + return isSeapony && entity.hasStatusEffect(UEffects.SEAPONYS_GRACE) && !entity.hasStatusEffect(UEffects.SEAPONYS_IRE); + } + + public static boolean hasIre(LivingEntity entity) { + return !EquinePredicates.PLAYER_SEAPONY.test(entity) || entity.hasStatusEffect(UEffects.SEAPONYS_IRE); + } + + public static void processBlockChange(World world, PlayerEntity player, BlockPos pos, BlockState stateBroken, @Nullable BlockEntity blockEntity) { + + if (!(world instanceof ServerWorld sw)) { + return; + } + + if (!hasGrace(player)) { + return; + } + + if (!stateBroken.isIn(UTags.Blocks.ANGERS_GUARDIANS)) { + return; + } + StructureStart start = sw.getStructureAccessor().getStructureContaining(pos, StructureKeys.MONUMENT); + if (start.getStructure() == null) { + return; + } + + List guardians = sw.getEntitiesByClass(GuardianEntity.class, player.getBoundingBox().expand(10), EntityPredicates.VALID_LIVING_ENTITY); + + if (guardians.size() > 0) { + guardians.forEach(guardian -> { + guardian.setTarget(player); + guardian.playAmbientSound(); + }); + + player.removeStatusEffect(UEffects.SEAPONYS_GRACE); + player.addStatusEffect(new StatusEffectInstance(UEffects.SEAPONYS_IRE, 90000, 0, false, true)); + world.playSound(null, pos, USounds.Vanilla.ENTITY_ELDER_GUARDIAN_CURSE, SoundCategory.PLAYERS, 1, 1); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java index 586a053b..798a7289 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java @@ -24,6 +24,9 @@ public interface UEffects { */ StatusEffect BUTTER_FINGERS = register("butter_fingers", new ButterfingersStatusEffect(0x888800)); + StatusEffect SEAPONYS_GRACE = register("seaponys_grace", new SimpleStatusEffect(StatusEffectCategory.BENEFICIAL, 0x0000EE, false)); + StatusEffect SEAPONYS_IRE = register("seaponys_ire", new SimpleStatusEffect(StatusEffectCategory.HARMFUL, 0xEE00EE, false)); + private static StatusEffect register(String name, StatusEffect effect) { return Registry.register(Registries.STATUS_EFFECT, Unicopia.id(name), effect); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 845cb09c..cfe236a9 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -24,6 +24,7 @@ import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.effect.MetamorphosisStatusEffect; +import com.minelittlepony.unicopia.entity.effect.SeaponyGraceStatusEffect; import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect; import com.minelittlepony.unicopia.entity.effect.UEffects; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; @@ -414,6 +415,8 @@ public class Pony extends Living implements Copyable, Update powers.tick(); acrobatics.tick(); + SeaponyGraceStatusEffect.update(entity); + if (getObservedSpecies() == Race.KIRIN) { var charge = getMagicalReserves().getCharge(); @@ -484,9 +487,6 @@ public class Pony extends Living implements Copyable, Update AmuletSelectors.PEARL_NECKLACE.test(entity) ? suppressedRace.or(Race.SEAPONY) : null ); UCriteria.PLAYER_CHANGE_RACE.trigger(entity); - - var hasNecklace = AmuletSelectors.PEARL_NECKLACE.test(entity); - System.out.println(hasNecklace); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinGuardianTargetPredicate.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinGuardianTargetPredicate.java index b7beed91..3b2f31b2 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinGuardianTargetPredicate.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinGuardianTargetPredicate.java @@ -1,21 +1,23 @@ package com.minelittlepony.unicopia.mixin; import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import com.minelittlepony.unicopia.EquinePredicates; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.minelittlepony.unicopia.entity.effect.SeaponyGraceStatusEffect; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.GuardianEntity; @Mixin(targets = "net.minecraft.entity.mob.GuardianEntity$GuardianTargetPredicate") abstract class MixinGuardianTargetPredicate { - @Inject(method = "test", at = @At("HEAD"), cancellable = true) - private void test(@Nullable LivingEntity livingEntity, CallbackInfoReturnable info) { - if (EquinePredicates.PLAYER_SEAPONY.test(livingEntity)) { - info.setReturnValue(false); - } + @Shadow + private @Final GuardianEntity owner; + + @ModifyReturnValue(method = "test", at = @At("RETURN")) + private boolean unicopia_excludeSeaponysGrace(boolean result, @Nullable LivingEntity target) { + return result && SeaponyGraceStatusEffect.hasIre(target, owner); } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPufferfishEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPufferfishEntity.java index 1e799247..9231dafa 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPufferfishEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPufferfishEntity.java @@ -2,12 +2,8 @@ package com.minelittlepony.unicopia.mixin; 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.CallbackInfoReturnable; - -import com.minelittlepony.unicopia.Race; -import com.minelittlepony.unicopia.entity.player.Pony; - +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.minelittlepony.unicopia.entity.effect.SeaponyGraceStatusEffect; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.passive.FishEntity; import net.minecraft.entity.passive.PufferfishEntity; @@ -16,10 +12,8 @@ import net.minecraft.entity.passive.PufferfishEntity; abstract class MixinPufferfishEntity extends FishEntity { MixinPufferfishEntity() { super(null, null); } - @Inject(method = "method_6591(Lnet/minecraft/entity/LivingEntity;)Z", at = @At("HEAD"), cancellable = true) - private static void onShouldTarget(LivingEntity entity, CallbackInfoReturnable info) { - Pony.of(entity).filter(pony -> pony.getCompositeRace().includes(Race.SEAPONY)).ifPresent(pony -> { - info.setReturnValue(false); - }); + @ModifyReturnValue(method = "method_6591(Lnet/minecraft/entity/LivingEntity;)Z", at = @At("RETURN")) + private static boolean unicopia_excludeSeaponysGrace(boolean result, LivingEntity entity) { + return result && !SeaponyGraceStatusEffect.hasGrace(entity); } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index af76a3ba..3d8903f2 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -408,6 +408,8 @@ "effect.unicopia.butter_fingers": "Butterfingers", "effect.unicopia.fortification": "Fortification", "effect.unicopia.broken_wings": "Broken Wings", + "effect.unicopia.seaponys_ire": "Seaponys Ire", + "effect.unicopia.seaponys_grace": "Seaponys Grace", "effect.unicopia.change_race_earth": "Earth Pony Metamorphosis", "effect.unicopia.change_race_unicorn": "Unicorn Metamorphosis", diff --git a/src/main/resources/assets/unicopia/textures/mob_effect/seaponys_grace.png b/src/main/resources/assets/unicopia/textures/mob_effect/seaponys_grace.png new file mode 100644 index 0000000000000000000000000000000000000000..d8ec0b418f7f5bda8da8b0bd7fc2edbf1d3e09e8 GIT binary patch literal 9502 zcmeHNc{r49+n=$GHA_QCnx@52!)&&xv5zgvpt8o8MH9w0LY5|EOAC^slqrfzluANn zDg`6=)Mjq4jZgw zBvmD0Fqn*uwS^;i%0W$B4BVG~oTbBH5|%6%8@7#&7EB!2q+l?(2n_z+5B^JE2rdj0 z2KEfl7QlsI3gCGJGzDOX{Gp}_7oB?+gZ|?0{Y#*a`R)VF$Ah^t;8_V80rZjJc^5QJ z(tO>6EdO*+IXBc(EuRg2qZF2 zk4zw<@ZfGpCgDLwi5Uo(3YhZ_v|q1(MVEkmgU#mw@%fp)7KV>QeP3s%mPe71|mo^qS>rY8ZXZH8?zpL|Uq0NHHL+(gxbJsi-@LNb& zL{tnRE+Hue9InVgN(l>z2#bn}h=9=;Fb)%u7gbn>Hx*k*qa)D4NW$*)eDURGWw#X_ zAAMLs^a+WRkW^ZvtfIPdl?Fyri=?ZkZ(v9^x1d^DS=-n;Id9s$#l_W)!DO+0w{fd~ zy4Uu&{Ygh>*VFFazTf%>UJnipkBp6foS6JHH9hkg;sx>iam_RP3om)VOGrdSSOfv_ zf(wO1#N|aqm*K?}Olb&u@Io|Uw>Z))J-_U>#B!qJ2SuNdN0Le_NWCk^AZl~W{%^$M z{v&2TiT%N=8zwCb2a6{x4>N|%d`rcgM9`>6_;%2dET>UndY~h5R*(t{K+;TP1gRJ} zWF`ObTLP>~&~OGcVFC=f0Ux2`z%2iWii82I9}VvF!vzW4pcW%aMQ#a7qEQu5V3rnt z;xk52V>c$dN|3tx%|`#3cd3{X_+bn{zeq(oh#Ue_q9&0v&)Owar1S1KBpNlks88J< zfILy}0w~^LJQ_79tsmqwDldbiIW8X}V+0lVBryWMVK+ulwXkkoZ7SwsG364lA6!a) zL{+>?XaKpYPePd_Zxf`ZFEs_$Mp_HF_vEScx6`OGw9&%=@}w3pp|${eDieUVhc^=B z6IxEAMrb5LU8qHdA!%NlqpVtZG-@ysvP2Dlg!wTDfUm4Jill9o=-mSXih{O85&Rr` z2X)mUC0q`~0OALI*Mfdr1RYR@|I!fk?KEoCor*b7NCh9tC!mk%2_qU+u?tZOk{dsh z$a9`^iU82xWdbW%EOY^g0l+rRikz{Fc%pjg-lgfN)`w62QwNX6a~`d(}CQgsesRFfB*xT@{RbwUI7KL-k$^Jsl-E-_pY5r z4V7*H)cE%RTi%D}O7J)|B@H4SY*~}e&s=8$bb>)zH4F(-Kc9L= z(FPh>x`5XY)&pRMg$K8TSLPOk_@jMRfL2$16rkXm-7tb9%19d3WiPl1>jIydQ+1L+ zDyZRx0H)KkHGq`#10aud4={9D#eu9Ef3Sz1h(~{6%o+i(YG6@J)WfLA&9#(TkZjgE zbFlkdJVmJm;|;ycCe9G;FaRzq3F!`jiGob{7-;H43P5 zPFNi(iasRR1WtNDG0%XQ(5yc;yIr$SB_BE)!(fs)j=8ymjk!50C?t^0@n^wc5yy@n z4tI9$R7z^C4&Ryo0Eg5xe_t(ws@5-Rv!EYQ@x}-*Ad(6K;liUm_5N%qVqyYa?~;gkAc=X|yK-pJVN z68&0whpKxs1^qH-Wq-2r*rH&XQg$Y`&mG-ir&t(F{e81qZX=y7#7C!$3N2V|Q(uT) zHCAW#+@cBzQ_~zF&A)-wxm zGyawCJKe-Gv!!nJ9XDQY>ET{^_HGCJYDb6V>qfSh;>b(jfF03g4ev!yGKjG8sheFSSs|3>i2IjYTc+|;23Ojk?v@hqO)V{YuR~lK z`{KUk&kldkpLjBr)-e1HBm3fb<}GBQPeygPO!|35Qz? zX*s~OOoWGomU}Po=Tm~j)Nd^kiNnc>ZiXva3vu|emrRYi#8XWqy5KwFw>wCwnk?J~ z*DygC$Y}HL_mC^#+<1hyNLu`$w^$YYqnrqR8Np&V61B-%iokDPCe|+=Y4XiM94Xph znj$BwU^eq`)mag(q~d(?S&7f;WKmCkiCO$Z$~I(9Tx`w2<+&{e7}@lw5`L5d!-OXHvQN__~M)>|iJoa8Idmy=f&Bq}eHu9uOp5TuJF95`>D znr?eqonu;gaBKf6LY&?5_YTTPQL2?n{#)A1vjZ5V?Yi5S6eBn7BgbvGnmoxBSkj1R zH*O=iNd)k(ntwUD{87q~KTp0=;YBjn+{^5h<$+VLym88^mIy}tSfd3!1Mi0`IP&$# z=H|#|6kD3Ox4}oTRLlk8k2;*9=)Jczs_ahbV5xam@LP8^`7^1+JCS{Y;B_AG5`}PN zxRQQC?yU#E6?|}uSR0MX+t=EV-MjdM=QR9xgV;Qj{ljGja<$@33HuVX%%pl1dYAPo zrdvB}bSuQCc=U<+D2^G7Nd_O9-oL`UP2+mHkF{Cbjy8H*WE-VzHR0%a`yH#SGDZ7G z`&W%q#~I`95~&Gg2?s>neX1??S=^{USTAK$b^7q>z5QBE>zZtvGBboT9y>;8259PQ z7Pga%REwM(>l`n)AvwfhlVQ@Zr=CjxrBI0Y;M~kNpm~Jvo6}m+3ZSvy57({^5QskfTNg`dfE1p?VfwC zS(=+ti%)57xneeXY=l_3=Ea^o+lzv!hraEH+N+)z= z+3$0R)$UK)Zb$s2uZ??$i=_)V3IUfMpYH6>EXv{(bK-}Ei7G^|%R-m6FTZ*)`M~wH z?(1u7?keRey}^>PTisM$Le|K-yu2cC5p@YD8@c*VmPB{zbsFlgy>^8=_(DEhXUb

z^mQi0K-%qH2qJ5&zkY<{vyQfPgN5_`W?D@Ru z3uUZxYVb?A=q-2+{DzRa_G7n3_YQe+p%|fXQ6tGV3AZH^4BRRMOvS2cPO__YtaTt} zB}s2$+fXj9v-DCa;(l1RRCajM`oud4`g>Zb6;_9=(kyZ;O7>N$7brLE8%b-lOtR9q zY%TfVQWn(^k+#W>)_gpRygGFAR?mV8t*|FYU7B3jZ<`Ew9v06ZRme7*uqmN>FEwJl zewV(#?@H3-vC-xd?~TD~1_Q@ZM3NH56PhfN>OE7OY&O_r**x~p=ju+eE`^5#jCCr{8%U596BKes$^l6832>-lc`ZVss*^HGQ16c)n*eSRwoS7xnTYU^6iS%d#lIFh?(RN~o}`{(a3czf$@ z&uGQv$DG0Rkm2#F@iI^NjqcS$iVcbv!|%MSapSnU-bgC7s_;F1?`Co6#n&&FL>W74 zYO9TnBD zQ(L6I>r>40sqhWc$A^rX44#h1cgTL}#soBsIz(~5*jYK=vG#Qy?9qJX^uqI#XMnNl zY{YbV_izsJlJC71g%+hePlN1m?x*O+nPI7vMU9n=8%sUXsv^#5RGgX3cvY}Eo1)|O zHf)#@-q3q*_}q>y8$B5wZz{Mk)zz)V7e_VDo#_62;mb3GzZf~N>*bKD2RUNLUCvOg z{Zwvt;LP*N*r=zYx7Xf(|9r`Q74_@)Yt}~UOuoGT#dT_MseeRrtjq7#BeVfV!JSFt zH(#HVeJCO9_L%bbHba>R#`&_ro6K+H^r{bXHdpttDS4-eN4Cu#?V`0C&d4Gnd0 z1RVka3p}u)kz5`<0?Q3u4nfRgSg=AFA)Fu{CyN4aQMF@(T#ExBm&x z4gIbH&_gGJ9;AcU#_0qE==?e(ltX$DsS*=b@MkvSnaM039qRCxGtD(h1`F&c%QPC!0FhP|yVJdDl6MgFl_e1`{Y~ zI}SH2;tyA6P5{e^M~BqJ>*Edax_Y_>cmq8HoFV=Xr_HR8P*8~w=G^)5+z7NRWIzT8 zONZ(d0L<9|7xLVJabSpZV4yz*4J9yl^89ny9=uLWI*)Dv&a46G&$DRfA7|04adJpXI{r$1-zRYIZWUJ5duF;5|s zzJoQt-T-TUh_Q{%^<{zG<9oUOuyg)RDUeutdZ23PSe79kR1*`gi#233=vXGhK$ng8 zAu-r&!#NdxqK5{udExXBmZ>k$5oiUkX5bb>z7P~YIsN&n{*^{@ou zUu)t!#dSK+w)kUF*XjJrvd=sGvX263=51hq2HU;P&;9zxxED}N1uA$%qv<_CIFKPkLtoR z4-9}lJYfIw2NYX&FIWWr#v$Ft!qnN|{-%ue+ZNK0i8l?2N1K@$WAbu)CF9JfuB`QYF&Jx8xoBrUM!TB@?ctv3*tZ^%l}@JFIg$bgkK~KnN9&4*>-T5Asn#}2 zeC_ojs^|Bq*_P{i{A4*1xUFUyzM^C=%N3@~kdya+X6a|Ion1E-lZHo1imKfScCeMF z%G;-i+hm-c`o_>t>qdOiAPspS(t>;u^S z1>Z!QgnH_O(~3KlmEZQlr=(4+n)3IK!j7%+4B&8!zXruU9wf031}}kWRX^q}P#O~C zhRg=k>xtZs-jE#_-&FcJVS~(8^&&lmZ5QN&i!@GK4t!g?qPX!^Q(k#*?e#BJi_ozb*2xkL5UiMp)&vhu-CGkC<@sOacpwgqN)a;_eF_A%P_%no;--2;`{ zHW@)vuboz{+LeHlFG1J?UZor>~!4(FU#X#@7tqm8$Yh=Gq8k}cW~am^UQTT-IQVjYizWP zoE|cy8yHg`RpK3j)sk@1kKqe8B|fdVe*F4Jp_-Blu#-1xdLoV9bX?2S>Bno?>?+0- zoZWm5TXxF2%!lQE|K&CAv*&Rcv0q-(cf7s2M@o6|;(@Umd6-i5ke#3Xp~CY|FFvoH zX^&p~wfThG@$P1%534IE|LzAqr|9_2h+9J9b)`>E7JZH4(vCQ-xGVMg#Dl3vHrk%= lSDlzj5vb&>PW$c1?BZH20rPoCE2viJ5oY{{WJherf;! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/mob_effect/seaponys_ire.png b/src/main/resources/assets/unicopia/textures/mob_effect/seaponys_ire.png new file mode 100644 index 0000000000000000000000000000000000000000..9c560cb3915de87558e3a600959e68294543da98 GIT binary patch literal 9781 zcmeHNc|6oz+n=#-Wof8Xj8PeCn2i}z6Jl(o49Z#=voK;TGq#FkH)$g&Bu2C=X_06{ z8&OiEmB>=vvQx=>ewOZfpXdF&@BMt9=l$!RKIeDNoO4~@bA7+pb$(-hO|tzut66gD zaxfTdmW{QA1L&2YCL;x|ngbII7)&;m?P9~RvC)IcfH`>>3@!nKPuszN8H>TiVd7vu z6|~uKF_;SI4}+!x<{^8islz2F`_o{&V0wHJjM39JkUtLi&H{ZIXm~J2fc`#c+{CGU zUxBd<0F#;gXCBOE2-qxS7+2tfw6d|Yht-L}U~_=YOb<;W@%lKdK7kAnv3Mc{Yec~l zkT@d>0S5*kqJ&gw*nHsg2WY>({t;ak_5(H*2gGMa3y9Q=7SMP`i)~;mKFtkMRO*+p z>Mxw(VpEvWkni+Z1(F-Qrg%;?PrQRE*;?9If{h?C!DZql%p4{oB_%B-DI+Z{Eh{S{ zr+}EHATO^lUuBLWVv)M0#v=8F3z3WUb&#m#+6xz=NxI9iI3kg#sbfqf<5%hvhwh= zDQOv5IeB1kSqV}~Tuee-Qc^+!tVV)$n1r&ViWbgHY7U(tjS52GcOA%+(OzAATh-yo zm&F9H;22pswYl@=t1nrqgVxm}8XA$v#uRf4nx&Psjjf~8hKvRn>Rz-GA_~ z;c4Tu=S|HoT3XxQw|9K#?CS36>mL{#8Xg%P`wH=bc+R}0nEf|i%7B-cgoL<+G{g%o z76uVlmXOrKNvW98r5QnUQ21Rkh}8%3if_wm6CA#%dIdj`Q(H`IUD5|pn`HKXBNp>7 zG5bmEPhKrB1#vh?p13m11UB|Vh|ZO!(-3f9Fp#@Mr@@TCK=!0a2=hnKO=pROXgD-W znXy|0X4RnORLEfvEV%(2v7=yG`3VgH16VT+?lohA0A^4N1@;m5y7Pg5?qc9(gc1pL z=gZR&PARQmZg5|%JY?n!A=;uv(bTU(bW!VUkxeE@P5D(0Kh;K?`#1k>l^QasOD#55cEy=K1d27;2sEA z=?P60wJH`MrsTihh8C5-AAHhCr`f9j^99P_l9JRV62@wGfsHB%lc?fCVBKhVP`u_NQ7_gerPHqwI@ zl~ry3jG%kOt|Ee%YE5ib?FRi*6C*i5a8(!>*O}NYq9HcGmmuh7#i|Ip^?f(A=(snR zhS*rx(SjBgFRlSr1nm@XHJ`J8%6kC~VK4pIiB1cZ8SzDnt|jaU10f%dIvhC%^tn-- z9etqBj>^Of(Ps#&AU#UIH$yQ&ZEP5bFlPvNkWQ2GwgOPTL4XlIhZ_ncS~mdg(O`nn z1N0LjL2S<9$-paj1 z4EWV)Hgp32jdu(5(4vcE8YmH4V-PM#Q>ramv`YyHsE`2aPx0hQk?;@Y_X0XC+^R#y8W)Bw9753D7FC1TelNJ^T_R!L|Fj6zN2SA`Pl^k{;0GjkkR-<2B6f~OH~n~&sKpOlU_=l1Eh59J^+_Ju;vn- z<{Jjx2sS5=1%hPG+^V1+-USp3I#z@@366HsUVv~P+@AFI1_8*_J#J{xRjOAyf^HuK z?sKX~B%J6pdL2M=px*;|=suPm59FN-d|~;Z>_O%H)}*fjr;od$z?o47xj!3i3vO2m z+d$EHCjs}iUBRI8p}VLPFQxmX~2LIV{)Q+}_6A92poKz~TC_VX*M* zqldzroSM`U>np;xOiMm{ft?Jpm{RxWUnizeno zYqoXR?n@CCGQYtUzQDw5VV)Q91hLiB%4q9V8oa@^2j+~TWTHu7Rm)(cJ>{`of-e&` znd!IZCN)STH^)4Bz)CK)uR8T2Mxi*;vZ`?ufvZI0258cV;_}0D=Dzq+Qjc1(`^eF| z%-t?KJ}88$yVp`tZ!(v(C(Y}d8$?&jNW-+bqn@u-EexW4-?%XAE`uW$jY|G3HhY;( zRUv9=U*+mo7Uc-oLfyV)dnbgF*$a1#I`F#ZU)#a+N{ue6X~@rd(Sq-Kll{qQuc;@Z zidBFe^DA@T<|dVvA%CmwsL2{j5BIW@_n&jFJb!Na;Vx&3YR^sH54+^;*R9XTn2ach zh9Zl{)3$jxS=q8L)Q$Nk$a=aIbR&LuX;`xgkf2X%Eu zAA()(w#EF&o9O;R8hkdAQr-Ont@!$A+ATz(TvuCJaf9R2_#N9gQfbwB3&taoCW78= zIaY~{OS{#|4;Li`J~bWtMYC1SGD1_?W_W07c1>4krLbKDOC<1P?BJ1;VpI{kQ=P!@zJ$fQtdJkra$au z5R%nq$x4bUtH&NMJt?7=csh@AQueC`MRHSg(dyX8R3AiUOjP2VN}07Wr!L^n&dR!_ z&@4F|Tlp?M5LK>T7c1ZTIZ)L@Q8V^stNfRcQKOY&CW+q4(MrndqJ()`3RSaYEkp+- z;`W_27ap)ZuE8}c+rPPeDL!VccCYego0A=AHD5#DMW+!P_E2Jct%h=W zB1<~q=eO%$}! z174&Oh6qz5#bw=k^uFMWTlk6{$eca()fue|zHAzWeQd$96>?Sr&b@zkdd z;ky31B;CSB$|?0zjt-R$B@GBJq1&{Z*zM4r-{4%J!@huT!E50Cj;uanj-SiEi7KUBP=Cii4>hJG;tdwc=DDjZ(vizgD zuk$K091rmiyua_Cw)Mb*)U32EsNUuE2Mi7cq~F9$Y~EG$E^oi+f@7X}>j9K4eGAS7 z=iV3HwxqgyN#l~?H7;v}8QCtuTVyvjILp!9@&(qX)^j(y(q61FHjg;pPwU{SW(rGe zFWSaGbWPXYAUvI~=X`nfP<9WYZ29Z>9NY7vk;mSR2OGf$v3(` z)8r}<=c&u8tE#_NCuE+^glCRrKFS=q{KZY-+~RXow+c6Y3#CQ5#r@KXOFAL#Av*;9 zg3J(&p45<|0_TspK=$E{G zH1x>zgW-p(%kQh@sC~pxFq_@fU4oY@y1cn8a*=fLFYdYW)yJRt=qj%`=i-w~$t5qm z3AMTSn0W;$%dYsiJHH&da>D=Z3)h#jpVl>xa{^e$ymmH51)r*OsB1_lV9xHDy*81O zsBBfn%zkfnPg%!Mr_izD=^XD_-dFhf197`^)?BQ?Wy~!qEZWgz)MQLrarH8<^R;rA z!HCyLl;Zq-9U9Lx_EDcv=TNh#-sNY@pNAhEvE2SGqIXbZm_E!HBaYRMwu}}HeeTm9 zi~qXe8?~=#r1M*tkab%$$iyxsqf3{La+6%G zqpSnaONd5;K3!SZrVAG@NY{j9$Y+Elu1UBTM~bhfm0BINO0meaDB4r5Q82H1PfyBS z%S0=ZWqr{Xm*VZ!;VB!|(rb^VQP&Zh@tfrrJbC#8zDrW`8Y z=#5U)mhTERdoCvqWq+6@r_B1&xsyx9xb{#3I_2_X+^0yX{!!1_R|mIF1GN7{&+^%VG_k$dhi;) z#L-lBeC?2INPJd&zUy9BL)U1=pg6m*XJ`oyJxmp87Be;PNJ&Q`qCsMmC;@rKELYWUTbH~f8_{FZaShaV0LZ@0dGAZKY-VPU?lRZV6qhcVDte3(hP!JjB9sXkdy zl>Xc;c;Uji8asz0UyX#V8$H^!>H+yhf9!L`Z!Kv5>d*GudEeGrIoz}McItem`_}RG zrr}NgCh8O6qnBE`GYJ>HAJ(bVspV`UXN2*FcibK8mQS90w~TpR(<7xk{ESZNiHX#= z1{VIR_7|UTuc+yLwP^2rjcYYGRzw&Ky{Y-;I?}1>7oHU5^4+?J z-oY%mH)Qg0{1wHE8q8^oywq#cl_t$RTikh*^`oCr{zZ3;+Y#4e@$~pud$(@=sRi{L zS1#C@)3+n4tjoE3%SgrJ$iB*ex|>6fEb3Bjw%_y^tr$$dbEfh)rO&s{GjD`XABb_CxeuW|Pj%^@?*F)YN`RiXR^MF74rw4TCAJ;ySqq zT_TR+@CaPo=9N|W$F26HQ0fb?Q}b9q!$@AaD~B$q`+IUCwx?E=l& zK3wZztU|wla-bD3eukE5j)Oz@IH(AjAFrczjAY6*Y-V0b^*|0EL`15p1QR zT)=ZV^MGJBlBiGA$6{#V+)zAfl^k+qFpEQRu&|tl0Pmhf2PZ|R&J3ER+05b#%&&Gm^g7&Ad0+?JDWpc=1k_a3e-WbCn zbFdg9nZ&{{pbO53!8T?SI9LLU^$U~@k1t^Gm~03Nfa`Ms4xWf-b68$v49kmQj3F}F zMi{ao(+Gq2BC+wt1e_6(h5rR&eJ~ePCByI6s30g7fFc{VCJQ8GAp5 zfCC(;sI^>PNcf+oPF#PsqksXai6h~RafU`lWP-7=A=Zfar_n}sFdtMRggN;vdU6Fy z3k8q?!ZM&b1pt%tfD2{v;d4N+Q$Too1eE zFT>&}*s1U#IJ*EAmlN^7Swn{hxf0lelv{K8f`H(N$*HLm<;V`2dN=jfk2`skkjTkH zL18ebDDWAf?5TVMtf?iY4}<5;26vC?a-Esy{*zK5vW<*D)i5w@V;ra^7S0f3%waMx zEGF5IgYzOXIUM6j6@H@g12}>(MljpV8|VnM0_8cW6%sv}DBa(!!+h9K7Jy(FtRV(R za>9`*L}LnpFfEwDf1V;6$Ho!JBsPY?!g4S~q7fFuz~RUkqA}CRkbx%=j7j9*gZ|ek zf-^*bY65ReA>#i3DB_LTIFd1kg&~lb1Pl?-!x$6ESPYZIVluI8FOnB)s?`4tS)8Fb z`QJIeQ(S2P-T7zgcBR2TRQ8m?FCP^k`%`n^BM5w=8T|Z6n=T6w?|lHV^zQ8wS4ehFBZtf-lTc zUTdr@VA`81Fc>8;FmC!P=ntKILQK&(gGVhnsk@cTt&^fxWnvoU~0aA z<{~f;@Q1!z!T#a*CeFKN&jmjTiLkLSb0XJ7rrB9L(GmA{_TE?#@aA3$C&6*IjBH-R z>ZBB8)zxJ&x#^bnNsYEXst5^s-eCC;ObUS(-M_ z!B&L!+S+`@PD!F*Wb5fmNJ|x)y{ZzlI-Ga&l|67|LHqDID;Y=rr@gE;p0XgN>?^)j z-g!u6>8Zipk7h?LgVXBzEB9aV=MPwt7zadO#_dQ+&j|>2q7(q48}@XNhQs({a?aKSbH&%8_IC*;%(w>3VPT&3RMI7=D+2 z99`h@Rx9~qnTzXnRtANi8PI!o-n`NKDw1lCOT)8Q24$Bz({7;|^NLiHL`i-|yW_7X zQ*-hP`;^|a5jF2FiS|>Y(da?i(_g>dbsQ^{mk0B+JP^9Y!%tW9Z?Z4tA9u;@U(|gbnHZ+Qeif< LbrwadJ!Ae0Dar5Y literal 0 HcmV?d00001 From a6b16ec09f7a2fa00eec9146f6103d0f2a6806cf Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 23 Jun 2024 17:01:02 +0100 Subject: [PATCH 85/85] Remove debug code --- .../minelittlepony/unicopia/server/world/WeatherConditions.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java index ec505291..5199f57e 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java @@ -165,8 +165,6 @@ public class WeatherConditions extends PersistentState implements Tickable { final float terrainFactor = getScaledDistanceFromTerrain(probedPosition.set(pos), world, MAX_TERRAIN_HEIGHT); final float windFactor = getScaledDistanceFromTerrain(probedPosition.set(pos), world, MAX_WIND_HEIGHT); - System.out.println(terrainFactor + "/" + windFactor); - Vec3d terrainGradient = LOCAL_ALTITUDE_FIELD.computeAverage(world, pos, probedPosition).multiply(1 - terrainFactor); Vec3d thermalGradient = THERMAL_FIELD.computeAverage(world, pos, probedPosition).multiply(1 - terrainFactor); Vec3d wind = get(world).getWindDirection().multiply(windFactor);