Updated to 1.21.8. Changed Data Storage to use Attachments or Capabilities.

This commit is contained in:
Tschipp 2025-09-01 10:18:25 +02:00
parent 162fc1051d
commit ece3ed7ff2
22 changed files with 325 additions and 82 deletions

View File

@ -38,5 +38,6 @@ public class Constants {
public static final ResourceLocation PACKET_ID_START_RIDING = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "start_riding"); public static final ResourceLocation PACKET_ID_START_RIDING = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "start_riding");
public static final ResourceLocation PACKET_ID_SYNC_SCRIPTS = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "sync_scripts"); public static final ResourceLocation PACKET_ID_SYNC_SCRIPTS = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "sync_scripts");
public static final ResourceLocation PACKET_ID_START_RIDING_OTHER = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "start_riding_other"); public static final ResourceLocation PACKET_ID_START_RIDING_OTHER = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "start_riding_other");
public static final ResourceLocation PACKET_ID_SYNC_CARRY_ON_DATA = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "sync_carry_data");
} }

View File

@ -30,6 +30,9 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter; import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.AreaEffectCloud; import net.minecraft.world.entity.AreaEffectCloud;
@ -47,6 +50,7 @@ import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.CarryOnScript; import tschipp.carryon.common.scripting.CarryOnScript;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
public class CarryOnData { public class CarryOnData {
@ -58,6 +62,7 @@ public class CarryOnData {
private int selectedSlot = 0; private int selectedSlot = 0;
private static final ProblemReporter problemReporter = new ProblemReporter.ScopedCollector(Constants.LOG); private static final ProblemReporter problemReporter = new ProblemReporter.ScopedCollector(Constants.LOG);
public static final Codec<CarryOnData> CODEC = CompoundTag.CODEC.flatXmap( public static final Codec<CarryOnData> CODEC = CompoundTag.CODEC.flatXmap(
tag -> { tag -> {
try { try {
@ -75,6 +80,10 @@ public class CarryOnData {
} }
); );
public static final StreamCodec<RegistryFriendlyByteBuf, CarryOnData> STREAM_CODEC = ByteBufCodecs.fromCodecWithRegistries(CODEC);
public static final String SERIALIZATION_KEY = "CarryOnData";
public CarryOnData(CompoundTag data) public CarryOnData(CompoundTag data)
{ {
if(data.contains("type")) if(data.contains("type"))
@ -236,11 +245,14 @@ public class CarryOnData {
public int getTick() public int getTick()
{ {
if(!this.nbt.contains("tick"))
return -1;
return this.nbt.getIntOr("tick", -1); return this.nbt.getIntOr("tick", -1);
} }
public void setTick(int tick) {
this.nbt.putInt("tick", tick);
}
public enum CarryType { public enum CarryType {
BLOCK, BLOCK,
ENTITY, ENTITY,

View File

@ -24,25 +24,22 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import tschipp.carryon.platform.Services;
public class CarryOnDataManager { public class CarryOnDataManager {
public static CarryOnData getCarryData(Player player) public static CarryOnData getCarryData(Player player)
{ {
return ((ICarrying)player).getCarryOnData(); return Services.PLATFORM.getCarryData(player);
} }
public static void setCarryData(Player player, CarryOnData data) public static void setCarryData(Player player, CarryOnData data)
{ {
((ICarrying)player).setCarryOnData(data); data.setSelected(player.getInventory().getSelectedSlot());
} data.setTick(player.tickCount);
Services.PLATFORM.setCarryData(player, data);
public interface ICarrying {
void setCarryOnData(CarryOnData data);
CarryOnData getCarryOnData();
} }
} }

View File

@ -154,7 +154,7 @@ public class PickupHandler {
level.playSound(null, pos, state.getSoundType().getHitSound(), SoundSource.BLOCKS, 1.0f, 0.5f); level.playSound(null, pos, state.getSoundType().getHitSound(), SoundSource.BLOCKS, 1.0f, 0.5f);
player.swing(InteractionHand.MAIN_HAND, true); player.swing(InteractionHand.MAIN_HAND, true);
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative) if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 1000000, CarryOnCommon.potionLevel(carry, player.level()), false, false)); player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
return true; return true;
} }
@ -242,7 +242,7 @@ public class PickupHandler {
player.level().playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC.value(), SoundSource.AMBIENT, 1.0f, 0.5f); player.level().playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC.value(), SoundSource.AMBIENT, 1.0f, 0.5f);
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative) if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 1000000, CarryOnCommon.potionLevel(carry, player.level()), false, false)); player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
return true; return true;
} }
@ -267,7 +267,7 @@ public class PickupHandler {
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
player.swing(InteractionHand.MAIN_HAND, true); player.swing(InteractionHand.MAIN_HAND, true);
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative) if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 1000000, CarryOnCommon.potionLevel(carry, player.level()), false, false)); player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
return true; return true;
} }

View File

@ -23,6 +23,7 @@ package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -34,6 +35,7 @@ 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.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(Inventory.class) @Mixin(Inventory.class)
@ -77,9 +79,10 @@ public class InventoryMixin
} }
@Inject(method = "setSelectedSlot(I)V", at = @At("HEAD"), cancellable = true) @Inject(method = "setSelectedSlot(I)V", at = @At("HEAD"), cancellable = true)
private void onSwapPaint(int $$0, CallbackInfo info) private void onSwapPaint(int slot, CallbackInfo info)
{ {
if(CarryOnDataManager.getCarryData(player).isCarrying()) CarryOnData data = CarryOnDataManager.getCarryData(player);
if(data.isCarrying() && data.getSelected() != slot)
info.cancel(); info.cancel();
} }
} }

View File

@ -44,54 +44,18 @@ import tschipp.carryon.common.carry.CarryOnDataManager;
import java.util.Optional; import java.util.Optional;
@Mixin(Player.class) @Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity implements CarryOnDataManager.ICarrying { public abstract class PlayerMixin extends LivingEntity {
@Unique
private static final EntityDataAccessor<CompoundTag> CARRY_DATA_KEY = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG);
@Override
public void setCarryOnData(CarryOnData data)
{
data.setSelected(this.getInventory().getSelectedSlot());
CompoundTag nbt = data.getNbt();
nbt.putInt("tick", tickCount);
this.getEntityData().set(CARRY_DATA_KEY, nbt);
}
@Override
public CarryOnData getCarryOnData()
{
CompoundTag data = this.getEntityData().get(CARRY_DATA_KEY);
return new CarryOnData(data.copy());
}
@Shadow
public abstract Inventory getInventory();
private PlayerMixin(EntityType<? extends LivingEntity> type, Level level) { private PlayerMixin(EntityType<? extends LivingEntity> type, Level level) {
super(type, level); super(type, level);
} }
//We leave this in here to ensure cross-compatibility if world are upgraded from <1.21.8. Should be removed in the future.
@Inject(method = "defineSynchedData(Lnet/minecraft/network/syncher/SynchedEntityData$Builder;)V", at = @At("RETURN"))
private void onDefineSynchedData(SynchedEntityData.Builder builder, CallbackInfo ci) {
builder.define(CARRY_DATA_KEY, new CompoundTag());
}
@Inject(method = "addAdditionalSaveData(Lnet/minecraft/world/level/storage/ValueOutput;)V", at = @At("RETURN"))
private void onAddAdditionalSaveData(ValueOutput output, CallbackInfo ci)
{
CarryOnData carry = CarryOnDataManager.getCarryData((Player)(Object)this);
output.store("CarryOnData", CarryOnData.CODEC, carry);
}
@Inject(method = "readAdditionalSaveData(Lnet/minecraft/world/level/storage/ValueInput;)V", at = @At("RETURN")) @Inject(method = "readAdditionalSaveData(Lnet/minecraft/world/level/storage/ValueInput;)V", at = @At("RETURN"))
private void onReadAdditionalSaveData(ValueInput input, CallbackInfo ci) private void onReadAdditionalSaveData(ValueInput input, CallbackInfo ci)
{ {
Optional<CarryOnData> res = input.read("CarryOnData", CarryOnData.CODEC); Optional<CarryOnData> res = input.read("CarryOnData", CarryOnData.CODEC);
res.ifPresent(this::setCarryOnData); res.ifPresent(data -> CarryOnDataManager.setCarryData((Player)((Object)this), data));
} }
} }

View File

@ -1,6 +0,0 @@
package tschipp.carryon.networking.clientbound;
import tschipp.carryon.common.carry.CarryOnData;
public record ClientboundSyncCarryDataPacket(CarryOnData data) {
}

View File

@ -29,6 +29,8 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.config.BuiltConfig; import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
@ -74,4 +76,8 @@ public interface IPlatformHelper {
sendPacketToPlayer(id, packet, p); sendPacketToPlayer(id, packet, p);
} }
CarryOnData getCarryData(Player player);
void setCarryData(Player player, CarryOnData data);
} }

View File

@ -21,13 +21,29 @@
package tschipp.carryon; package tschipp.carryon;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.attachment.v1.AttachmentRegistry;
import net.fabricmc.fabric.api.attachment.v1.AttachmentSyncPredicate;
import net.fabricmc.fabric.api.attachment.v1.AttachmentType;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.fabric.ConfigLoaderImpl; import tschipp.carryon.config.fabric.ConfigLoaderImpl;
import tschipp.carryon.events.CommonEvents; import tschipp.carryon.events.CommonEvents;
import java.io.IOException; import java.io.IOException;
public class CarryOnFabricMod implements ModInitializer { public class CarryOnFabricMod implements ModInitializer {
public static final AttachmentType<CarryOnData> CARRY_ON_DATA_ATTACHMENT_TYPE = AttachmentRegistry.create(
ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "carry_on_data"),
builder -> builder
.initializer(() -> new CarryOnData(new CompoundTag()))
.persistent(CarryOnData.CODEC)
.syncWith(CarryOnData.STREAM_CODEC, (t, p) -> p.connection != null)
.copyOnDeath()
);
@Override @Override
public void onInitialize() { public void onInitialize() {

View File

@ -25,6 +25,7 @@ import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking.PlayPayloadHandler; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking.PlayPayloadHandler;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
@ -35,6 +36,8 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import tschipp.carryon.CarryOnFabricClientMod; import tschipp.carryon.CarryOnFabricClientMod;
import tschipp.carryon.CarryOnFabricMod;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.BuiltConfig; import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.fabric.ConfigLoaderImpl; import tschipp.carryon.config.fabric.ConfigLoaderImpl;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
@ -101,4 +104,15 @@ public class FabricPlatformHelper implements IPlatformHelper {
{ {
ServerPlayNetworking.send(player, packet); ServerPlayNetworking.send(player, packet);
} }
@Override
public CarryOnData getCarryData(Player player) {
CarryOnData data = player.getAttachedOrCreate(CarryOnFabricMod.CARRY_ON_DATA_ATTACHMENT_TYPE);
return data.clone();
}
@Override
public void setCarryData(Player player, CarryOnData data) {
player.setAttached(CarryOnFabricMod.CARRY_ON_DATA_ATTACHMENT_TYPE, data);
}
} }

View File

@ -29,6 +29,9 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.network.ChannelBuilder; import net.minecraftforge.network.ChannelBuilder;
import net.minecraftforge.network.SimpleChannel; import net.minecraftforge.network.SimpleChannel;
import tschipp.carryon.config.forge.ConfigLoaderImpl; import tschipp.carryon.config.forge.ConfigLoaderImpl;
import tschipp.carryon.networking.ClientboundSyncCarryDataPacket;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
import tschipp.carryon.platform.Services;
@Mod(Constants.MOD_ID) @Mod(Constants.MOD_ID)
@EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) @EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
@ -54,6 +57,13 @@ public class CarryOnForge {
CarryOnCommon.registerServerPackets(); CarryOnCommon.registerServerPackets();
CarryOnCommon.registerClientPackets(); CarryOnCommon.registerClientPackets();
Services.PLATFORM.registerClientboundPacket(
ClientboundSyncCarryDataPacket.TYPE,
ClientboundSyncCarryDataPacket.class,
ClientboundSyncCarryDataPacket.CODEC,
ClientboundSyncCarryDataPacket::handle
);
} }
} }

View File

@ -0,0 +1,23 @@
package tschipp.carryon.carry;
import net.minecraft.nbt.CompoundTag;
import tschipp.carryon.common.carry.CarryOnData;
public class CarryOnDataCapability implements ICarryOnDataCapability {
private CarryOnData data;
public CarryOnDataCapability() {
this.data = new CarryOnData(new CompoundTag());
}
@Override
public CarryOnData getCarryData() {
return data;
}
@Override
public void setCarryData(CarryOnData data) {
this.data = data;
}
}

View File

@ -0,0 +1,38 @@
package tschipp.carryon.carry;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import tschipp.carryon.common.carry.CarryOnData;
public class CarryOnDataCapabilityProvider implements ICapabilitySerializable<CompoundTag> {
public static final Capability<ICarryOnDataCapability> CARRY_ON_DATA_CAPABILITY = CapabilityManager.get(new CapabilityToken<ICarryOnDataCapability>() {});
private final CarryOnDataCapability impl = new CarryOnDataCapability();
private final LazyOptional<ICarryOnDataCapability> opt = LazyOptional.of(() -> impl);
@Override
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
return cap == CARRY_ON_DATA_CAPABILITY ? opt.cast() : LazyOptional.empty();
}
@Override
public CompoundTag serializeNBT(HolderLookup.Provider registryAccess) {
return (CompoundTag) CarryOnData.CODEC.encodeStart(NbtOps.INSTANCE, impl.getCarryData()).getOrThrow();
}
@Override
public void deserializeNBT(HolderLookup.Provider registryAccess, CompoundTag nbt) {
CarryOnData data = CarryOnData.CODEC.parse(NbtOps.INSTANCE, nbt).getOrThrow();
impl.setCarryData(data);
}
}

View File

@ -0,0 +1,14 @@
package tschipp.carryon.carry;
import net.minecraftforge.common.capabilities.AutoRegisterCapability;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
@AutoRegisterCapability
public interface ICarryOnDataCapability {
CarryOnData getCarryData();
void setCarryData(CarryOnData data);
}

View File

@ -21,6 +21,7 @@
package tschipp.carryon.events; package tschipp.carryon.events;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@ -32,12 +33,10 @@ import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.BlockSnapshot; import net.minecraftforge.common.util.BlockSnapshot;
import net.minecraftforge.common.util.Result; import net.minecraftforge.common.util.Result;
import net.minecraftforge.event.AddReloadListenerEvent; import net.minecraftforge.event.*;
import net.minecraftforge.event.OnDatapackSyncEvent;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.event.TagsUpdatedEvent;
import net.minecraftforge.event.TickEvent.Phase; import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.event.TickEvent.ServerTickEvent; import net.minecraftforge.event.TickEvent.ServerTickEvent;
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.MobSpawnEvent.FinalizeSpawn; import net.minecraftforge.event.entity.living.MobSpawnEvent.FinalizeSpawn;
import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.entity.player.AttackEntityEvent;
@ -54,6 +53,7 @@ import net.minecraftforge.fml.common.Mod;
import oshi.jna.platform.mac.SystemB; import oshi.jna.platform.mac.SystemB;
import tschipp.carryon.CarryOnCommon; import tschipp.carryon.CarryOnCommon;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.carry.CarryOnDataCapabilityProvider;
import tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType; import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
@ -61,6 +61,8 @@ import tschipp.carryon.common.carry.PickupHandler;
import tschipp.carryon.common.carry.PlacementHandler; import tschipp.carryon.common.carry.PlacementHandler;
import tschipp.carryon.common.scripting.ScriptReloadListener; import tschipp.carryon.common.scripting.ScriptReloadListener;
import tschipp.carryon.config.ConfigLoader; import tschipp.carryon.config.ConfigLoader;
import tschipp.carryon.networking.ClientboundSyncCarryDataPacket;
import tschipp.carryon.platform.Services;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, modid = Constants.MOD_ID) @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, modid = Constants.MOD_ID)
public class CommonEvents public class CommonEvents
@ -178,8 +180,16 @@ public class CommonEvents
@SubscribeEvent @SubscribeEvent
public static void onClone(Clone event) public static void onClone(Clone event)
{ {
if (!event.getOriginal().level().isClientSide) if (!event.getOriginal().level().isClientSide) {
PlacementHandler.placeCarriedOnDeath((ServerPlayer) event.getOriginal(), (ServerPlayer) event.getEntity(), event.isWasDeath()); Player newPlayer = event.getEntity();
Player oldPlayer = event.getOriginal();
oldPlayer.reviveCaps();
PlacementHandler.placeCarriedOnDeath((ServerPlayer) oldPlayer, (ServerPlayer) newPlayer, event.isWasDeath());
oldPlayer.invalidateCaps();
}
} }
@SubscribeEvent @SubscribeEvent
@ -214,4 +224,25 @@ public class CommonEvents
CarryOnCommon.onRiderDisconnected(player); CarryOnCommon.onRiderDisconnected(player);
} }
@SubscribeEvent
public static void onAttachCapabilities(AttachCapabilitiesEvent.Entities event) {
if (event.getObject() instanceof Player player) {
event.addCapability(ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "carry_on_data"), new CarryOnDataCapabilityProvider());
}
}
@SubscribeEvent
public static void onStartTracking(PlayerEvent.StartTracking event) {
if(event.getEntity() instanceof ServerPlayer sp && event.getTarget() instanceof ServerPlayer target) {
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_SYNC_CARRY_ON_DATA, new ClientboundSyncCarryDataPacket(sp.getId(), CarryOnDataManager.getCarryData(sp)), target);
}
}
@SubscribeEvent
public static void onJoinWorld(EntityJoinLevelEvent event) {
if (event.getEntity() instanceof ServerPlayer sp) {
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_SYNC_CARRY_ON_DATA, new ClientboundSyncCarryDataPacket(sp.getId(), CarryOnDataManager.getCarryData(sp)), sp);
}
}
} }

View File

@ -0,0 +1,36 @@
package tschipp.carryon.networking;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
public record ClientboundSyncCarryDataPacket(int iden, CarryOnData data) implements PacketBase {
public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundSyncCarryDataPacket> CODEC = StreamCodec.composite(
ByteBufCodecs.INT, ClientboundSyncCarryDataPacket::iden,
CarryOnData.STREAM_CODEC, ClientboundSyncCarryDataPacket::data,
ClientboundSyncCarryDataPacket::new
);
public static final CustomPacketPayload.Type<ClientboundSyncCarryDataPacket> TYPE = new Type<>(Constants.PACKET_ID_SYNC_CARRY_ON_DATA);
@Override
public void handle(Player player) {
Entity e = player.level().getEntity(this.iden);
if(e instanceof Player p) {
CarryOnDataManager.setCarryData(p, data);
}
}
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}

View File

@ -25,6 +25,7 @@ import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.network.CustomPayloadEvent; import net.minecraftforge.event.network.CustomPayloadEvent;
@ -34,8 +35,14 @@ import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.PacketDistributor;
import tschipp.carryon.CarryOnCommonClient; import tschipp.carryon.CarryOnCommonClient;
import tschipp.carryon.CarryOnForge; import tschipp.carryon.CarryOnForge;
import tschipp.carryon.Constants;
import tschipp.carryon.carry.CarryOnDataCapability;
import tschipp.carryon.carry.CarryOnDataCapabilityProvider;
import tschipp.carryon.carry.ICarryOnDataCapability;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.BuiltConfig; import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.forge.ConfigLoaderImpl; import tschipp.carryon.config.forge.ConfigLoaderImpl;
import tschipp.carryon.networking.ClientboundSyncCarryDataPacket;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
import tschipp.carryon.platform.services.IPlatformHelper; import tschipp.carryon.platform.services.IPlatformHelper;
@ -111,4 +118,19 @@ public class ForgePlatformHelper implements IPlatformHelper {
{ {
CarryOnForge.network.send(packet, PacketDistributor.PLAYER.with(player)); CarryOnForge.network.send(packet, PacketDistributor.PLAYER.with(player));
} }
@Override
public CarryOnData getCarryData(Player player) {
var cap = player.getCapability(CarryOnDataCapabilityProvider.CARRY_ON_DATA_CAPABILITY).orElse(new CarryOnDataCapability());
return cap.getCarryData();
}
@Override
public void setCarryData(Player player, CarryOnData data) {
var cap = player.getCapability(CarryOnDataCapabilityProvider.CARRY_ON_DATA_CAPABILITY).orElse(new CarryOnDataCapability());
cap.setCarryData(data);
if(!player.level().isClientSide) {
sendPacketToAllPlayers(Constants.PACKET_ID_SYNC_SCRIPTS, new ClientboundSyncCarryDataPacket(player.getId(), data), (ServerLevel) player.level());
}
}
} }

View File

@ -20,20 +20,38 @@
package tschipp.carryon; package tschipp.carryon;
import net.minecraft.nbt.CompoundTag;
import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.IEventBus;
import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.ModContainer; import net.neoforged.fml.ModContainer;
import net.neoforged.fml.common.Mod; import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.attachment.AttachmentType;
import net.neoforged.neoforge.client.gui.ConfigurationScreen; import net.neoforged.neoforge.client.gui.ConfigurationScreen;
import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.neoforged.neoforge.network.registration.PayloadRegistrar;
import net.neoforged.neoforge.registries.DeferredRegister;
import net.neoforged.neoforge.registries.NeoForgeRegistries;
import tschipp.carryon.carry.CarryOnDataSyncHandler;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.neoforge.ConfigLoaderImpl; import tschipp.carryon.config.neoforge.ConfigLoaderImpl;
import java.util.function.Supplier;
@Mod(Constants.MOD_ID) @Mod(Constants.MOD_ID)
public class CarryOnNeoForge { public class CarryOnNeoForge {
private static final DeferredRegister<AttachmentType<?>> ATTACHMENT_TYPES = DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, Constants.MOD_ID);
public static final Supplier<AttachmentType<CarryOnData>> CARRY_ON_DATA_ATTACHMENT = ATTACHMENT_TYPES.register(
"carry_on_data",
() -> AttachmentType.builder(() -> new CarryOnData(new CompoundTag()))
.sync(new CarryOnDataSyncHandler())
.serialize(CarryOnData.CODEC.fieldOf(CarryOnData.SERIALIZATION_KEY))
.build()
);
public CarryOnNeoForge(ModContainer container) { public CarryOnNeoForge(ModContainer container) {
// This method is invoked by the Forge mod loader when it is ready // This method is invoked by the Forge mod loader when it is ready
@ -45,6 +63,8 @@ public class CarryOnNeoForge {
container.getEventBus().addListener(this::registerPackets); container.getEventBus().addListener(this::registerPackets);
ConfigLoaderImpl.initialize(container); ConfigLoaderImpl.initialize(container);
ATTACHMENT_TYPES.register(container.getEventBus());
} }
private void setup(final FMLCommonSetupEvent event) private void setup(final FMLCommonSetupEvent event)
@ -57,6 +77,8 @@ public class CarryOnNeoForge {
CarryOnCommon.registerServerPackets(registrar); CarryOnCommon.registerServerPackets(registrar);
CarryOnCommon.registerClientPackets(registrar); CarryOnCommon.registerClientPackets(registrar);
} }
} }

View File

@ -0,0 +1,27 @@
package tschipp.carryon.carry;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.attachment.AttachmentSyncHandler;
import net.neoforged.neoforge.attachment.IAttachmentHolder;
import org.jetbrains.annotations.Nullable;
import tschipp.carryon.common.carry.CarryOnData;
public class CarryOnDataSyncHandler implements AttachmentSyncHandler<CarryOnData> {
@Override
public void write(RegistryFriendlyByteBuf registryFriendlyByteBuf, CarryOnData carryOnData, boolean b) {
CarryOnData.STREAM_CODEC.encode(registryFriendlyByteBuf, carryOnData);
}
@Override
public @Nullable CarryOnData read(IAttachmentHolder iAttachmentHolder, RegistryFriendlyByteBuf registryFriendlyByteBuf, @Nullable CarryOnData carryOnData) {
return CarryOnData.STREAM_CODEC.decode(registryFriendlyByteBuf);
}
@Override
public boolean sendToPlayer(IAttachmentHolder holder, ServerPlayer to) {
if (to.connection == null)
return false;
return AttachmentSyncHandler.super.sendToPlayer(holder, to);
}
}

View File

@ -20,6 +20,7 @@
package tschipp.carryon.platform; package tschipp.carryon.platform;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
@ -35,7 +36,9 @@ import net.neoforged.neoforge.network.PacketDistributor;
import net.neoforged.neoforge.network.handling.IPayloadHandler; import net.neoforged.neoforge.network.handling.IPayloadHandler;
import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.neoforged.neoforge.network.registration.PayloadRegistrar;
import tschipp.carryon.CarryOnCommonClient; import tschipp.carryon.CarryOnCommonClient;
import tschipp.carryon.CarryOnNeoForge;
import tschipp.carryon.CarryOnNeoForgeClient; import tschipp.carryon.CarryOnNeoForgeClient;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.BuiltConfig; import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.neoforge.ConfigLoaderImpl; import tschipp.carryon.config.neoforge.ConfigLoaderImpl;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
@ -106,4 +109,14 @@ public class NeoForgePlatformHelper implements IPlatformHelper {
public void sendPacketToPlayer(ResourceLocation id, PacketBase packet, ServerPlayer player) { public void sendPacketToPlayer(ResourceLocation id, PacketBase packet, ServerPlayer player) {
PacketDistributor.sendToPlayer(player, packet); PacketDistributor.sendToPlayer(player, packet);
} }
@Override
public CarryOnData getCarryData(Player player) {
return player.getData(CarryOnNeoForge.CARRY_ON_DATA_ATTACHMENT);
}
@Override
public void setCarryData(Player player, CarryOnData data) {
player.setData(CarryOnNeoForge.CARRY_ON_DATA_ATTACHMENT, data);
}
} }

View File

@ -4,7 +4,7 @@ plugins {
} }
base { base {
archivesName = "${mod_id}-${project.name}-${minecraft_version}" archivesName = "${mod_id}-${project.name.toLowerCase()}-${minecraft_version}"
} }
java { java {

View File

@ -1,36 +1,36 @@
# Project # Project
version=2.6.0 version=2.7.0
group=tschipp.carryon group=tschipp.carryon
# Common # Common
minecraft_version=1.21.7 minecraft_version=1.21.8
mod_name=Carry On mod_name=Carry On
mod_author=Tschipp, PurpliciousCow mod_author=Tschipp, PurpliciousCow
mod_id=carryon mod_id=carryon
license=GNU LGPLv3 license=GNU LGPLv3
credits= credits=
description=Carry On is a simple mod that improves game interaction by allowing players to pick up, carry, and place single block Tile Entities using only their empty hands. description=Carry On is a simple mod that improves game interaction by allowing players to pick up, carry, and place single block Tile Entities using only their empty hands.
minecraft_version_range=[1.21.7, 1.22) minecraft_version_range=[1.21.8, 1.22)
neo_form_version=1.21.7-20250711.194848 neo_form_version=1.21.8-20250717.133445
java_version=21 java_version=21
parchment_version=2025.07.18 parchment_version=2025.07.20
mod_dev_version=2.0.107 mod_dev_version=2.0.107
# Forge # Forge
forge_version=57.0.3 forge_version=58.0.10
forge_loader_version_range=[56,) forge_loader_version_range=[57,)
parchment_mappings=2025.07.18-1.21.7 parchment_mappings=2025.07.20-1.21.8
//forge_ats_enabled=true //forge_ats_enabled=true
# Fabric # Fabric
fabric_version=0.129.0+1.21.7 fabric_version=0.132.0+1.21.8
fabric_loader_version=0.17.2 fabric_loader_version=0.17.2
parchment_mappings_fabric=1.21.7:2025.07.18 parchment_mappings_fabric=1.21.8:2025.07.20
# Neoforge # Neoforge
neoforge_version=21.7.25-beta neoforge_version=21.8.36
neoforge_loader_version_range=[4,) neoforge_loader_version_range=[4,)
neogradle.subsystems.parchment.minecraftVersion=1.21.7 neogradle.subsystems.parchment.minecraftVersion=1.21.8
neogradle.subsystems.parchment.mappingsVersion=2025.07.18 neogradle.subsystems.parchment.mappingsVersion=2025.07.20
# Gradle # Gradle