This commit is contained in:
KäseToatz
2025-08-23 02:27:04 +02:00
parent 1403d6dbed
commit 4b3a2add69
9 changed files with 132 additions and 41 deletions

View File

@@ -6,7 +6,7 @@ minecraft_version=1.21.8
yarn_mappings=1.21.8+build.1 yarn_mappings=1.21.8+build.1
loader_version=0.17.2 loader_version=0.17.2
# Mod Properties # Mod Properties
mod_version=1.0 mod_version=1.1
maven_group=com.kasetoatz maven_group=com.kasetoatz
archives_base_name=JukeboxBoat archives_base_name=JukeboxBoat
# Dependencies # Dependencies

View File

@@ -8,6 +8,6 @@ public interface IAbstractBoatEntity
boolean jukeboxBoat$isJukeboxBoat(); boolean jukeboxBoat$isJukeboxBoat();
void jukeboxBoat$setJukeboxBoat(boolean value); void jukeboxBoat$setJukeboxBoat(boolean value);
ItemStack jukeboxBoat$getStoredDisc(); ItemStack jukeboxBoat$getStoredDisc();
DisplayEntity.BlockDisplayEntity jukeboxBoat$getJukebox(); String jukeboxBoat$getJukebox();
void jukeboxBoat$setJukebox(DisplayEntity.BlockDisplayEntity jukebox); void jukeboxBoat$setJukebox(String uuid);
} }

View File

@@ -0,0 +1,9 @@
package com.kasetoatz.jukeboxboat.interfaces;
import java.util.UUID;
public interface IBlockDisplayEntity
{
String jukeboxBoat$getUUID();
void jukeboxBoat$setUUID(String uuid);
}

View File

@@ -10,12 +10,16 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractBoatEntity; import net.minecraft.entity.vehicle.AbstractBoatEntity;
import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.s2c.play.PlaySoundFromEntityS2CPacket;
import net.minecraft.network.packet.s2c.play.PositionFlag; import net.minecraft.network.packet.s2c.play.PositionFlag;
import net.minecraft.registry.Registries;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvent;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; 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.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; 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 org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.UUID;
import static com.kasetoatz.jukeboxboat.util.Util.*; import static com.kasetoatz.jukeboxboat.util.Util.*;
@@ -98,32 +101,21 @@ public abstract class AbstractBoatEntityMixin implements IAbstractBoatEntity
} }
@Override @Override
public DisplayEntity.BlockDisplayEntity jukeboxBoat$getJukebox() public String jukeboxBoat$getJukebox()
{ {
if ((Object)this instanceof BoatEntity boat) if ((Object)this instanceof BoatEntity boat)
{ {
String uuid = boat.get(DataComponentTypes.CUSTOM_DATA).copyNbt().getString("jukebox", ""); return boat.get(DataComponentTypes.CUSTOM_DATA).copyNbt().getString("jukebox", "");
if (boat.getWorld().getEntity(UUID.fromString(uuid)) instanceof DisplayEntity.BlockDisplayEntity entity)
{
return entity;
}
} }
return null; return null;
} }
@Override @Override
public void jukeboxBoat$setJukebox(DisplayEntity.BlockDisplayEntity jukebox) public void jukeboxBoat$setJukebox(String uuid)
{ {
if ((Object)this instanceof BoatEntity boat) if ((Object)this instanceof BoatEntity boat)
{ {
if (jukebox == null) boat.setComponent(DataComponentTypes.CUSTOM_DATA, boat.get(DataComponentTypes.CUSTOM_DATA).apply(nbtCompound -> nbtCompound.putString("jukebox", uuid)));
{
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())));
}
} }
} }
@@ -162,19 +154,19 @@ public abstract class AbstractBoatEntityMixin implements IAbstractBoatEntity
return ActionResult.PASS; return ActionResult.PASS;
} }
stack.splitUnlessCreative(1, player); stack.splitUnlessCreative(1, player);
DisplayEntity.BlockDisplayEntity jukebox = jukeboxBoat$getJukebox(); DisplayEntity.BlockDisplayEntity jukebox = findJukebox(boat, jukeboxBoat$getJukebox());
if (jukebox == null) if (jukebox == null)
{ {
jukebox = createJukebox(boat); jukebox = createJukebox(boat);
} }
player.getWorld().playSoundFromEntity( boat.getServer().getPlayerManager().sendToAll(new PlaySoundFromEntityS2CPacket(
null, Registries.SOUND_EVENT.getEntry(sound),
jukebox, SoundCategory.RECORDS,
sound, jukebox,
SoundCategory.RECORDS, 1.f,
1.0f, 1.f,
1.0f 0L
); ));
setPlaying(boat, true); setPlaying(boat, true);
setStoredDisc(storedDisc); setStoredDisc(storedDisc);
setLastStateChange(); setLastStateChange();
@@ -190,7 +182,7 @@ public abstract class AbstractBoatEntityMixin implements IAbstractBoatEntity
if ((Object)this instanceof BoatEntity boat) if ((Object)this instanceof BoatEntity boat)
{ {
IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat; IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat;
DisplayEntity.BlockDisplayEntity jukebox = jukeboxBoat$getJukebox(); DisplayEntity.BlockDisplayEntity jukebox = findJukebox(boat, jukeboxBoat$getJukebox());
if (!accessor.jukeboxBoat$isJukeboxBoat() || jukebox == null) if (!accessor.jukeboxBoat$isJukeboxBoat() || jukebox == null)
{ {
return; return;

View File

@@ -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);
}
}

View File

@@ -31,14 +31,13 @@ public class BoatItemMixin
{ {
isJukeboxBoat = name.getString().equals("Boat with Jukebox"); isJukeboxBoat = name.getString().equals("Boat with Jukebox");
} }
IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat; ((IAbstractBoatEntity)boat).jukeboxBoat$setJukeboxBoat(isJukeboxBoat);
accessor.jukeboxBoat$setJukeboxBoat(isJukeboxBoat);
if (!isJukeboxBoat) if (!isJukeboxBoat)
{ {
return; return;
} }
spawnPlaceholder(boat); spawnPlaceholder(boat);
accessor.jukeboxBoat$setJukebox(createJukebox(boat)); createJukebox(boat);
} }
} }
} }

View File

@@ -3,6 +3,7 @@ package com.kasetoatz.jukeboxboat.mixin;
import com.kasetoatz.jukeboxboat.interfaces.IAbstractBoatEntity; import com.kasetoatz.jukeboxboat.interfaces.IAbstractBoatEntity;
import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.decoration.DisplayEntity; import net.minecraft.entity.decoration.DisplayEntity;
import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.entity.vehicle.VehicleEntity; import net.minecraft.entity.vehicle.VehicleEntity;
@@ -10,31 +11,46 @@ import net.minecraft.item.ItemStack;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 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; import static com.kasetoatz.jukeboxboat.util.Util.removePlaceholder;
@Mixin(VehicleEntity.class) @Mixin(VehicleEntity.class)
public abstract class VehicleEntityMixin public abstract class VehicleEntityMixin
{ {
@Inject(method="killAndDropItem", at=@At("HEAD")) @Unique
public void preKill(CallbackInfo ci) private void delete()
{ {
if ((Object)this instanceof BoatEntity boat) if ((Object)this instanceof BoatEntity boat)
{ {
IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat; IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat;
DisplayEntity.BlockDisplayEntity jukebox = accessor.jukeboxBoat$getJukebox(); DisplayEntity.BlockDisplayEntity jukebox = findJukebox(boat, accessor.jukeboxBoat$getJukebox());
if (jukebox != null) if (jukebox != null)
{ {
jukebox.discard(); jukebox.discard();
accessor.jukeboxBoat$setJukebox(null); accessor.jukeboxBoat$setJukebox("");
} }
removePlaceholder(boat); removePlaceholder(boat);
} }
} }
@Inject(method="damage", at=@At(value = "INVOKE", target = "Lnet/minecraft/entity/vehicle/VehicleEntity;discard()V"))
public void discard(CallbackInfoReturnable<Boolean> 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<Boolean> 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;")) @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) public void killAndDropItem(CallbackInfo ci, @Local(argsOnly=true) ServerWorld world, @Local ItemStack stack)
{ {

View File

@@ -2,11 +2,13 @@ package com.kasetoatz.jukeboxboat.util;
import com.kasetoatz.jukeboxboat.interfaces.IAbstractBoatEntity; import com.kasetoatz.jukeboxboat.interfaces.IAbstractBoatEntity;
import com.kasetoatz.jukeboxboat.interfaces.IArmorStandEntity; import com.kasetoatz.jukeboxboat.interfaces.IArmorStandEntity;
import com.kasetoatz.jukeboxboat.interfaces.IBlockDisplayEntity;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.JukeboxBlock; import net.minecraft.block.JukeboxBlock;
import net.minecraft.block.jukebox.JukeboxSong; import net.minecraft.block.jukebox.JukeboxSong;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.JukeboxPlayableComponent; import net.minecraft.component.type.JukeboxPlayableComponent;
import net.minecraft.component.type.NbtComponent;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.decoration.ArmorStandEntity;
@@ -16,12 +18,14 @@ import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvent;
import net.minecraft.util.math.AffineTransformation; import net.minecraft.util.math.AffineTransformation;
import org.joml.Quaternionf; import org.joml.Quaternionf;
import org.joml.Vector3f; import org.joml.Vector3f;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
public class Util public class Util
{ {
@@ -38,7 +42,7 @@ public class Util
public static void setPlaying(BoatEntity boat, boolean playing) 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 (jukebox != null)
{ {
if (playing) if (playing)
@@ -63,6 +67,8 @@ public class Util
new Quaternionf() new Quaternionf()
)); ));
boat.getWorld().spawnEntity(jukebox); boat.getWorld().spawnEntity(jukebox);
((IBlockDisplayEntity)jukebox).jukeboxBoat$setUUID(jukebox.getUuidAsString());
((IAbstractBoatEntity)boat).jukeboxBoat$setJukebox(jukebox.getUuidAsString());
return jukebox; return jukebox;
} }
@@ -92,13 +98,46 @@ public class Util
public static void replaceJukebox(BoatEntity boat) public static void replaceJukebox(BoatEntity boat)
{ {
IAbstractBoatEntity accessor = (IAbstractBoatEntity)boat; DisplayEntity.BlockDisplayEntity old = findJukebox(boat, ((IAbstractBoatEntity)boat).jukeboxBoat$getJukebox());
DisplayEntity.BlockDisplayEntity old = accessor.jukeboxBoat$getJukebox();
if (old != null) if (old != null)
{ {
old.discard(); old.discard();
} }
DisplayEntity.BlockDisplayEntity jukebox = createJukebox(boat); createJukebox(boat);
accessor.jukeboxBoat$setJukebox(jukebox); }
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);
} }
} }

View File

@@ -6,6 +6,7 @@
"mixins": [ "mixins": [
"AbstractBoatEntityMixin", "AbstractBoatEntityMixin",
"ArmorStandEntityMixin", "ArmorStandEntityMixin",
"BlockDisplayEntityMixin",
"BoatItemMixin", "BoatItemMixin",
"ShapelessRecipeMixin", "ShapelessRecipeMixin",
"VehicleEntityMixin" "VehicleEntityMixin"