diff --git a/gradle.properties b/gradle.properties index 934d874..5c6ed4a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.21.8 yarn_mappings=1.21.8+build.1 loader_version=0.17.2 # Mod Properties -mod_version=1.0 +mod_version=1.1 maven_group=com.kasetoatz archives_base_name=JukeboxBoat # Dependencies diff --git a/src/main/java/com/kasetoatz/jukeboxboat/interfaces/IAbstractBoatEntity.java b/src/main/java/com/kasetoatz/jukeboxboat/interfaces/IAbstractBoatEntity.java index 8b632a1..ddaac58 100644 --- a/src/main/java/com/kasetoatz/jukeboxboat/interfaces/IAbstractBoatEntity.java +++ b/src/main/java/com/kasetoatz/jukeboxboat/interfaces/IAbstractBoatEntity.java @@ -8,6 +8,6 @@ public interface IAbstractBoatEntity boolean jukeboxBoat$isJukeboxBoat(); void jukeboxBoat$setJukeboxBoat(boolean value); ItemStack jukeboxBoat$getStoredDisc(); - DisplayEntity.BlockDisplayEntity jukeboxBoat$getJukebox(); - void jukeboxBoat$setJukebox(DisplayEntity.BlockDisplayEntity jukebox); + String jukeboxBoat$getJukebox(); + void jukeboxBoat$setJukebox(String uuid); } diff --git a/src/main/java/com/kasetoatz/jukeboxboat/interfaces/IBlockDisplayEntity.java b/src/main/java/com/kasetoatz/jukeboxboat/interfaces/IBlockDisplayEntity.java new file mode 100644 index 0000000..f31faaa --- /dev/null +++ b/src/main/java/com/kasetoatz/jukeboxboat/interfaces/IBlockDisplayEntity.java @@ -0,0 +1,9 @@ +package com.kasetoatz.jukeboxboat.interfaces; + +import java.util.UUID; + +public interface IBlockDisplayEntity +{ + String jukeboxBoat$getUUID(); + void jukeboxBoat$setUUID(String uuid); +} diff --git a/src/main/java/com/kasetoatz/jukeboxboat/mixin/AbstractBoatEntityMixin.java b/src/main/java/com/kasetoatz/jukeboxboat/mixin/AbstractBoatEntityMixin.java index c1ea34a..0af342e 100644 --- a/src/main/java/com/kasetoatz/jukeboxboat/mixin/AbstractBoatEntityMixin.java +++ b/src/main/java/com/kasetoatz/jukeboxboat/mixin/AbstractBoatEntityMixin.java @@ -10,12 +10,16 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.vehicle.AbstractBoatEntity; import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.item.ItemStack; +import net.minecraft.network.packet.s2c.play.PlaySoundFromEntityS2CPacket; import net.minecraft.network.packet.s2c.play.PositionFlag; +import net.minecraft.registry.Registries; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.WorldEvents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -24,7 +28,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.EnumSet; -import java.util.UUID; import static com.kasetoatz.jukeboxboat.util.Util.*; @@ -98,32 +101,21 @@ public abstract class AbstractBoatEntityMixin implements IAbstractBoatEntity } @Override - public DisplayEntity.BlockDisplayEntity jukeboxBoat$getJukebox() + public String jukeboxBoat$getJukebox() { if ((Object)this instanceof BoatEntity boat) { - String uuid = boat.get(DataComponentTypes.CUSTOM_DATA).copyNbt().getString("jukebox", ""); - if (boat.getWorld().getEntity(UUID.fromString(uuid)) instanceof DisplayEntity.BlockDisplayEntity entity) - { - return entity; - } + return boat.get(DataComponentTypes.CUSTOM_DATA).copyNbt().getString("jukebox", ""); } return null; } @Override - public void jukeboxBoat$setJukebox(DisplayEntity.BlockDisplayEntity jukebox) + public void jukeboxBoat$setJukebox(String uuid) { if ((Object)this instanceof BoatEntity boat) { - if (jukebox == null) - { - boat.setComponent(DataComponentTypes.CUSTOM_DATA, boat.get(DataComponentTypes.CUSTOM_DATA).apply(nbtCompound -> nbtCompound.remove("jukebox"))); - } - else - { - boat.setComponent(DataComponentTypes.CUSTOM_DATA, boat.get(DataComponentTypes.CUSTOM_DATA).apply(nbtCompound -> nbtCompound.putString("jukebox", jukebox.getUuidAsString()))); - } + boat.setComponent(DataComponentTypes.CUSTOM_DATA, boat.get(DataComponentTypes.CUSTOM_DATA).apply(nbtCompound -> nbtCompound.putString("jukebox", uuid))); } } @@ -162,19 +154,19 @@ public abstract class AbstractBoatEntityMixin implements IAbstractBoatEntity return ActionResult.PASS; } stack.splitUnlessCreative(1, player); - DisplayEntity.BlockDisplayEntity jukebox = jukeboxBoat$getJukebox(); + DisplayEntity.BlockDisplayEntity jukebox = findJukebox(boat, jukeboxBoat$getJukebox()); if (jukebox == null) { jukebox = createJukebox(boat); } - player.getWorld().playSoundFromEntity( - null, - jukebox, - sound, - SoundCategory.RECORDS, - 1.0f, - 1.0f - ); + boat.getServer().getPlayerManager().sendToAll(new PlaySoundFromEntityS2CPacket( + Registries.SOUND_EVENT.getEntry(sound), + SoundCategory.RECORDS, + jukebox, + 1.f, + 1.f, + 0L + )); setPlaying(boat, true); setStoredDisc(storedDisc); setLastStateChange(); @@ -190,7 +182,7 @@ public abstract class AbstractBoatEntityMixin implements IAbstractBoatEntity if ((Object)this instanceof BoatEntity boat) { IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat; - DisplayEntity.BlockDisplayEntity jukebox = jukeboxBoat$getJukebox(); + DisplayEntity.BlockDisplayEntity jukebox = findJukebox(boat, jukeboxBoat$getJukebox()); if (!accessor.jukeboxBoat$isJukeboxBoat() || jukebox == null) { return; diff --git a/src/main/java/com/kasetoatz/jukeboxboat/mixin/BlockDisplayEntityMixin.java b/src/main/java/com/kasetoatz/jukeboxboat/mixin/BlockDisplayEntityMixin.java new file mode 100644 index 0000000..512bc80 --- /dev/null +++ b/src/main/java/com/kasetoatz/jukeboxboat/mixin/BlockDisplayEntityMixin.java @@ -0,0 +1,35 @@ +package com.kasetoatz.jukeboxboat.mixin; + +import com.kasetoatz.jukeboxboat.interfaces.IBlockDisplayEntity; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.DisplayEntity; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(DisplayEntity.BlockDisplayEntity.class) +public class BlockDisplayEntityMixin implements IBlockDisplayEntity +{ + @Override + public String jukeboxBoat$getUUID() + { + NbtComponent nbt = ((Entity)(Object)this).get(DataComponentTypes.CUSTOM_DATA); + if (nbt != null) + { + return nbt.copyNbt().getString("uuid").orElse(""); + } + return ""; + } + + @Override + public void jukeboxBoat$setUUID(String uuid) + { + Entity entity = ((Entity)(Object)this); + NbtComponent nbt = entity.get(DataComponentTypes.CUSTOM_DATA); + if (nbt != null) + { + nbt.apply(nbtCompound -> nbtCompound.putString("uuid", uuid)); + } + entity.setComponent(DataComponentTypes.CUSTOM_DATA, nbt); + } +} diff --git a/src/main/java/com/kasetoatz/jukeboxboat/mixin/BoatItemMixin.java b/src/main/java/com/kasetoatz/jukeboxboat/mixin/BoatItemMixin.java index 6c8ae93..145f218 100644 --- a/src/main/java/com/kasetoatz/jukeboxboat/mixin/BoatItemMixin.java +++ b/src/main/java/com/kasetoatz/jukeboxboat/mixin/BoatItemMixin.java @@ -31,14 +31,13 @@ public class BoatItemMixin { isJukeboxBoat = name.getString().equals("Boat with Jukebox"); } - IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat; - accessor.jukeboxBoat$setJukeboxBoat(isJukeboxBoat); + ((IAbstractBoatEntity)boat).jukeboxBoat$setJukeboxBoat(isJukeboxBoat); if (!isJukeboxBoat) { return; } spawnPlaceholder(boat); - accessor.jukeboxBoat$setJukebox(createJukebox(boat)); + createJukebox(boat); } } } diff --git a/src/main/java/com/kasetoatz/jukeboxboat/mixin/VehicleEntityMixin.java b/src/main/java/com/kasetoatz/jukeboxboat/mixin/VehicleEntityMixin.java index b3ac5ac..88b9b01 100644 --- a/src/main/java/com/kasetoatz/jukeboxboat/mixin/VehicleEntityMixin.java +++ b/src/main/java/com/kasetoatz/jukeboxboat/mixin/VehicleEntityMixin.java @@ -3,6 +3,7 @@ package com.kasetoatz.jukeboxboat.mixin; import com.kasetoatz.jukeboxboat.interfaces.IAbstractBoatEntity; import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.component.DataComponentTypes; +import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.decoration.DisplayEntity; import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.entity.vehicle.VehicleEntity; @@ -10,31 +11,46 @@ import net.minecraft.item.ItemStack; import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; 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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import static com.kasetoatz.jukeboxboat.util.Util.findJukebox; import static com.kasetoatz.jukeboxboat.util.Util.removePlaceholder; @Mixin(VehicleEntity.class) public abstract class VehicleEntityMixin { - @Inject(method="killAndDropItem", at=@At("HEAD")) - public void preKill(CallbackInfo ci) + @Unique + private void delete() { if ((Object)this instanceof BoatEntity boat) { IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat; - DisplayEntity.BlockDisplayEntity jukebox = accessor.jukeboxBoat$getJukebox(); + DisplayEntity.BlockDisplayEntity jukebox = findJukebox(boat, accessor.jukeboxBoat$getJukebox()); if (jukebox != null) { jukebox.discard(); - accessor.jukeboxBoat$setJukebox(null); + accessor.jukeboxBoat$setJukebox(""); } removePlaceholder(boat); } } + @Inject(method="damage", at=@At(value = "INVOKE", target = "Lnet/minecraft/entity/vehicle/VehicleEntity;discard()V")) + public void discard(CallbackInfoReturnable cir) + { + delete(); + } + + @Inject(method="damage", at= @At(value = "INVOKE", target = "Lnet/minecraft/entity/vehicle/VehicleEntity;killAndDropSelf(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/entity/damage/DamageSource;)V")) + public void preKill(CallbackInfoReturnable cir) + { + delete(); + } + @Inject(method="killAndDropItem", at=@At(value="INVOKE", target="Lnet/minecraft/entity/vehicle/VehicleEntity;dropStack(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/item/ItemStack;)Lnet/minecraft/entity/ItemEntity;")) public void killAndDropItem(CallbackInfo ci, @Local(argsOnly=true) ServerWorld world, @Local ItemStack stack) { diff --git a/src/main/java/com/kasetoatz/jukeboxboat/util/Util.java b/src/main/java/com/kasetoatz/jukeboxboat/util/Util.java index f191702..344c08f 100644 --- a/src/main/java/com/kasetoatz/jukeboxboat/util/Util.java +++ b/src/main/java/com/kasetoatz/jukeboxboat/util/Util.java @@ -2,11 +2,13 @@ package com.kasetoatz.jukeboxboat.util; import com.kasetoatz.jukeboxboat.interfaces.IAbstractBoatEntity; import com.kasetoatz.jukeboxboat.interfaces.IArmorStandEntity; +import com.kasetoatz.jukeboxboat.interfaces.IBlockDisplayEntity; import net.minecraft.block.Blocks; import net.minecraft.block.JukeboxBlock; import net.minecraft.block.jukebox.JukeboxSong; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.JukeboxPlayableComponent; +import net.minecraft.component.type.NbtComponent; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.decoration.ArmorStandEntity; @@ -16,12 +18,14 @@ import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.item.ItemStack; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKeys; +import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundEvent; import net.minecraft.util.math.AffineTransformation; import org.joml.Quaternionf; import org.joml.Vector3f; import java.util.Optional; +import java.util.UUID; public class Util { @@ -38,7 +42,7 @@ public class Util public static void setPlaying(BoatEntity boat, boolean playing) { - DisplayEntity.BlockDisplayEntity jukebox = ((IAbstractBoatEntity)boat).jukeboxBoat$getJukebox(); + DisplayEntity.BlockDisplayEntity jukebox = findJukebox(boat, ((IAbstractBoatEntity)boat).jukeboxBoat$getJukebox()); if (jukebox != null) { if (playing) @@ -63,6 +67,8 @@ public class Util new Quaternionf() )); boat.getWorld().spawnEntity(jukebox); + ((IBlockDisplayEntity)jukebox).jukeboxBoat$setUUID(jukebox.getUuidAsString()); + ((IAbstractBoatEntity)boat).jukeboxBoat$setJukebox(jukebox.getUuidAsString()); return jukebox; } @@ -92,13 +98,46 @@ public class Util public static void replaceJukebox(BoatEntity boat) { - IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat; - DisplayEntity.BlockDisplayEntity old = accessor.jukeboxBoat$getJukebox(); + DisplayEntity.BlockDisplayEntity old = findJukebox(boat, ((IAbstractBoatEntity)boat).jukeboxBoat$getJukebox()); if (old != null) { old.discard(); } - DisplayEntity.BlockDisplayEntity jukebox = createJukebox(boat); - accessor.jukeboxBoat$setJukebox(jukebox); + createJukebox(boat); + } + + private static DisplayEntity.BlockDisplayEntity iterateJukeboxes(BoatEntity boat, String uuid) + { + if (boat.getWorld() instanceof ServerWorld world) + { + for (Entity entity : world.iterateEntities()) + { + if (entity instanceof DisplayEntity.BlockDisplayEntity jukebox) + { + IBlockDisplayEntity accessor = (IBlockDisplayEntity)jukebox; + if (accessor.jukeboxBoat$getUUID().equals(uuid)) + { + ((IAbstractBoatEntity)accessor).jukeboxBoat$setJukebox(jukebox.getUuidAsString()); + accessor.jukeboxBoat$setUUID(jukebox.getUuidAsString()); + return jukebox; + } + } + } + } + return null; + } + + public static DisplayEntity.BlockDisplayEntity findJukebox(BoatEntity boat, String uuid) + { + if (uuid.isEmpty()) + { + return null; + } + Entity possible = boat.getWorld().getEntity(UUID.fromString(uuid)); + if (possible instanceof DisplayEntity.BlockDisplayEntity jukebox) + { + return jukebox; + } + return iterateJukeboxes(boat, uuid); } } diff --git a/src/main/resources/jukeboxboat.mixins.json b/src/main/resources/jukeboxboat.mixins.json index 4bf2c9a..d84b89e 100644 --- a/src/main/resources/jukeboxboat.mixins.json +++ b/src/main/resources/jukeboxboat.mixins.json @@ -6,6 +6,7 @@ "mixins": [ "AbstractBoatEntityMixin", "ArmorStandEntityMixin", + "BlockDisplayEntityMixin", "BoatItemMixin", "ShapelessRecipeMixin", "VehicleEntityMixin"