diff --git a/.github/workflows/push_build_and_release.yml b/.github/workflows/push_build_and_release.yml index 5f48e3a..00ebbc4 100644 --- a/.github/workflows/push_build_and_release.yml +++ b/.github/workflows/push_build_and_release.yml @@ -27,10 +27,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' - name: Validate Gradle Wrapper uses: gradle/actions/wrapper-validation@v3 @@ -63,10 +63,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' - name: Validate Gradle Wrapper uses: gradle/actions/wrapper-validation@v3 diff --git a/common/src/main/java/tocraft/remorphed/Remorphed.java b/common/src/main/java/tocraft/remorphed/Remorphed.java index 39b944a..e2fd793 100644 --- a/common/src/main/java/tocraft/remorphed/Remorphed.java +++ b/common/src/main/java/tocraft/remorphed/Remorphed.java @@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory; import tocraft.craftedcore.config.ConfigLoader; import tocraft.craftedcore.event.common.CommandEvents; +import tocraft.craftedcore.event.common.EntityEvents; import tocraft.craftedcore.event.common.PlayerEvents; import tocraft.craftedcore.network.ModernNetworking; import tocraft.craftedcore.platform.PlatformData; @@ -22,6 +23,8 @@ import tocraft.remorphed.command.RemorphedCommand; import tocraft.remorphed.config.RemorphedConfig; import tocraft.remorphed.events.ShapeEventsCallback; +import tocraft.remorphed.handler.LivingDeathHandler; +import tocraft.remorphed.handler.PlayerRespawnHandler; import tocraft.remorphed.impl.RemorphedPlayerDataProvider; import tocraft.remorphed.network.NetworkHandler; import tocraft.walkers.Walkers; @@ -54,6 +57,8 @@ public void initialize() { ShapeEvents.UNLOCK_SHAPE.register(((player, type) -> new ShapeEventsCallback().event(player, type))); ShapeEvents.SWAP_SHAPE.register(((player, shape) -> new ShapeEventsCallback().event(player, ShapeType.from(shape)))); CommandEvents.REGISTRATION.register(new RemorphedCommand()); + EntityEvents.LIVING_DEATH.register(new LivingDeathHandler()); + PlayerEvents.PLAYER_RESPAWN.register(new PlayerRespawnHandler()); // allow unlocking friendly mobs via the "normal" method Walkers.CONFIG.unlockOverridesCurrentShape = Remorphed.CONFIG.unlockFriendlyNormal; diff --git a/common/src/main/java/tocraft/remorphed/RemorphedClient.java b/common/src/main/java/tocraft/remorphed/RemorphedClient.java index 0bb22cf..21e76aa 100644 --- a/common/src/main/java/tocraft/remorphed/RemorphedClient.java +++ b/common/src/main/java/tocraft/remorphed/RemorphedClient.java @@ -5,8 +5,10 @@ import net.fabricmc.api.Environment; import net.minecraft.client.KeyMapping; import org.lwjgl.glfw.GLFW; +import tocraft.craftedcore.event.client.ClientPlayerEvents; import tocraft.craftedcore.event.client.ClientTickEvents; import tocraft.craftedcore.registration.KeyBindingRegistry; +import tocraft.remorphed.handler.client.ClientPlayerRespawnHandler; import tocraft.remorphed.network.ClientNetworking; import tocraft.remorphed.tick.KeyPressHandler; @@ -21,5 +23,7 @@ public void initialize() { // Register event handlers ClientTickEvents.CLIENT_PRE.register(new KeyPressHandler()); ClientNetworking.registerPacketHandlers(); + + ClientPlayerEvents.CLIENT_PLAYER_RESPAWN.register(new ClientPlayerRespawnHandler()); } } diff --git a/common/src/main/java/tocraft/remorphed/config/RemorphedConfig.java b/common/src/main/java/tocraft/remorphed/config/RemorphedConfig.java index eb9feae..29e7a76 100644 --- a/common/src/main/java/tocraft/remorphed/config/RemorphedConfig.java +++ b/common/src/main/java/tocraft/remorphed/config/RemorphedConfig.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; +@SuppressWarnings("CanBeFinal") public class RemorphedConfig implements Config { @Synchronize public boolean creativeUnlockAll = true; diff --git a/common/src/main/java/tocraft/remorphed/mixin/LivingEntityMixin.java b/common/src/main/java/tocraft/remorphed/handler/LivingDeathHandler.java similarity index 51% rename from common/src/main/java/tocraft/remorphed/mixin/LivingEntityMixin.java rename to common/src/main/java/tocraft/remorphed/handler/LivingDeathHandler.java index 448cc90..776ba14 100644 --- a/common/src/main/java/tocraft/remorphed/mixin/LivingEntityMixin.java +++ b/common/src/main/java/tocraft/remorphed/handler/LivingDeathHandler.java @@ -1,33 +1,22 @@ -package tocraft.remorphed.mixin; +package tocraft.remorphed.handler; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import tocraft.craftedcore.event.common.EntityEvents; import tocraft.remorphed.Remorphed; import tocraft.remorphed.impl.RemorphedPlayerDataProvider; import tocraft.walkers.api.PlayerShape; import tocraft.walkers.api.PlayerShapeChanger; import tocraft.walkers.api.variant.ShapeType; -@Mixin(LivingEntity.class) -public abstract class LivingEntityMixin extends Entity { - - private LivingEntityMixin(EntityType type, Level world) { - super(type, world); - } - - @Inject(method = "die", at = @At("HEAD")) - public void onDeath(DamageSource damageSource, CallbackInfo ci) { - if (!((Object) this instanceof Player) && damageSource.getEntity() instanceof ServerPlayer killer) { - ShapeType type = ShapeType.from((LivingEntity) (Object) this); +public class LivingDeathHandler implements EntityEvents.LivingDeath { + @Override + public InteractionResult die(LivingEntity entity, DamageSource source) { + if (!(entity instanceof Player) && source.getEntity() instanceof ServerPlayer killer) { + ShapeType type = ShapeType.from(entity); if (type != null) { ((RemorphedPlayerDataProvider) killer).remorphed$addKill(type); @@ -37,5 +26,7 @@ public void onDeath(DamageSource damageSource, CallbackInfo ci) { } } } + + return InteractionResult.PASS; } } diff --git a/common/src/main/java/tocraft/remorphed/handler/PlayerRespawnHandler.java b/common/src/main/java/tocraft/remorphed/handler/PlayerRespawnHandler.java new file mode 100644 index 0000000..63348b0 --- /dev/null +++ b/common/src/main/java/tocraft/remorphed/handler/PlayerRespawnHandler.java @@ -0,0 +1,16 @@ +package tocraft.remorphed.handler; + +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.server.level.ServerPlayer; +import tocraft.craftedcore.event.client.ClientPlayerEvents; +import tocraft.craftedcore.event.common.PlayerEvents; +import tocraft.remorphed.impl.RemorphedPlayerDataProvider; + +public class PlayerRespawnHandler implements PlayerEvents.PlayerRespawn { + @Override + public void clone(ServerPlayer oldPlayer, ServerPlayer newPlayer) { + ((RemorphedPlayerDataProvider) newPlayer).remorphed$setUnlockedShapes(((RemorphedPlayerDataProvider) oldPlayer).remorphed$getUnlockedShapes()); + ((RemorphedPlayerDataProvider) newPlayer).remorphed$getFavorites().clear(); + ((RemorphedPlayerDataProvider) newPlayer).remorphed$getFavorites().addAll(((RemorphedPlayerDataProvider) oldPlayer).remorphed$getFavorites()); + } +} diff --git a/common/src/main/java/tocraft/remorphed/handler/client/ClientPlayerRespawnHandler.java b/common/src/main/java/tocraft/remorphed/handler/client/ClientPlayerRespawnHandler.java new file mode 100644 index 0000000..ee5d159 --- /dev/null +++ b/common/src/main/java/tocraft/remorphed/handler/client/ClientPlayerRespawnHandler.java @@ -0,0 +1,14 @@ +package tocraft.remorphed.handler.client; + +import net.minecraft.client.player.LocalPlayer; +import tocraft.craftedcore.event.client.ClientPlayerEvents; +import tocraft.remorphed.impl.RemorphedPlayerDataProvider; + +public class ClientPlayerRespawnHandler implements ClientPlayerEvents.ClientPlayerRespawn { + @Override + public void respawn(LocalPlayer oldPlayer, LocalPlayer newPlayer) { + ((RemorphedPlayerDataProvider) newPlayer).remorphed$setUnlockedShapes(((RemorphedPlayerDataProvider) oldPlayer).remorphed$getUnlockedShapes()); + ((RemorphedPlayerDataProvider) newPlayer).remorphed$getFavorites().clear(); + ((RemorphedPlayerDataProvider) newPlayer).remorphed$getFavorites().addAll(((RemorphedPlayerDataProvider) oldPlayer).remorphed$getFavorites()); + } +} diff --git a/common/src/main/java/tocraft/remorphed/mixin/ClientPlayerDataCacheMixin.java b/common/src/main/java/tocraft/remorphed/mixin/ClientPlayerDataCacheMixin.java deleted file mode 100644 index 4056e19..0000000 --- a/common/src/main/java/tocraft/remorphed/mixin/ClientPlayerDataCacheMixin.java +++ /dev/null @@ -1,49 +0,0 @@ -package tocraft.remorphed.mixin; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl; -import net.minecraft.client.multiplayer.ClientPacketListener; -import net.minecraft.client.multiplayer.CommonListenerCookie; -import net.minecraft.network.Connection; -import net.minecraft.network.protocol.game.ClientboundRespawnPacket; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import tocraft.remorphed.impl.RemorphedPlayerDataProvider; - -@Environment(EnvType.CLIENT) -@Mixin(ClientPacketListener.class) -public abstract class ClientPlayerDataCacheMixin extends ClientCommonPacketListenerImpl { - @Unique - private RemorphedPlayerDataProvider remorphed$dataCache = null; - - protected ClientPlayerDataCacheMixin(Minecraft minecraft, Connection connection, CommonListenerCookie commonListenerCookie) { - super(minecraft, connection, commonListenerCookie); - } - - // This @Inject caches the custom data attached to this client's player before it - // is reset when changing dimensions. - // For example, switching from The End => Overworld will reset the player's NBT. - @Inject(method = "handleRespawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;createPlayer(Lnet/minecraft/client/multiplayer/ClientLevel;Lnet/minecraft/stats/StatsCounter;Lnet/minecraft/client/ClientRecipeBook;ZZ)Lnet/minecraft/client/player/LocalPlayer;")) - private void beforePlayerReset(ClientboundRespawnPacket packet, CallbackInfo ci) { - remorphed$dataCache = ((RemorphedPlayerDataProvider) minecraft.player); - } - - // This inject applies data cached from the previous inject. - // Re-applying on the client will help to prevent sync blips which occur when - // wiping data and waiting for the server to send a sync packet. - @Inject(method = "handleRespawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;dimension()Lnet/minecraft/resources/ResourceKey;", ordinal = 1)) - private void afterPlayerReset(ClientboundRespawnPacket packet, CallbackInfo ci) { - if (remorphed$dataCache != null && minecraft.player != null) { - ((RemorphedPlayerDataProvider) minecraft.player).remorphed$setUnlockedShapes(remorphed$dataCache.remorphed$getUnlockedShapes()); - ((RemorphedPlayerDataProvider) minecraft.player).remorphed$getFavorites().clear(); - ((RemorphedPlayerDataProvider) minecraft.player).remorphed$getFavorites().addAll(remorphed$dataCache.remorphed$getFavorites()); - } - - remorphed$dataCache = null; - } -} \ No newline at end of file diff --git a/common/src/main/java/tocraft/remorphed/mixin/PlayerEntityMixin.java b/common/src/main/java/tocraft/remorphed/mixin/PlayerEntityMixin.java index 3aff263..5210b9b 100644 --- a/common/src/main/java/tocraft/remorphed/mixin/PlayerEntityMixin.java +++ b/common/src/main/java/tocraft/remorphed/mixin/PlayerEntityMixin.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Set; +@SuppressWarnings({"DataFlowIssue", "resource", "ControlFlowStatementWithoutBraces"}) @Mixin(Player.class) public abstract class PlayerEntityMixin extends LivingEntity implements RemorphedPlayerDataProvider { @Unique diff --git a/common/src/main/java/tocraft/remorphed/mixin/ServerPlayerEntityMixin.java b/common/src/main/java/tocraft/remorphed/mixin/ServerPlayerEntityMixin.java deleted file mode 100644 index 695910f..0000000 --- a/common/src/main/java/tocraft/remorphed/mixin/ServerPlayerEntityMixin.java +++ /dev/null @@ -1,21 +0,0 @@ -package tocraft.remorphed.mixin; - -import net.minecraft.server.level.ServerPlayer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import tocraft.remorphed.impl.RemorphedPlayerDataProvider; - -@Mixin(ServerPlayer.class) -public class ServerPlayerEntityMixin { - - @Inject(method = "restoreFrom", at = @At("TAIL")) - private void copyWalkersData(ServerPlayer oldPlayer, boolean alive, CallbackInfo ci) { - RemorphedPlayerDataProvider oldData = ((RemorphedPlayerDataProvider) oldPlayer); - RemorphedPlayerDataProvider newData = ((RemorphedPlayerDataProvider) this); - - // Transfer data from the old ServerPlayer -> new ServerPlayer - newData.remorphed$setUnlockedShapes(oldData.remorphed$getUnlockedShapes()); - } -} diff --git a/common/src/main/java/tocraft/remorphed/network/NetworkHandler.java b/common/src/main/java/tocraft/remorphed/network/NetworkHandler.java index 3ae29ea..26c5e9e 100644 --- a/common/src/main/java/tocraft/remorphed/network/NetworkHandler.java +++ b/common/src/main/java/tocraft/remorphed/network/NetworkHandler.java @@ -42,7 +42,7 @@ public static void sendSwap2ndShapeRequest(@NotNull Sha ModernNetworking.sendToServer(NetworkHandler.SHAPE_REQUEST, compound); } - @SuppressWarnings({"ALL"}) + @SuppressWarnings({"DataFlowIssue", "unchecked"}) private static void handleShapeRequestPacket(ModernNetworking.Context context, CompoundTag compound) { context.getPlayer().getServer().execute(() -> { // check if player is blacklisted @@ -88,7 +88,7 @@ public static void sendFavoriteRequest(ShapeType type, b ModernNetworking.sendToServer(FAVORITE_UPDATE, packet); } - @SuppressWarnings("ALL") + @SuppressWarnings({"unchecked", "DataFlowIssue"}) private static void handleFavoriteRequestPacket(ModernNetworking.Context context, CompoundTag packet) { EntityType entityType = (EntityType) BuiltInRegistries.ENTITY_TYPE.get(new ResourceLocation(packet.getString("id"))); int variant = packet.getInt("variant"); diff --git a/common/src/main/java/tocraft/remorphed/screen/RemorphedScreen.java b/common/src/main/java/tocraft/remorphed/screen/RemorphedScreen.java index 82de4fe..860ef8e 100644 --- a/common/src/main/java/tocraft/remorphed/screen/RemorphedScreen.java +++ b/common/src/main/java/tocraft/remorphed/screen/RemorphedScreen.java @@ -31,6 +31,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; +@SuppressWarnings({"DataFlowIssue", "SequencedCollectionMethodCanBeUsed"}) @Environment(EnvType.CLIENT) public class RemorphedScreen extends Screen { private final List> unlocked = new CopyOnWriteArrayList<>(); @@ -210,7 +211,7 @@ private void populateEntityWidgets(List> rendered) { addRenderableWidget(entityWidget); entityWidgets.add(entityWidget); } else { - Remorphed.LOGGER.error("invalid shape type: " + type.getEntityType().getDescriptionId()); + Remorphed.LOGGER.error("invalid shape type: {}", type.getEntityType().getDescriptionId()); } } } diff --git a/common/src/main/java/tocraft/remorphed/screen/widget/EntityWidget.java b/common/src/main/java/tocraft/remorphed/screen/widget/EntityWidget.java index 45317e9..c02c5d5 100644 --- a/common/src/main/java/tocraft/remorphed/screen/widget/EntityWidget.java +++ b/common/src/main/java/tocraft/remorphed/screen/widget/EntityWidget.java @@ -104,7 +104,7 @@ public void renderWidget(GuiGraphics context, int mouseX, int mouseY, float delt // ARGH InventoryScreen.renderEntityInInventory(context, getX() + (float) this.getWidth() / 2, (int) (getY() + this.getHeight() * .75f), size, new Vector3f(), new Quaternionf().rotationXYZ(0.43633232F, (float) Math.PI, (float) Math.PI), null, entity); } catch (Exception e) { - Remorphed.LOGGER.error("Error while rendering " + ShapeType.createTooltipText(entity).getString(), e); + Remorphed.LOGGER.error("Error while rendering {}", ShapeType.createTooltipText(entity).getString(), e); crashed = true; MultiBufferSource.BufferSource immediate = Minecraft.getInstance().renderBuffers().bufferSource(); immediate.endBatch(); diff --git a/common/src/main/resources/remorphed.mixins.json b/common/src/main/resources/remorphed.mixins.json index 3367f04..e8d165c 100644 --- a/common/src/main/resources/remorphed.mixins.json +++ b/common/src/main/resources/remorphed.mixins.json @@ -4,14 +4,11 @@ "package": "tocraft.remorphed.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "LivingEntityMixin", "PlayerEntityMixin", "PlayerListMixin", - "ServerEntityMixin", - "ServerPlayerEntityMixin" + "ServerEntityMixin" ], "client": [ - "ClientPlayerDataCacheMixin", "accessor.ScreenAccessor" ], "injectors": { diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..3d4be78 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,42 @@ +modLoader = "javafml" +loaderVersion = "[1,)" +issueTrackerURL = "https://github.com/ToCraft/Remorphed/issues" +displayURL = "https://github.com/ToCraft/Remorphed" +license = "MIT" + +[[mixins]] +config = "remorphed.mixins.json" + +[[mods]] +modId = "remorphed" +version = "${version}" +displayName = "ReMorphed" +authors = "To_Craft" +credits = "Original mod by Draylar" +description = ''' +Transform like in the old-school morph mod! +''' +logoFile = "icon.png" + +[[dependencies.remorphed]] +modId = "minecraft" +mandatory = true +versionRange = "[${minecraft_version},)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.remorphed]] +modId = "craftedcore" +mandatory = true +type = "required" +versionRange = "[${craftedcore_version},)" +ordering = "AFTER" +side = "BOTH" + +[[dependencies.remorphed]] +modId = "walkers" +mandatory = true +type = "required" +versionRange = "[${woodwalkers_version},)" +ordering = "AFTER" +side = "BOTH"