diff --git a/Common/src/main/java/tschipp/carryon/CommonClass.java b/Common/src/main/java/tschipp/carryon/CommonClass.java deleted file mode 100644 index ec070b7..0000000 --- a/Common/src/main/java/tschipp/carryon/CommonClass.java +++ /dev/null @@ -1,40 +0,0 @@ -package tschipp.carryon; - -import tschipp.carryon.platform.Services; -import net.minecraft.core.Registry; -import net.minecraft.network.chat.Component; -import net.minecraft.world.food.FoodProperties; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.TooltipFlag; - -import java.util.List; - -public class CommonClass { - - // This method serves as an initialization hook for the mod. The vanilla - // game has no mechanism to load tooltip listeners so this must be - // invoked from a mod loader specific project like Forge or Fabric. - public static void init() { - - Constants.LOG.info("Hello from Common init on {}! we are currently in a {} environment!", Services.PLATFORM.getPlatformName(), Services.PLATFORM.isDevelopmentEnvironment() ? "development" : "production"); - Constants.LOG.info("Diamond Item >> {}", Registry.ITEM.getKey(Items.DIAMOND)); - } - - // This method serves as a hook to modify item tooltips. The vanilla game - // has no mechanism to load tooltip listeners so this must be registered - // by a mod loader like Forge or Fabric. - public static void onItemTooltip(ItemStack stack, TooltipFlag context, List tooltip) { - - if (!stack.isEmpty()) { - - final FoodProperties food = stack.getItem().getFoodProperties(); - - if (food != null) { - - tooltip.add(Component.literal("Nutrition: " + food.getNutrition())); - tooltip.add(Component.literal("Saturation: " + food.getSaturationModifier())); - } - } - } -} \ No newline at end of file diff --git a/Common/src/main/java/tschipp/carryon/client/render/CarriedObjectRender.java b/Common/src/main/java/tschipp/carryon/client/render/CarriedObjectRender.java new file mode 100644 index 0000000..d0f9163 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/client/render/CarriedObjectRender.java @@ -0,0 +1,83 @@ +package tschipp.carryon.client.render; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import tschipp.carryon.common.carry.CarryOnData; +import tschipp.carryon.common.carry.CarryOnData.CarryType; +import tschipp.carryon.common.carry.CarryOnDataManager; + +public class CarriedObjectRender +{ + + public static boolean drawFirstPerson(Player player, MultiBufferSource buffer, PoseStack matrix, int light) + { + CarryOnData carry = CarryOnDataManager.getCarryData(player); + if(carry.isCarrying(CarryType.BLOCK)) + drawFirstPersonBlock(player, buffer, matrix, light, carry.getBlock()); + else + ; + + return carry.isCarrying(); + } + + private static void drawFirstPersonBlock(Player player, MultiBufferSource buffer, PoseStack matrix, int light, BlockState state) + { + matrix.pushPose(); + matrix.scale(2.5f, 2.5f, 2.5f); + matrix.translate(0, -0.5, -1); + RenderSystem.enableBlend(); + RenderSystem.disableCull(); + int perspective = CarryRenderHelper.getPerspective(); + + //TODO: FacePlayer config + if (isChest(state.getBlock())) { + matrix.mulPose(Vector3f.YP.rotationDegrees(180)); + matrix.mulPose(Vector3f.XN.rotationDegrees(8)); + } else { + matrix.mulPose(Vector3f.XP.rotationDegrees(8)); + } + +// +// CarryOnOverride carryOverride = ScriptChecker.getOverride(player); +// if (carryOverride != null) { +// CarryRenderHelper.performOverrideTransformation(matrix, carryOverride); +// +// if (!carryOverride.getRenderNameBlock().isEmpty()) { +// Block b = StringParser.getBlock(carryOverride.getRenderNameBlock()); +// if (b != null) { +// ItemStack s = new ItemStack(b, 1); +// s.setTag(carryOverride.getRenderNBT()); +// model = Minecraft.getInstance().getItemRenderer().getModel(s, level, player, 0); +// } +// } +// } + + RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS); + + ItemStack stack = new ItemStack(state.getBlock().asItem()); + //TODO: Model overrides + BakedModel model = Minecraft.getInstance().getItemRenderer().getModel(stack, player.level, player, 0); + CarryRenderHelper.renderItem(state, null, stack, matrix, buffer, light, model); + + RenderSystem.enableCull(); + RenderSystem.disableBlend(); + matrix.popPose(); + } + + + public static boolean isChest(Block block) + { + return block == Blocks.CHEST || block == Blocks.ENDER_CHEST || block == Blocks.TRAPPED_CHEST; + } +} + diff --git a/Common/src/main/java/tschipp/carryon/client/render/CarryRenderHelper.java b/Common/src/main/java/tschipp/carryon/client/render/CarryRenderHelper.java new file mode 100644 index 0000000..69c37d5 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/client/render/CarryRenderHelper.java @@ -0,0 +1,87 @@ +package tschipp.carryon.client.render; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class CarryRenderHelper +{ + public static Vec3 getExactPos(Entity entity, float partialticks) + { + return new Vec3(entity.xOld + (entity.getX() - entity.xOld) * partialticks, entity.yOld + (entity.getY() - entity.yOld) * partialticks, entity.zOld + (entity.getZ() - entity.zOld) * partialticks); + } + + public static float getExactBodyRotationDegrees(LivingEntity entity, float partialticks) + { + if (entity.getVehicle() != null && entity.getVehicle() instanceof LivingEntity) + return -(entity.yHeadRotO + (entity.yHeadRot - entity.yHeadRotO) * partialticks); + else + return -(entity.yBodyRotO + (entity.yBodyRot - entity.yBodyRotO) * partialticks); + } + + public static Quaternion getExactBodyRotation(LivingEntity entity, float partialticks) + { + return Vector3f.YP.rotationDegrees(getExactBodyRotationDegrees(entity, partialticks)); + } + + //TODO: Scripting +// public static void performOverrideTransformation(PoseStack matrix, CarryOnOverride override) +// { +// int perspective = getPerspective(); +// +// float[] translation = ScriptParseHelper.getXYZArray(override.getRenderTranslation()); +// float[] rotation = ScriptParseHelper.getXYZArray(override.getRenderRotation()); +// float[] scaled = ScriptParseHelper.getScaled(override.getRenderScaled()); +// +// Quaternion rot = Vector3f.XP.rotationDegrees(rotation[0]); +// rot.mul(Vector3f.YP.rotationDegrees(rotation[1])); +// rot.mul(Vector3f.ZP.rotationDegrees(rotation[2])); +// matrix.mulPose(rot); +// +// matrix.translate(translation[0], translation[1], perspective == 1 && override.isBlock() ? -translation[2] : translation[2]); +// +// matrix.scale(scaled[0], scaled[1], scaled[2]); +// } + + public static void renderItem(BlockState state, CompoundTag tag, ItemStack stack, PoseStack matrix, MultiBufferSource buffer, int light, BakedModel model) + { + ItemRenderer renderer = Minecraft.getInstance().getItemRenderer(); +// if (ModelOverridesHandler.hasCustomOverrideModel(state, tag)) +// { +// Object override = ModelOverridesHandler.getOverrideObject(state, tag); + +// if (override instanceof ItemStack) +// { +// renderer.render((ItemStack) override, TransformType.NONE, false, matrix, buffer, light, OverlayTexture.NO_OVERLAY, model); +// return; +//// } +// } + + renderer.render(stack, TransformType.NONE, false, matrix, buffer, light, OverlayTexture.NO_OVERLAY, model); + } + + @SuppressWarnings("resource") + public static int getPerspective() + { + boolean isThirdPerson = !Minecraft.getInstance().options.getCameraType().isFirstPerson(); // isThirdPerson + boolean isThirdPersonReverse = Minecraft.getInstance().options.getCameraType().isMirrored(); + + if (!isThirdPerson && !isThirdPersonReverse) + return 0; + if (isThirdPerson && !isThirdPersonReverse) + return 1; + return 2; + } +} diff --git a/Common/src/main/java/tschipp/carryon/common/carry/CarryOnData.java b/Common/src/main/java/tschipp/carryon/common/carry/CarryOnData.java index 5d44e97..f4bb35b 100644 --- a/Common/src/main/java/tschipp/carryon/common/carry/CarryOnData.java +++ b/Common/src/main/java/tschipp/carryon/common/carry/CarryOnData.java @@ -8,6 +8,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; import javax.annotation.Nullable; @@ -35,6 +36,10 @@ public class CarryOnData { public void setBlock(BlockState state, @Nullable BlockEntity tile) { this.type = CarryType.BLOCK; + + if(state.hasProperty(BlockStateProperties.WATERLOGGED)) + state = state.setValue(BlockStateProperties.WATERLOGGED, false); + CompoundTag stateData = NbtUtils.writeBlockState(state); nbt.put("block", stateData); @@ -81,6 +86,29 @@ public class CarryOnData { return EntityType.create(nbt.getCompound("entity"), level).orElseThrow(); } + public boolean isCarrying() + { + return this.type != CarryType.INVALID; + } + + public boolean isCarrying(CarryType type) + { + return this.type == type; + } + + public void clear() + { + this.type = CarryType.INVALID; + this.nbt = new CompoundTag(); + } + + public int getTick() + { + if(!this.nbt.contains("tick")) + return -1; + return this.nbt.getInt("tick"); + } + public enum CarryType { BLOCK, ENTITY, diff --git a/Common/src/main/java/tschipp/carryon/common/carry/CarryOnDataManager.java b/Common/src/main/java/tschipp/carryon/common/carry/CarryOnDataManager.java index f6f1433..1e50f99 100644 --- a/Common/src/main/java/tschipp/carryon/common/carry/CarryOnDataManager.java +++ b/Common/src/main/java/tschipp/carryon/common/carry/CarryOnDataManager.java @@ -5,21 +5,27 @@ import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.world.entity.player.Player; +import org.apache.commons.lang3.ObjectUtils; public class CarryOnDataManager { public static final EntityDataAccessor CARRY_DATA_KEY = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG); - public CarryOnData getCarryData(Player player) + public static CarryOnData getCarryData(Player player) { CompoundTag data = player.getEntityData().get(CARRY_DATA_KEY); - return new CarryOnData(data); + return new CarryOnData(data.copy()); } - public void setCarryData(Player player, CarryOnData data) + public static void setCarryData(Player player, CarryOnData data) { - player.getEntityData().set(CARRY_DATA_KEY, data.getNbt()); + CompoundTag nbt = data.getNbt(); + nbt.putInt("tick", player.tickCount); + System.out.println(player.getEntityData().isDirty()); + System.out.println("Old: " + player.getEntityData().get(CARRY_DATA_KEY) + ", New: " + nbt + ", NotEqual: " + ObjectUtils.notEqual(player.getEntityData().get(CARRY_DATA_KEY), nbt)); + player.getEntityData().set(CARRY_DATA_KEY, nbt); + System.out.println(player.getEntityData().isDirty()); } } diff --git a/Common/src/main/java/tschipp/carryon/common/carry/PickupHandler.java b/Common/src/main/java/tschipp/carryon/common/carry/PickupHandler.java new file mode 100644 index 0000000..a08c452 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/common/carry/PickupHandler.java @@ -0,0 +1,117 @@ +package tschipp.carryon.common.carry; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Entity.RemovalReason; +import net.minecraft.world.entity.TamableAnimal; +import net.minecraft.world.entity.animal.Animal; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +import java.util.UUID; + +public class PickupHandler { + + //TODO: CONFIG + private static final double range = 2.0; + + + public static boolean canCarryGeneral(ServerPlayer player, Vec3 pos) + { + //TODO: Check carry key + if(!player.isShiftKeyDown()) + return false; + + if(!player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty()) + return false; + + if(player.position().distanceTo(pos) >= range) + return false; + + CarryOnData carry = CarryOnDataManager.getCarryData(player); + if(carry.isCarrying()) + return false; + + if(player.tickCount == carry.getTick()) + return false; + + if (player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR || player.gameMode.getGameModeForPlayer() == GameType.ADVENTURE) + return false; + + + return true; + } + + + public static boolean tryPickUpBlock(ServerPlayer player, BlockPos pos, Level level) + { + if(!canCarryGeneral(player, Vec3.atCenterOf(pos))) + return false; + + //TODO: Whitelist/Blacklist checks + + + CarryOnData carry = CarryOnDataManager.getCarryData(player); + BlockEntity blockEntity = level.getBlockEntity(pos); + BlockState state = level.getBlockState(pos); + carry.setBlock(state, blockEntity); + + level.removeBlockEntity(pos); + level.removeBlock(pos, false); + + CarryOnDataManager.setCarryData(player, carry); + level.playSound(null, pos, state.getSoundType().getHitSound(), SoundSource.BLOCKS, 1.0f, 0.5f); + player.swing(InteractionHand.MAIN_HAND, true); + return true; + } + + + + public static boolean tryPickupEntity(ServerPlayer player, Entity entity) + { + if(!canCarryGeneral(player, entity.position())) + return false; + + if (entity.invulnerableTime != 0) + return false; + + if (entity instanceof Player) + return false; + + if (entity instanceof TamableAnimal tame) + { + UUID owner = tame.getOwnerUUID(); + UUID playerID = player.getGameProfile().getId(); + if (owner != null && !owner.equals(playerID)) + return false; + } + + if (entity instanceof Animal) + ((Animal) entity).dropLeash(true, true); + + //TODO: White and blacklist + + //TODO: Protections + + CarryOnData carry = CarryOnDataManager.getCarryData(player); + + + entity.ejectPassengers(); + carry.setEntity(entity); + entity.remove(RemovalReason.DISCARDED); + + player.level.playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC, SoundSource.AMBIENT, 1.0f, 0.5f); + CarryOnDataManager.setCarryData(player, carry); + player.swing(InteractionHand.MAIN_HAND, true); + return true; + } + +} diff --git a/Common/src/main/java/tschipp/carryon/common/carry/PlacementHandler.java b/Common/src/main/java/tschipp/carryon/common/carry/PlacementHandler.java new file mode 100644 index 0000000..34dbe60 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/common/carry/PlacementHandler.java @@ -0,0 +1,144 @@ +package tschipp.carryon.common.carry; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import tschipp.carryon.common.carry.CarryOnData.CarryType; + +import javax.annotation.Nullable; +import java.util.function.BiFunction; + +public class PlacementHandler +{ + + public static boolean tryPlaceBlock(ServerPlayer player, BlockPos pos, Direction facing, @Nullable BiFunction placementCallback) + { + CarryOnData carry = CarryOnDataManager.getCarryData(player); + if (!carry.isCarrying(CarryOnData.CarryType.BLOCK)) + return false; + + if (player.tickCount == carry.getTick()) + return false; + + Level level = player.getLevel(); + BlockState state = carry.getBlock(); + + BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos)); + + if (!level.getBlockState(pos).canBeReplaced(context)) + pos = pos.relative(facing); + + context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos)); + + BlockEntity blockEntity = carry.getBlockEntity(pos); + + boolean canPlace = state.canSurvive(level, pos) && level.mayInteract(player, pos) && level.getBlockState(pos).canBeReplaced(context) && level.isUnobstructed(state, pos, CollisionContext.of(player)); + if (!canPlace) + return false; + + state = getPlacementState(state, player, context, pos); + boolean doPlace = placementCallback == null ? true : placementCallback.apply(pos, state); + + if (!doPlace) + return false; + + level.setBlock(pos, state, 3); + if (blockEntity != null) + level.setBlockEntity(blockEntity); + carry.clear(); + CarryOnDataManager.setCarryData(player, carry); + player.playSound(state.getSoundType().getPlaceSound(), 1.0f, 0.5f); + level.playSound(null, pos, state.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0f, 0.5f); + player.swing(InteractionHand.MAIN_HAND, true); + return true; + } + + private static BlockState getPlacementState(BlockState state, ServerPlayer player, BlockPlaceContext context, BlockPos pos) + { + BlockState placementState = state.getBlock().getStateForPlacement(context); + System.out.println(placementState); + + for (var prop : placementState.getProperties()) { + if (prop instanceof DirectionProperty) { + state = updateProperty(state, placementState, prop); + } + if (prop instanceof EnumProperty) { + if (state.getValue(prop) instanceof Axis) + state = updateProperty(state, placementState, prop); + } + //TODO: Add config for state variant names, which should be taken from the placementState + if (prop.getName().equals("type")) { + state = updateProperty(state, placementState, prop); + } + } + + System.out.println(state); + + state = Block.updateFromNeighbourShapes(state, player.level, pos); + + if (placementState.hasProperty(BlockStateProperties.WATERLOGGED)) + state = state.setValue(BlockStateProperties.WATERLOGGED, placementState.getValue(BlockStateProperties.WATERLOGGED)); + + return state; + } + + private static , V extends T> BlockState updateProperty(BlockState state, BlockState otherState, Property prop) + { + var val = otherState.getValue(prop); + return state.setValue(prop, val); + } + + public static boolean tryPlaceEntity(ServerPlayer player, BlockPos pos, Direction facing, @Nullable BiFunction placementCallback) + { + CarryOnData carry = CarryOnDataManager.getCarryData(player); + if (!carry.isCarrying(CarryType.ENTITY)) + return false; + + if (player.tickCount == carry.getTick()) + return false; + + Level level = player.getLevel(); + + BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos)); + if (!level.getBlockState(pos).canBeReplaced(context)) + pos = pos.relative(facing); + + Vec3 placementPos = Vec3.atBottomCenterOf(pos); + + + Entity entity = carry.getEntity(level); + entity.setPos(placementPos); + + boolean doPlace = placementCallback == null ? true : placementCallback.apply(placementPos, entity); + if (!doPlace) + return false; + + level.addFreshEntity(entity); + if(entity instanceof Mob mob) + mob.playAmbientSound(); + + player.swing(InteractionHand.MAIN_HAND, true); + carry.clear(); + CarryOnDataManager.setCarryData(player, carry); + return true; + } + +} diff --git a/Common/src/main/java/tschipp/carryon/mixin/InventoryMixin.java b/Common/src/main/java/tschipp/carryon/mixin/InventoryMixin.java new file mode 100644 index 0000000..22159ea --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/mixin/InventoryMixin.java @@ -0,0 +1,49 @@ +package tschipp.carryon.mixin; + +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +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 tschipp.carryon.common.carry.CarryOnDataManager; + +@Mixin(Inventory.class) +public class InventoryMixin +{ + @Shadow + public Player player; + +// @Redirect(method = "selected:I", at = @At()) +// private void setSelected(Inventory inv, int value) +// { +// +// } + + @Inject(method = "setPickedItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true) + private void onPickBlock(CallbackInfo info) + { + System.out.println("onPickBlock"); + if(CarryOnDataManager.getCarryData(player).isCarrying()) + info.cancel(); + } + + @Inject(method = "pickSlot(I)V", at = @At("HEAD"), cancellable = true) + private void onPickSlot(int slot, CallbackInfo info) + { + System.out.println("onPickSlot"); + if(CarryOnDataManager.getCarryData(player).isCarrying()) + info.cancel(); + } + + @Inject(method = "swapPaint(D)V", at = @At("HEAD"), cancellable = true) + private void onSwapPaint(double direction, CallbackInfo info) + { + System.out.println(player); + System.out.println(CarryOnDataManager.getCarryData(player).getNbt()); + System.out.println("onSwapPaint"); + if(CarryOnDataManager.getCarryData(player).isCarrying()) + info.cancel(); + } +} diff --git a/Common/src/main/java/tschipp/carryon/mixin/MinecraftMixin.java b/Common/src/main/java/tschipp/carryon/mixin/MinecraftMixin.java new file mode 100644 index 0000000..3fca3fa --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/mixin/MinecraftMixin.java @@ -0,0 +1,19 @@ +package tschipp.carryon.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.player.Inventory; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import tschipp.carryon.common.carry.CarryOnDataManager; + +@Mixin(Minecraft.class) +public class MinecraftMixin +{ + @Redirect(method = "handleKeybinds()V", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/player/Inventory;selected:I", ordinal = 0, opcode = 181)) //Opcode for PUTFIELD + private void onSlotSelected(Inventory inv,int slot) + { + if(!CarryOnDataManager.getCarryData(inv.player).isCarrying()) + inv.selected = slot; + } +} diff --git a/Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java b/Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java index 83e5f69..f11a43c 100644 --- a/Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java +++ b/Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java @@ -2,26 +2,44 @@ package tschipp.carryon.mixin; import net.minecraft.nbt.CompoundTag; -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 tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.CarryOnDataManager; @Mixin(Player.class) -public abstract class PlayerMixin extends Entity { +public abstract class PlayerMixin extends LivingEntity { - public PlayerMixin(EntityType type, Level level) { + private PlayerMixin(EntityType type, Level level) { super(type, level); } - @Inject(at = @At("RETURN"), method = "defineSynchedData()V") + @Inject(method = "defineSynchedData()V", at = @At("RETURN")) private void onDefineSynchedData(CallbackInfo info) { this.entityData.define(CarryOnDataManager.CARRY_DATA_KEY, new CompoundTag()); } + @Inject(method = "addAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("RETURN")) + private void onAddAdditionalSaveData(CompoundTag tag, CallbackInfo info) + { + CarryOnData carry = CarryOnDataManager.getCarryData((Player)(Object)this); + tag.put("CarryOnData", carry.getNbt()); + } + + @Inject(method = "readAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("RETURN")) + private void onReadAdditionalSaveData(CompoundTag tag, CallbackInfo info) + { + if(tag.contains("CarryOnData")) + { + CarryOnData data = new CarryOnData(tag.getCompound("CarryOnData")); + CarryOnDataManager.setCarryData((Player)(Object)this, data); + } + } + } diff --git a/Common/src/main/resources/carryon.mixins.json b/Common/src/main/resources/carryon.mixins.json index 93ca0e7..4879127 100644 --- a/Common/src/main/resources/carryon.mixins.json +++ b/Common/src/main/resources/carryon.mixins.json @@ -4,8 +4,11 @@ "package": "tschipp.carryon.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ + "InventoryMixin", + "PlayerMixin" ], "client": [ + "MinecraftMixin" ], "server": [ ], diff --git a/Fabric/src/main/java/tschipp/carryon/ExampleMod.java b/Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java similarity index 55% rename from Fabric/src/main/java/tschipp/carryon/ExampleMod.java rename to Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java index 44cfecb..955c14e 100644 --- a/Fabric/src/main/java/tschipp/carryon/ExampleMod.java +++ b/Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java @@ -1,9 +1,8 @@ package tschipp.carryon; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; -public class ExampleMod implements ModInitializer { +public class CarryOnFabricMod implements ModInitializer { @Override public void onInitialize() { @@ -14,10 +13,6 @@ public class ExampleMod implements ModInitializer { // Use Fabric to bootstrap the Common mod. Constants.LOG.info("Hello Fabric world!"); - CommonClass.init(); - - // Some code like events require special initialization from the - // loader specific code. - ItemTooltipCallback.EVENT.register(CommonClass::onItemTooltip); + } } diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json index 47bb916..160567a 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/Fabric/src/main/resources/fabric.mod.json @@ -19,7 +19,7 @@ "environment": "*", "entrypoints": { "main": [ - "tschipp.carryon.ExampleMod" + "tschipp.carryon.CarryOnFabricMod" ] }, "mixins": [ diff --git a/Forge/src/main/java/tschipp/carryon/CarryOnForge.java b/Forge/src/main/java/tschipp/carryon/CarryOnForge.java new file mode 100644 index 0000000..46799c3 --- /dev/null +++ b/Forge/src/main/java/tschipp/carryon/CarryOnForge.java @@ -0,0 +1,18 @@ +package tschipp.carryon; + +import net.minecraftforge.fml.common.Mod; + +@Mod(Constants.MOD_ID) +public class CarryOnForge { + + public CarryOnForge() { + + // This method is invoked by the Forge mod loader when it is ready + // to load your mod. You can access Forge and Common code in this + // project. + + // Use Forge to bootstrap the Common mod. + Constants.LOG.info("Hello Forge world!"); + } + +} \ No newline at end of file diff --git a/Forge/src/main/java/tschipp/carryon/ExampleMod.java b/Forge/src/main/java/tschipp/carryon/ExampleMod.java deleted file mode 100644 index 11cb673..0000000 --- a/Forge/src/main/java/tschipp/carryon/ExampleMod.java +++ /dev/null @@ -1,33 +0,0 @@ -package tschipp.carryon; - -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.player.ItemTooltipEvent; -import net.minecraftforge.fml.common.Mod; - -@Mod(Constants.MOD_ID) -public class ExampleMod { - - public ExampleMod() { - - // This method is invoked by the Forge mod loader when it is ready - // to load your mod. You can access Forge and Common code in this - // project. - - // Use Forge to bootstrap the Common mod. - Constants.LOG.info("Hello Forge world!"); - CommonClass.init(); - - // Some code like events require special initialization from the - // loader specific code. - MinecraftForge.EVENT_BUS.addListener(this::onItemTooltip); - - } - - // This method exists as a wrapper for the code in the Common project. - // It takes Forge's event object and passes the parameters along to - // the Common listener. - private void onItemTooltip(ItemTooltipEvent event) { - - CommonClass.onItemTooltip(event.getItemStack(), event.getFlags(), event.getToolTip()); - } -} \ No newline at end of file diff --git a/Forge/src/main/java/tschipp/carryon/events/ClientEvents.java b/Forge/src/main/java/tschipp/carryon/events/ClientEvents.java new file mode 100644 index 0000000..233616d --- /dev/null +++ b/Forge/src/main/java/tschipp/carryon/events/ClientEvents.java @@ -0,0 +1,31 @@ +package tschipp.carryon.events; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.entity.player.Player; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.event.RenderHandEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import tschipp.carryon.Constants; +import tschipp.carryon.client.render.CarriedObjectRender; +import tschipp.carryon.client.render.CarryRenderHelper; + +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, modid = Constants.MOD_ID, value = Dist.CLIENT) +public class ClientEvents { + + @OnlyIn(Dist.CLIENT) + @SubscribeEvent + public static void renderHand(RenderHandEvent event) + { + Player player = Minecraft.getInstance().player; + MultiBufferSource buffer = event.getMultiBufferSource(); + PoseStack matrix = event.getPoseStack(); + int light = event.getPackedLight(); + + if(CarriedObjectRender.drawFirstPerson(player, buffer, matrix, light) && CarryRenderHelper.getPerspective() == 0) + event.setCanceled(true); + } +} diff --git a/Forge/src/main/java/tschipp/carryon/events/CommonEvents.java b/Forge/src/main/java/tschipp/carryon/events/CommonEvents.java new file mode 100644 index 0000000..f67beca --- /dev/null +++ b/Forge/src/main/java/tschipp/carryon/events/CommonEvents.java @@ -0,0 +1,105 @@ +package tschipp.carryon.events; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.BlockSnapshot; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.level.BlockEvent.EntityPlaceEvent; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.eventbus.api.Event.Result; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import tschipp.carryon.Constants; +import tschipp.carryon.common.carry.CarryOnData; +import tschipp.carryon.common.carry.CarryOnData.CarryType; +import tschipp.carryon.common.carry.CarryOnDataManager; +import tschipp.carryon.common.carry.PickupHandler; +import tschipp.carryon.common.carry.PlacementHandler; + +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, modid = Constants.MOD_ID) +public class CommonEvents +{ + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void onBlockClick(PlayerInteractEvent.RightClickBlock event) + { + if (event.isCanceled()) + return; + + Player player = event.getEntity(); + Level level = event.getLevel(); + BlockPos pos = event.getPos(); + + if (level.isClientSide) + return; + + boolean cancel = false; + + CarryOnData carry = CarryOnDataManager.getCarryData(player); + if (!carry.isCarrying()) { + if (PickupHandler.tryPickUpBlock((ServerPlayer) player, pos, level)) { + cancel = true; + } + } else { + if (carry.isCarrying(CarryType.BLOCK)) { + if (PlacementHandler.tryPlaceBlock((ServerPlayer) player, pos, event.getFace(), (pos2, state) -> { + BlockSnapshot snapshot = BlockSnapshot.create(level.dimension(), level, pos2); + EntityPlaceEvent event1 = new EntityPlaceEvent(snapshot, level.getBlockState(pos), player); + MinecraftForge.EVENT_BUS.post(event1); + return !event1.isCanceled(); + })) { + cancel = true; + } + } else { + if (PlacementHandler.tryPlaceEntity((ServerPlayer) player,pos, event.getFace(), null)) + { + cancel = true; + } + } + } + + if(cancel) + { + event.setUseBlock(Event.Result.DENY); + event.setUseItem(Event.Result.DENY); + event.setCancellationResult(InteractionResult.SUCCESS); + event.setCanceled(true); + return; + } + } + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void onEntityRightClick(PlayerInteractEvent.EntityInteract event) + { + if (event.isCanceled()) + return; + + Player player = event.getEntity(); + Level level = event.getLevel(); + Entity target = event.getTarget(); + + if (level.isClientSide) + return; + + CarryOnData carry = CarryOnDataManager.getCarryData(player); + if (!carry.isCarrying()) { + if (PickupHandler.tryPickupEntity((ServerPlayer) player, target)) { + event.setResult(Result.DENY); + event.setCancellationResult(InteractionResult.SUCCESS); + event.setCanceled(true); + return; + } + } + else if(carry.isCarrying(CarryType.ENTITY)) + { + //TODO: Stacking + } + } + +} diff --git a/Forge/src/main/java/tschipp/carryon/events/ModBusEvents.java b/Forge/src/main/java/tschipp/carryon/events/ModBusEvents.java new file mode 100644 index 0000000..764d8a4 --- /dev/null +++ b/Forge/src/main/java/tschipp/carryon/events/ModBusEvents.java @@ -0,0 +1,8 @@ +package tschipp.carryon.events; + +import net.minecraftforge.fml.common.Mod; +import tschipp.carryon.Constants; + +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD, modid = Constants.MOD_ID) +public class ModBusEvents { +} diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml index a2889e3..b13cc16 100644 --- a/Forge/src/main/resources/META-INF/mods.toml +++ b/Forge/src/main/resources/META-INF/mods.toml @@ -15,33 +15,29 @@ license="All rights reserved" # A list of mods - how many allowed here is determined by the individual mod loader [[mods]] #mandatory # The modid of the mod -modId="multiloader" #mandatory +modId="carryon" #mandatory # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it # ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata # see the associated build.gradle script for how to populate this completely automatically during a build version="${file.jarVersion}" #mandatory # A display name for the mod -displayName="Example Mod" #mandatory +displayName="Carry On" #mandatory # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ #updateJSONURL="https://change.me.example.invalid/updates.json" #optional # A URL for the "homepage" for this mod, displayed in the mod UI #displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional # A file name (in the root of the mod JAR) containing a logo for display -logoFile="multiloader.png" #optional +logoFile="carryon.png" #optional # A text field displayed in the mod UI -credits="Thanks for this example mod goes to Java" #optional +credits="Tschipp, PurpliciousCow, cy4n" #optional # A text field displayed in the mod UI -authors="Love, Cheese and small house plants" #optional +authors="Tschipp, PurpliciousCow, cy4n" #optional # The description text for the mod (multi line!) (#mandatory) description=''' -This is a long form description of the mod. You can write whatever you want here - -Have some lorem ipsum. - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis lacinia magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sagittis luctus odio eu tempus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque volutpat ligula eget lacus auctor sagittis. In hac habitasse platea dictumst. Nunc gravida elit vitae sem vehicula efficitur. Donec mattis ipsum et arcu lobortis, eleifend sagittis sem rutrum. Cras pharetra quam eget posuere fermentum. Sed id tincidunt justo. Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Carry On Mod. ''' # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. -[[dependencies.multiloader]] #optional +[[dependencies.carryon]] #optional # the modid of the dependency modId="forge" #mandatory # Does this dependency have to exist - if not, ordering below must be specified @@ -53,7 +49,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis lacinia magn # Side this dependency is applied on - BOTH, CLIENT or SERVER side="BOTH" # Here's another dependency -[[dependencies.multiloader]] +[[dependencies.carryon]] modId="minecraft" mandatory=true # This version range declares a minimum of the current minecraft version up to but not including the next major version diff --git a/gradle.properties b/gradle.properties index 2586b09..3bcb89e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,6 +4,7 @@ group=tschipp.carryon # Common minecraft_version=1.19.2 +parchment_mappings=2022.09.18 common_runs_enabled=false common_client_run_name=Common Client common_server_run_name=Common Server @@ -16,6 +17,10 @@ forge_version=43.1.30 fabric_version=0.62.0+1.19.2 fabric_loader_version=0.14.9 +# Quilt +quilt_loader_version=0.16.0-beta.7 +quilt_stdlib_version=1.1.0-beta.3+1.18.2 + # Mod options mod_name=Carry On mod_author=Tschipp, PurpliciousCow