Added networking, Scripting

This commit is contained in:
Tschipp 2022-11-29 00:49:57 +01:00
parent cf6a14f5d9
commit 375eb8dcc3
62 changed files with 2558 additions and 211 deletions

View File

@ -4,7 +4,7 @@ plugins {
id 'maven-publish' id 'maven-publish'
} }
archivesBaseName = "${mod_name}-common-${minecraft_version}" archivesBaseName = "${mod_id}-common-${minecraft_version}"
minecraft { minecraft {
version(minecraft_version) version(minecraft_version)

View File

@ -0,0 +1,58 @@
package tschipp.carryon;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.commands.CommandSourceStack;
import tschipp.carryon.common.command.CommandCarryOn;
import tschipp.carryon.config.ConfigLoader;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket;
import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket;
import tschipp.carryon.platform.Services;
public class CarryOnCommon
{
public static void registerServerPackets()
{
Services.PLATFORM.registerServerboundPacket(
Constants.PACKET_ID_KEY_PRESSED,
0,
ServerboundCarryKeyPressedPacket.class,
ServerboundCarryKeyPressedPacket::toBytes,
ServerboundCarryKeyPressedPacket::new,
ServerboundCarryKeyPressedPacket::handle
);
}
public static void registerClientPackets()
{
Services.PLATFORM.registerClientboundPacket(
Constants.PACKET_ID_START_RIDING,
1,
ClientboundStartRidingPacket.class,
ClientboundStartRidingPacket::toBytes,
ClientboundStartRidingPacket::new,
ClientboundStartRidingPacket::handle
);
Services.PLATFORM.registerClientboundPacket(
Constants.PACKET_ID_SYNC_SCRIPTS,
2,
ClientboundSyncScriptsPacket.class,
ClientboundSyncScriptsPacket::toBytes,
ClientboundSyncScriptsPacket::new,
ClientboundSyncScriptsPacket::handle
);
}
public static void registerConfig()
{
ConfigLoader.registerConfig(Constants.COMMON_CONFIG);
ConfigLoader.registerConfig(Constants.CLIENT_CONFIG);
}
public static void registerCommands(CommandDispatcher<CommandSourceStack> dispatcher)
{
CommandCarryOn.register(dispatcher);
}
}

View File

@ -0,0 +1,28 @@
package tschipp.carryon;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.client.keybinds.CarryOnKeybinds;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
public class CarryOnCommonClient
{
public static void checkForKeybinds()
{
Player player = Minecraft.getInstance().player;
if(player != null) {
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (CarryOnKeybinds.carryKey.isDown() && !carry.isKeyPressed()) {
CarryOnKeybinds.onCarryKey(true);
carry.setKeyPressed(true);
CarryOnDataManager.setCarryData(player, carry);
} else if (!CarryOnKeybinds.carryKey.isDown() && carry.isKeyPressed()) {
CarryOnKeybinds.onCarryKey(false);
carry.setKeyPressed(false);
CarryOnDataManager.setCarryData(player, carry);
}
}
}
}

View File

@ -1,9 +1,9 @@
package tschipp.carryon; package tschipp.carryon;
import net.minecraft.resources.ResourceLocation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import tschipp.carryon.common.config.CarryConfig; import tschipp.carryon.common.config.CarryConfig;
import tschipp.carryon.config.ConfigLoader;
public class Constants { public class Constants {
@ -14,8 +14,8 @@ public class Constants {
public static final CarryConfig.Common COMMON_CONFIG = new CarryConfig.Common(); public static final CarryConfig.Common COMMON_CONFIG = new CarryConfig.Common();
public static final CarryConfig.Client CLIENT_CONFIG = new CarryConfig.Client(); public static final CarryConfig.Client CLIENT_CONFIG = new CarryConfig.Client();
static { public static final ResourceLocation PACKET_ID_KEY_PRESSED = new ResourceLocation(Constants.MOD_ID, "key_pressed");
ConfigLoader.registerConfig(COMMON_CONFIG); public static final ResourceLocation PACKET_ID_START_RIDING = new ResourceLocation(Constants.MOD_ID, "start_riding");
ConfigLoader.registerConfig(CLIENT_CONFIG); public static final ResourceLocation PACKET_ID_SYNC_SCRIPTS = new ResourceLocation(Constants.MOD_ID, "sync_scripts");
}
} }

View File

@ -0,0 +1,12 @@
package tschipp.carryon.client;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.player.Player;
public class CarryOnClient
{
public static Player getPlayer()
{
return Minecraft.getInstance().player;
}
}

View File

@ -0,0 +1,25 @@
package tschipp.carryon.client.keybinds;
import net.minecraft.client.KeyMapping;
import tschipp.carryon.Constants;
import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket;
import tschipp.carryon.platform.Services;
import java.util.function.Consumer;
public class CarryOnKeybinds
{
public static KeyMapping carryKey;
public static void registerKeybinds(Consumer<KeyMapping> registrar)
{
carryKey = new KeyMapping("key.carry.desc", 340, "key.carry.category");
registrar.accept(carryKey);
}
public static void onCarryKey(boolean pressed)
{
Services.PLATFORM.sendPacketToServer(Constants.PACKET_ID_KEY_PRESSED, new ServerboundCarryKeyPressedPacket(pressed));
}
}

View File

@ -2,26 +2,28 @@ package tschipp.carryon.client.render;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Vector3f; import com.mojang.math.Vector3f;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.MultiBufferSource.BufferSource;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher; import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
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;
import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
import java.util.Optional; import java.util.Optional;
@ -32,9 +34,19 @@ public class CarriedObjectRender
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying(CarryType.BLOCK)) if(carry.isCarrying(CarryType.BLOCK))
drawFirstPersonBlock(player, buffer, matrix, light, carry.getBlock()); drawFirstPersonBlock(player, buffer, matrix, light, CarryRenderHelper.getRenderState(player));
else if (carry.isCarrying(CarryType.ENTITY)) else if (carry.isCarrying(CarryType.ENTITY))
drawFirstPersonEntity(player, buffer, matrix, light, carry.getEntity(player.level), partialTicks); drawFirstPersonEntity(player, buffer, matrix, light, partialTicks);
if(carry.getActiveScript().isPresent())
{
ScriptRender render = carry.getActiveScript().get().scriptRender();
if(!render.renderLeftArm() && player.getMainArm() == HumanoidArm.LEFT)
return false;
if(!render.renderRightArm() && player.getMainArm() == HumanoidArm.RIGHT)
return false;
}
return carry.isCarrying(); return carry.isCarrying();
} }
@ -46,44 +58,34 @@ public class CarriedObjectRender
matrix.translate(0, -0.5, -1); matrix.translate(0, -0.5, -1);
RenderSystem.enableBlend(); RenderSystem.enableBlend();
RenderSystem.disableCull(); RenderSystem.disableCull();
int perspective = CarryRenderHelper.getPerspective();
if (Constants.CLIENT_CONFIG.facePlayer && isChest(state.getBlock())) { CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (!Constants.CLIENT_CONFIG.facePlayer && CarryRenderHelper.isChest(state.getBlock())) {
matrix.mulPose(Vector3f.YP.rotationDegrees(180)); matrix.mulPose(Vector3f.YP.rotationDegrees(180));
matrix.mulPose(Vector3f.XN.rotationDegrees(8)); matrix.mulPose(Vector3f.XN.rotationDegrees(8));
} else { } else {
matrix.mulPose(Vector3f.XP.rotationDegrees(8)); matrix.mulPose(Vector3f.XP.rotationDegrees(8));
} }
// if(carry.getActiveScript().isPresent())
// CarryOnOverride carryOverride = ScriptChecker.getOverride(player); CarryRenderHelper.performScriptTransformation(matrix, carry.getActiveScript().get());
// 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); RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
ItemStack stack = new ItemStack(state.getBlock().asItem()); ItemStack stack = new ItemStack(state.getBlock().asItem());
//TODO: Model overrides BakedModel model = CarryRenderHelper.getRenderBlock(player);
BakedModel model = Minecraft.getInstance().getItemRenderer().getModel(stack, player.level, player, 0); CarryRenderHelper.renderBakedModel(stack, matrix, buffer, light, model);
CarryRenderHelper.renderItem(state, null, stack, matrix, buffer, light, model);
RenderSystem.enableCull(); RenderSystem.enableCull();
RenderSystem.disableBlend(); RenderSystem.disableBlend();
matrix.popPose(); matrix.popPose();
} }
private static void drawFirstPersonEntity(Player player, MultiBufferSource buffer, PoseStack matrix, int light, Entity entity, float partialTicks) { private static void drawFirstPersonEntity(Player player, MultiBufferSource buffer, PoseStack matrix, int light, float partialTicks) {
EntityRenderDispatcher manager = Minecraft.getInstance().getEntityRenderDispatcher(); EntityRenderDispatcher manager = Minecraft.getInstance().getEntityRenderDispatcher();
Entity entity = CarryRenderHelper.getRenderEntity(player);
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (entity != null) if (entity != null)
{ {
@ -102,58 +104,121 @@ public class CarriedObjectRender
matrix.mulPose(Vector3f.YP.rotationDegrees(180)); matrix.mulPose(Vector3f.YP.rotationDegrees(180));
matrix.translate(0.0, -height - .1, width + 0.1); matrix.translate(0.0, -height - .1, width + 0.1);
// RenderSystem.enableAlphaTest(); manager.setRenderShadow(false);
// Lighting.en Optional<CarryOnScript> res = carry.getActiveScript();
manager.setRenderShadow(false); if(res.isPresent())
{
//TODO: Scripts CarryOnScript script = res.get();
/* CarryRenderHelper.performScriptTransformation(matrix, script);
CarryOnOverride carryOverride = ScriptChecker.getOverride(player);
if (carryOverride != null)
{
CarryRenderHelper.performOverrideTransformation(matrix, carryOverride);
String entityname = carryOverride.getRenderNameEntity();
if (entityname != null)
{
Entity newEntity = null;
Optional<EntityType<?>> type = EntityType.byString(entityname);
if (type.isPresent())
newEntity = type.get().create(level);
if (newEntity != null)
{
CompoundTag nbttag = carryOverride.getRenderNBT();
if (nbttag != null)
newEntity.deserializeNBT(nbttag);
entity = newEntity;
entity.setPos(playerpos.x, playerpos.y, playerpos.z);
entity.xRotO = 0.0f;
entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f);
}
}
}
*/
if (entity instanceof LivingEntity)
((LivingEntity) entity).hurtTime = 0;
manager.render(entity, 0, 0, 0, 0f, 0, matrix, buffer, light);
manager.setRenderShadow(true);
} }
// RenderSystem.disableAlphaTest(); if (entity instanceof LivingEntity)
matrix.popPose(); ((LivingEntity) entity).hurtTime = 0;
manager.render(entity, 0, 0, 0, 0f, 0, matrix, buffer, light);
manager.setRenderShadow(true);
}
// RenderSystem.disableAlphaTest();
matrix.popPose();
} }
/**
* Draws the third person view of entities and blocks
* @param partialticks
* @param matrix
*/
public static void drawThirdPerson(float partialticks, PoseStack matrix) {
Minecraft mc = Minecraft.getInstance();
Level level = mc.level;
BufferSource buffer = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
int light = 0;
int perspective = CarryRenderHelper.getPerspective();
EntityRenderDispatcher manager = mc.getEntityRenderDispatcher();
private static boolean isChest(Block block) RenderSystem.enableBlend();
{ RenderSystem.disableCull();
return block == Blocks.CHEST || block == Blocks.ENDER_CHEST || block == Blocks.TRAPPED_CHEST; RenderSystem.disableDepthTest();
for (Player player : level.players())
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (perspective == 0 && player == mc.player)
continue;
light = manager.getPackedLightCoords(player, partialticks);
if (carry.isCarrying(CarryType.BLOCK))
{
BlockState state = CarryRenderHelper.getRenderState(player);
CarryRenderHelper.applyBlockTransformations(player, partialticks, matrix, state.getBlock());
ItemStack tileItem = new ItemStack(state.getBlock().asItem());
BakedModel model = CarryRenderHelper.getRenderBlock(player);
//ModelOverridesHandler.hasCustomOverrideModel(state, tag) ? ModelOverridesHandler.getCustomOverrideModel(state, tag, level, player) : tileItem.isEmpty() ? mc.getBlockRenderer().getBlockModel(state) : mc.getItemRenderer().getModel(tileItem, level, player, 0);
//
Optional<CarryOnScript> res = carry.getActiveScript();
if(res.isPresent())
{
CarryOnScript script = res.get();
CarryRenderHelper.performScriptTransformation(matrix, script);
}
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
RenderSystem.enableCull();
PoseStack.Pose p = matrix.last();
PoseStack copy = new PoseStack();
copy.mulPoseMatrix(p.pose());
matrix.popPose();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
CarryRenderHelper.renderBakedModel(tileItem, copy, buffer, light, model);
buffer.endBatch();
matrix.popPose();
}
else if (carry.isCarrying(CarryType.ENTITY))
{
Entity entity = CarryRenderHelper.getRenderEntity(player);
if (entity != null)
{
CarryRenderHelper.applyEntityTransformations(player, partialticks, matrix, entity);
manager.setRenderShadow(false);
Optional<CarryOnScript> res = carry.getActiveScript();
if(res.isPresent())
{
CarryOnScript script = res.get();
CarryRenderHelper.performScriptTransformation(matrix, script);
}
if (entity instanceof LivingEntity le)
le.hurtTime = 0;
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
manager.render(entity, 0, 0, 0, 0f, 0, matrix, buffer, light);
buffer.endBatch();
matrix.popPose();
manager.setRenderShadow(true);
matrix.popPose();
}
}
}
RenderSystem.enableDepthTest();
RenderSystem.enableCull();
RenderSystem.disableBlend();
} }
} }

View File

@ -9,15 +9,26 @@ import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType;
import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.nbt.CompoundTag; import net.minecraft.core.Registry;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.Pose;
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;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
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.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
public class CarryRenderHelper public class CarryRenderHelper
{ {
@ -28,8 +39,11 @@ public class CarryRenderHelper
public static float getExactBodyRotationDegrees(LivingEntity entity, float partialticks) public static float getExactBodyRotationDegrees(LivingEntity entity, float partialticks)
{ {
if (entity.getVehicle() != null && entity.getVehicle() instanceof LivingEntity) if (entity.getVehicle() != null && entity.getVehicle() instanceof LivingEntity vehicle)
return -(entity.yHeadRotO + (entity.yHeadRot - entity.yHeadRotO) * partialticks); if(vehicle instanceof Player player)
return -(player.yBodyRotO + (player.yBodyRot - player.yBodyRotO) * partialticks);
else
return -(entity.yHeadRotO + (entity.yHeadRot - entity.yHeadRotO) * partialticks);
else else
return -(entity.yBodyRotO + (entity.yBodyRot - entity.yBodyRotO) * partialticks); return -(entity.yBodyRotO + (entity.yBodyRot - entity.yBodyRotO) * partialticks);
} }
@ -99,14 +113,14 @@ public class CarryRenderHelper
matrix.mulPose(Vector3f.XN.rotationDegrees(f2 * (-90.0F - player.xRotO))); matrix.mulPose(Vector3f.XN.rotationDegrees(f2 * (-90.0F - player.xRotO)));
} }
Vec3 Vector3d = player.getViewVector(partialticks); Vec3 viewVector = player.getViewVector(partialticks);
Vec3 Vector3d1 = player.getDeltaMovement(); Vec3 deltaMovement = player.getDeltaMovement();
double d0 = Vector3d1.horizontalDistanceSqr(); double d0 = deltaMovement.horizontalDistanceSqr();
double d1 = Vector3d1.horizontalDistanceSqr(); double d1 = deltaMovement.horizontalDistanceSqr();
if (d0 > 0.0D && d1 > 0.0D) if (d0 > 0.0D && d1 > 0.0D)
{ {
double d2 = (Vector3d1.x * Vector3d.x + Vector3d1.z * Vector3d.z) / (Math.sqrt(d0) * Math.sqrt(d1)); double d2 = (deltaMovement.x * viewVector.x + deltaMovement.z * viewVector.z) / (Math.sqrt(d0) * Math.sqrt(d1));
double d3 = Vector3d1.x * Vector3d.z - Vector3d1.z * Vector3d.x; double d3 = deltaMovement.x * viewVector.z - deltaMovement.z * viewVector.x;
matrix.mulPose(Vector3f.YP.rotation((float) (Math.signum(d3) * Math.acos(d2)))); matrix.mulPose(Vector3f.YP.rotation((float) (Math.signum(d3) * Math.acos(d2))));
} }
@ -119,43 +133,182 @@ public class CarryRenderHelper
matrix.translate(0, 1.6, 0.65); matrix.translate(0, 1.6, 0.65);
} }
public static void applyBlockTransformations(Player player, float partialticks, PoseStack matrix, Block block)
{
int perspective = CarryRenderHelper.getPerspective();
//TODO: Scripting applyGeneralTransformations(player, partialticks, matrix);
// 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) if (!Constants.CLIENT_CONFIG.facePlayer && isChest(block))
{
//if ((ModList.get().isLoaded("realrender") || ModList.get().isLoaded("rfpr")) && perspective == 0)
// matrix.translate(0, 0, -0.4);
matrix.mulPose(Vector3f.YP.rotationDegrees(180));
}
//else if ((ModList.get().isLoaded("realrender") || ModList.get().isLoaded("rfpr")) && perspective == 0)
// matrix.translate(0, 0, 0.4);
//matrix.mulPose(Vector3f.YP.rotationDegrees(180));
float height = getRenderHeight(player);
float offset = (height - 1f) / 1.2f;
matrix.translate(0, -offset, 0);
}
public static void applyEntityTransformations(Player player, float partialticks, PoseStack matrix, Entity entity)
{
int perspective = CarryRenderHelper.getPerspective();
Pose pose = player.getPose();
applyGeneralTransformations(player, partialticks, matrix);
if (perspective == 2)
matrix.translate(0, -1.6, 0.65);
else
matrix.translate(0, -1.6, -0.65);
matrix.scale(1.666f, 1.666f, 1.666f);
float height = entity.getBbHeight();
float width = entity.getBbWidth();
float multiplier = height * width;
entity.yo = 0.0f;
entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f);
entity.xo = 0.0f;
entity.xRotO = 0.0f;
if (perspective == 2)
matrix.mulPose(Vector3f.YP.rotationDegrees(180));
matrix.scale((10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f);
matrix.translate(0.0, height / 2 + -(height / 2) + 1, width - 0.1 < 0.7 ? width - 0.1 + (0.7 - (width - 0.1)) : width - 0.1);
if (pose == Pose.SWIMMING || pose == Pose.FALL_FLYING)
{
matrix.mulPose(Vector3f.XN.rotationDegrees(90));
matrix.translate(0, -0.2 * height, 0);
if (pose == Pose.FALL_FLYING)
matrix.translate(0, 0, 0.2);
}
}
public static void performScriptTransformation(PoseStack matrix, CarryOnScript script)
{
int perspective = getPerspective();
ScriptRender render = script.scriptRender();
Vec3 translation = render.renderTranslation().getVec();
Vec3 rotation = render.renderRotation().getVec();
Vec3 scale = render.renderscale().getVec(1);
Quaternion rot = Vector3f.XP.rotationDegrees((float) rotation.x);
rot.mul(Vector3f.YP.rotationDegrees((float) rotation.y));
rot.mul(Vector3f.ZP.rotationDegrees((float) rotation.z));
matrix.mulPose(rot);
matrix.translate(translation.x, translation.y, perspective == 1 && script.isBlock() ? -translation.z : translation.z);
matrix.scale((float) scale.x, (float) scale.y, (float) scale.z);
}
public static void renderBakedModel(ItemStack stack, PoseStack matrix, MultiBufferSource buffer, int light, BakedModel model)
{ {
ItemRenderer renderer = Minecraft.getInstance().getItemRenderer(); 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); renderer.render(stack, TransformType.NONE, false, matrix, buffer, light, OverlayTexture.NO_OVERLAY, model);
} }
public static BlockState getRenderState(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
BlockState state = carry.getBlock().getBlock().defaultBlockState();
if(carry.getActiveScript().isPresent())
{
ScriptRender render = carry.getActiveScript().get().scriptRender();
if(render.renderNameBlock().isPresent())
state = Registry.BLOCK.get(render.renderNameBlock().get()).defaultBlockState();
}
return state;
}
public static BakedModel getRenderBlock(Player player)
{
BlockState state = getRenderState(player);
BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state);
if(state.getRenderShape() != RenderShape.MODEL || model.isCustomRenderer() || model.getQuads(state, null, RandomSource.create()).size() <= 0) {
ItemStack stack = new ItemStack(state.getBlock());
model = Minecraft.getInstance().getItemRenderer().getModel(stack, player.level, player, 0);
}
return model;
}
public static Entity getRenderEntity(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
Entity entity = carry.getEntity(player.level);
if(carry.getActiveScript().isPresent())
{
CarryOnScript script = carry.getActiveScript().get();
ScriptRender render = script.scriptRender();
if(render.renderNameEntity().isPresent())
entity = Registry.ENTITY_TYPE.get(render.renderNameEntity().get()).create(player.level);
if(render.renderNBT().isPresent())
entity.load(render.renderNBT().get());
}
return entity;
}
public static float getRenderWidth(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying(CarryType.BLOCK))
{
VoxelShape shape = getRenderState(player).getShape(player.level, player.blockPosition());
if(shape == null)
return 1f;
float width = (float)Math.abs(shape.bounds().maxX - shape.bounds().minX);
return width;
}
else if(carry.isCarrying(CarryType.ENTITY))
{
Entity entity = getRenderEntity(player);
return entity.getBbWidth();
}
else
return 1f;
}
public static float getRenderHeight(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying(CarryType.BLOCK))
{
VoxelShape shape = getRenderState(player).getShape(player.level, player.blockPosition());
if(shape == null)
return 1f;
float height = (float)Math.abs(shape.bounds().maxY - shape.bounds().minY);
return height;
}
else if(carry.isCarrying(CarryType.ENTITY))
{
Entity entity = getRenderEntity(player);
return entity.getBbHeight();
}
else
return 1f;
}
@SuppressWarnings("resource") @SuppressWarnings("resource")
public static int getPerspective() public static int getPerspective()
{ {
@ -176,4 +329,10 @@ public class CarryRenderHelper
return player.isShiftKeyDown() || player.isCrouching(); return player.isShiftKeyDown() || player.isCrouching();
} }
public static boolean isChest(Block block)
{
return block == Blocks.CHEST || block == Blocks.ENDER_CHEST || block == Blocks.TRAPPED_CHEST;
}
} }

View File

@ -1,21 +1,28 @@
package tschipp.carryon.common.carry; package tschipp.carryon.common.carry;
import com.mojang.serialization.DataResult;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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.BlockStateProperties;
import tschipp.carryon.common.scripting.CarryOnScript;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Optional;
public class CarryOnData { public class CarryOnData {
private CarryType type; private CarryType type;
private CompoundTag nbt; private CompoundTag nbt;
private boolean keyPressed = false;
private CarryOnScript activeScript;
public CarryOnData(CompoundTag data) public CarryOnData(CompoundTag data)
{ {
@ -25,11 +32,27 @@ public class CarryOnData {
this.type = CarryType.INVALID; this.type = CarryType.INVALID;
this.nbt = data; this.nbt = data;
if(data.contains("keyPressed"))
this.keyPressed = data.getBoolean("keyPressed");
if(data.contains("activeScript"))
{
DataResult<CarryOnScript> res = CarryOnScript.CODEC.parse(NbtOps.INSTANCE, data.get("activeScript"));
this.activeScript = res.getOrThrow(false, (s) -> {throw new RuntimeException("Failed to decode activeScript during CarryOnData serialization: " + s);});
}
} }
public CompoundTag getNbt() public CompoundTag getNbt()
{ {
nbt.putString("type", type.toString()); nbt.putString("type", type.toString());
nbt.putBoolean("keyPressed", keyPressed);
if(activeScript != null)
{
DataResult<Tag> res = CarryOnScript.CODEC.encodeStart(NbtOps.INSTANCE, activeScript);
Tag tag = res.getOrThrow(false, (s) -> {throw new RuntimeException("Failed to encode activeScript during CarryOnData serialization: " + s);});
nbt.put("activeScript", tag);
}
return nbt; return nbt;
} }
@ -83,7 +106,23 @@ public class CarryOnData {
if(this.type != CarryType.ENTITY) if(this.type != CarryType.ENTITY)
throw new IllegalStateException("Called getEntity on data that contained " + this.type); throw new IllegalStateException("Called getEntity on data that contained " + this.type);
return EntityType.create(nbt.getCompound("entity"), level).orElseThrow(); return EntityType.create(nbt.getCompound("entity"), level).orElseThrow(() -> new IllegalStateException("Called EntityType#create even though no entity data was present. Data: " + nbt.toString()));
}
public Optional<CarryOnScript> getActiveScript()
{
if(activeScript == null)
return Optional.empty();
return Optional.of(activeScript);
}
public void setActiveScript(CarryOnScript script)
{
this.activeScript = script;
}
public void setCarryingPlayer() {
this.type = CarryType.PLAYER;
} }
public boolean isCarrying() public boolean isCarrying()
@ -96,10 +135,18 @@ public class CarryOnData {
return this.type == type; return this.type == type;
} }
public boolean isKeyPressed() {return this.keyPressed;}
public void setKeyPressed(boolean val) {
this.keyPressed = val;
this.nbt.putBoolean("keyPressed", val);
}
public void clear() public void clear()
{ {
this.type = CarryType.INVALID; this.type = CarryType.INVALID;
this.nbt = new CompoundTag(); this.nbt = new CompoundTag();
this.activeScript = null;
} }
public int getTick() public int getTick()
@ -112,6 +159,7 @@ public class CarryOnData {
public enum CarryType { public enum CarryType {
BLOCK, BLOCK,
ENTITY, ENTITY,
PLAYER,
INVALID INVALID
} }
} }

View File

@ -5,7 +5,6 @@ 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.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import org.apache.commons.lang3.ObjectUtils;
public class CarryOnDataManager { public class CarryOnDataManager {
@ -22,10 +21,7 @@ public class CarryOnDataManager {
{ {
CompoundTag nbt = data.getNbt(); CompoundTag nbt = data.getNbt();
nbt.putInt("tick", player.tickCount); 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); player.getEntityData().set(CARRY_DATA_KEY, nbt);
System.out.println(player.getEntityData().isDirty());
} }
} }

View File

@ -191,4 +191,34 @@ public class ListHandler {
return containsAll; return containsAll;
} }
public static void addForbiddenTiles(String toAdd)
{
FORBIDDEN_TILES.add(toAdd);
}
public static void addForbiddenEntities(String toAdd)
{
FORBIDDEN_ENTITIES.add(toAdd);
}
public static void addForbiddenStacking(String toAdd)
{
FORBIDDEN_STACKING.add(toAdd);
}
public static void addAllowedTiles(String toAdd)
{
ALLOWED_TILES.add(toAdd);
}
public static void addAllowedEntities(String toAdd)
{
ALLOWED_ENTITIES.add(toAdd);
}
public static void addAllowedStacking(String toAdd)
{
ALLOWED_ENTITIES.add(toAdd);
}
} }

View File

@ -19,17 +19,18 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.ScriptManager;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
import tschipp.carryon.platform.Services;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public class PickupHandler { public class PickupHandler {
public static boolean canCarryGeneral(ServerPlayer player, Vec3 pos) public static boolean canCarryGeneral(ServerPlayer player, Vec3 pos)
{ {
//TODO: Check carry key
if(!player.isShiftKeyDown())
return false;
if(!player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty()) if(!player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty())
return false; return false;
@ -40,6 +41,9 @@ public class PickupHandler {
if(carry.isCarrying()) if(carry.isCarrying())
return false; return false;
if(!carry.isKeyPressed())
return false;
//Needed so that we don't pick up and place in the same tick //Needed so that we don't pick up and place in the same tick
if(player.tickCount == carry.getTick()) if(player.tickCount == carry.getTick())
return false; return false;
@ -61,6 +65,9 @@ public class PickupHandler {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
BlockEntity blockEntity = level.getBlockEntity(pos); BlockEntity blockEntity = level.getBlockEntity(pos);
BlockState state = level.getBlockState(pos); BlockState state = level.getBlockState(pos);
CompoundTag nbt = null;
if(blockEntity != null)
nbt = blockEntity.saveWithId();
if(!ListHandler.isPermitted(state.getBlock())) if(!ListHandler.isPermitted(state.getBlock()))
return false; return false;
@ -74,17 +81,28 @@ public class PickupHandler {
//Check if TE is locked //Check if TE is locked
if(blockEntity != null) if(blockEntity != null)
{ {
CompoundTag nbt = blockEntity.saveWithId();
if(nbt.contains("Lock") && !nbt.getString("Lock").equals("")) if(nbt.contains("Lock") && !nbt.getString("Lock").equals(""))
return false; return false;
} }
//TODO: Script conditions
//TODO: Gamestages conditions check //TODO: Gamestages conditions check
//TODO: Protections //TODO: Protections
Optional<CarryOnScript> result = ScriptManager.inspectBlock(state, level, pos, nbt);
if(result.isPresent())
{
CarryOnScript script = result.get();
if(!script.fulfillsConditions(player))
return false;
carry.setActiveScript(script);
String cmd = script.scriptEffects().commandInit();
if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd);
}
carry.setBlock(state, blockEntity); carry.setBlock(state, blockEntity);
level.removeBlockEntity(pos); level.removeBlockEntity(pos);
@ -106,9 +124,6 @@ public class PickupHandler {
if (entity.invulnerableTime != 0) if (entity.invulnerableTime != 0)
return false; return false;
if (entity instanceof Player)
return false;
if (entity instanceof TamableAnimal tame) if (entity instanceof TamableAnimal tame)
{ {
UUID owner = tame.getOwnerUUID(); UUID owner = tame.getOwnerUUID();
@ -130,21 +145,65 @@ public class PickupHandler {
if(!Constants.COMMON_CONFIG.settings.pickupHostileMobs && entity.getType().getCategory() == MobCategory.MONSTER) if(!Constants.COMMON_CONFIG.settings.pickupHostileMobs && entity.getType().getCategory() == MobCategory.MONSTER)
return false; return false;
if(Constants.COMMON_CONFIG.settings.maxEntityHeight > entity.getBbHeight() || Constants.COMMON_CONFIG.settings.maxEntityWidth > entity.getBbWidth()) if(Constants.COMMON_CONFIG.settings.maxEntityHeight < entity.getBbHeight() || Constants.COMMON_CONFIG.settings.maxEntityWidth < entity.getBbWidth())
return false; return false;
} }
//TODO: Script conditions
//TODO: Gamestages conditions check //TODO: Gamestages conditions check
//TODO: Protections //TODO: Protections
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
Optional<CarryOnScript> result = ScriptManager.inspectEntity(entity);
if(result.isPresent())
{
CarryOnScript script = result.get();
if(!script.fulfillsConditions(player))
return false;
carry.setActiveScript(script);
}
if (entity instanceof Player otherPlayer) {
if (!Constants.COMMON_CONFIG.settings.pickupPlayers)
return false;
if (!player.isCreative() && otherPlayer.isCreative())
return false;
otherPlayer.ejectPassengers();
otherPlayer.stopRiding();
if (result.isPresent()) {
String cmd = result.get().scriptEffects().commandInit();
if (!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd);
}
otherPlayer.startRiding(player);
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_START_RIDING, new ClientboundStartRidingPacket(otherPlayer.getId(), true), player);
carry.setCarryingPlayer();
player.swing(InteractionHand.MAIN_HAND, true);
player.level.playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC, SoundSource.AMBIENT, 1.0f, 0.5f);
CarryOnDataManager.setCarryData(player, carry);
return true;
}
entity.ejectPassengers(); entity.ejectPassengers();
if (entity instanceof Animal animal) entity.stopRiding();
if (entity instanceof Animal animal) {
animal.dropLeash(true, true); animal.dropLeash(true, true);
}
if(result.isPresent())
{
String cmd = result.get().scriptEffects().commandInit();
if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd);
}
carry.setEntity(entity); carry.setEntity(entity);
entity.remove(RemovalReason.UNLOADED_WITH_PLAYER); entity.remove(RemovalReason.UNLOADED_WITH_PLAYER);
@ -155,4 +214,18 @@ public class PickupHandler {
return true; return true;
} }
public static void onCarryTick(ServerPlayer player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
{
if(carry.getActiveScript().isPresent())
{
String cmd = carry.getActiveScript().get().scriptEffects().commandLoop();
if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd);
}
}
}
} }

View File

@ -3,10 +3,12 @@ package tschipp.carryon.common.carry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.animal.horse.Horse;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -19,9 +21,12 @@ import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.CollisionContext;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData.CarryType; import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptEffects;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public class PlacementHandler public class PlacementHandler
@ -50,7 +55,10 @@ public class PlacementHandler
boolean canPlace = state.canSurvive(level, pos) && level.mayInteract(player, pos) && level.getBlockState(pos).canBeReplaced(context) && level.isUnobstructed(state, pos, CollisionContext.of(player)); boolean canPlace = state.canSurvive(level, pos) && level.mayInteract(player, pos) && level.getBlockState(pos).canBeReplaced(context) && level.isUnobstructed(state, pos, CollisionContext.of(player));
if (!canPlace) if (!canPlace)
{
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
return false; return false;
}
state = getPlacementState(state, player, context, pos); state = getPlacementState(state, player, context, pos);
boolean doPlace = placementCallback == null || placementCallback.apply(pos, state); boolean doPlace = placementCallback == null || placementCallback.apply(pos, state);
@ -58,6 +66,14 @@ public class PlacementHandler
if (!doPlace) if (!doPlace)
return false; return false;
if(carry.getActiveScript().isPresent())
{
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace();
if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd);
}
level.setBlock(pos, state, 3); level.setBlock(pos, state, 3);
if (blockEntity != null) if (blockEntity != null)
level.setBlockEntity(blockEntity); level.setBlockEntity(blockEntity);
@ -72,7 +88,6 @@ public class PlacementHandler
private static BlockState getPlacementState(BlockState state, ServerPlayer player, BlockPlaceContext context, BlockPos pos) private static BlockState getPlacementState(BlockState state, ServerPlayer player, BlockPlaceContext context, BlockPos pos)
{ {
BlockState placementState = state.getBlock().getStateForPlacement(context); BlockState placementState = state.getBlock().getStateForPlacement(context);
System.out.println(placementState);
for (var prop : placementState.getProperties()) { for (var prop : placementState.getProperties()) {
if (prop instanceof DirectionProperty) { if (prop instanceof DirectionProperty) {
@ -88,8 +103,6 @@ public class PlacementHandler
} }
} }
System.out.println(state);
state = Block.updateFromNeighbourShapes(state, player.level, pos); state = Block.updateFromNeighbourShapes(state, player.level, pos);
if (placementState.hasProperty(BlockStateProperties.WATERLOGGED)) if (placementState.hasProperty(BlockStateProperties.WATERLOGGED))
@ -107,7 +120,8 @@ public class PlacementHandler
public static boolean tryPlaceEntity(ServerPlayer player, BlockPos pos, Direction facing, @Nullable BiFunction<Vec3, Entity, Boolean> placementCallback) public static boolean tryPlaceEntity(ServerPlayer player, BlockPos pos, Direction facing, @Nullable BiFunction<Vec3, Entity, Boolean> placementCallback)
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (!carry.isCarrying(CarryType.ENTITY))
if (!carry.isCarrying(CarryType.ENTITY) && !carry.isCarrying(CarryType.PLAYER))
return false; return false;
if (player.tickCount == carry.getTick()) if (player.tickCount == carry.getTick())
@ -121,6 +135,18 @@ public class PlacementHandler
Vec3 placementPos = Vec3.atBottomCenterOf(pos); Vec3 placementPos = Vec3.atBottomCenterOf(pos);
if(carry.isCarrying(CarryType.PLAYER))
{
Entity otherPlayer = player.getFirstPassenger();
player.ejectPassengers();
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
if(otherPlayer == null)
return true;
otherPlayer.teleportTo(placementPos.x, placementPos.y, placementPos.z);
player.swing(InteractionHand.MAIN_HAND, true);
return true;
}
Entity entity = carry.getEntity(level); Entity entity = carry.getEntity(level);
entity.setPos(placementPos); entity.setPos(placementPos);
@ -129,6 +155,14 @@ public class PlacementHandler
if (!doPlace) if (!doPlace)
return false; return false;
if(carry.getActiveScript().isPresent())
{
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace();
if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd);
}
level.addFreshEntity(entity); level.addFreshEntity(entity);
if(entity instanceof Mob mob) if(entity instanceof Mob mob)
mob.playAmbientSound(); mob.playAmbientSound();
@ -139,4 +173,115 @@ public class PlacementHandler
return true; return true;
} }
public static void tryStackEntity(ServerPlayer player, Entity entityClicked)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(!carry.isCarrying(CarryType.ENTITY) && !carry.isCarrying(CarryType.PLAYER))
return;
Level level = player.level;
Entity entityHeld;
if(carry.isCarrying(CarryType.ENTITY))
entityHeld = carry.getEntity(level);
else
entityHeld = player.getFirstPassenger();
double sizeHeldEntity = entityHeld.getBbHeight() * entityHeld.getBbWidth();
double distance = entityClicked.blockPosition().distSqr(player.blockPosition());
Entity lowestEntity = entityClicked.getRootVehicle();
int numPassengers = getPassengerCount(lowestEntity);
if (numPassengers < Constants.COMMON_CONFIG.settings.maxEntityStackLimit - 1)
{
Entity topEntity = getTopPassenger(lowestEntity);
if(topEntity == entityHeld)
return;
if (ListHandler.isStackingPermitted(topEntity))
{
double sizeEntity = topEntity.getBbHeight() * topEntity.getBbWidth();
if (Constants.COMMON_CONFIG.settings.entitySizeMattersStacking && sizeHeldEntity <= sizeEntity || !Constants.COMMON_CONFIG.settings.entitySizeMattersStacking)
{
if (topEntity instanceof Horse horse)
horse.setTamed(true);
if (distance < 6)
{
double tempX = entityClicked.getX();
double tempY = entityClicked.getY();
double tempZ = entityClicked.getZ();
if(carry.isCarrying(CarryType.ENTITY)) {
entityHeld.setPos(tempX, tempY + 2.6, tempZ);
level.addFreshEntity(entityHeld);
entityHeld.teleportTo(tempX, tempY, tempZ);
}
entityHeld.startRiding(topEntity, false);
}
else
{
if(carry.isCarrying(CarryType.ENTITY)) {
entityHeld.setPos(entityClicked.getX(), entityClicked.getY(), entityClicked.getZ());
level.addFreshEntity(entityHeld);
}
entityHeld.startRiding(topEntity, false);
}
if(carry.getActiveScript().isPresent())
{
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace();
if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd);
}
player.swing(InteractionHand.MAIN_HAND, true);
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.HORSE_SADDLE, SoundSource.PLAYERS, 0.5F, 1.5F);
}
else
{
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
}
}
}
else
{
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
}
}
private static int getPassengerCount(Entity entity)
{
int passengers = 0;
while (entity.isVehicle())
{
List<Entity> pass = entity.getPassengers();
if (!pass.isEmpty())
{
entity = pass.get(0);
passengers++;
}
}
return passengers;
}
private static Entity getTopPassenger(Entity entity)
{
Entity top = entity;
while (entity.isVehicle())
{
List<Entity> pass = entity.getPassengers();
if (!pass.isEmpty())
{
entity = pass.get(0);
top = entity;
}
}
return top;
}
} }

View File

@ -0,0 +1,112 @@
package tschipp.carryon.common.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import java.util.Collection;
import java.util.Collections;
public class CommandCarryOn
{
public static void register(CommandDispatcher<CommandSourceStack> dispatcher)
{
LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("carryon")
.then(Commands.literal("debug").executes(cmd -> handleDebug(cmd.getSource())))
.then(Commands.literal("clear").executes(cmd -> handleClear(cmd.getSource(), Collections.singleton(cmd.getSource().getPlayerOrException()))))
.then(Commands.literal("clear").then(Commands.argument("target", EntityArgument.players()).requires(src -> src.hasPermission(2)).executes(cmd -> handleClear(cmd.getSource(), EntityArgument.getPlayers(cmd, "target")))))
;
dispatcher.register(builder);
}
private static int handleDebug(CommandSourceStack source)
{
try
{
if (source.getEntityOrException() != null)
{
ServerPlayer player = source.getPlayerOrException();
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (carry.isCarrying(CarryType.BLOCK))
{
log(source,"Block: " + carry.getBlock().getBlock());
log(source,"BlockState: " + carry.getBlock());
log(source,"NBT: " + carry.getNbt());
//TODO
// if (ModelOverridesHandler.hasCustomOverrideModel(ItemCarryonBlock.getBlockState(main), ItemCarryonBlock.getTileData(main)))
// source.sendSuccess(Component.literal("Override Model: " + ModelOverridesHandler.getOverrideObject(ItemCarryonBlock.getBlockState(main), ItemCarryonBlock.getTileData(main))), true);
// if (CustomPickupOverrideHandler.hasSpecialPickupConditions(ItemCarryonBlock.getBlockState(main)))
// source.sendSuccess(Component.literal("Custom Pickup Condition: " + CustomPickupOverrideHandler.getPickupCondition(ItemCarryonBlock.getBlockState(main))), true);
return 1;
}
else if (carry.isCarrying(CarryType.ENTITY))
{
log(source,"Entity: " + carry.getEntity(player.level));
log(source,"Entity Name: " + carry.getEntity(player.level).getType());
log(source,"NBT: " + carry.getNbt());
// if (CustomPickupOverrideHandler.hasSpecialPickupConditions(ItemCarryonEntity.getEntity(main, player.level)))
// source.sendSuccess(Component.literal("Custom Pickup Condition: " + CustomPickupOverrideHandler.getPickupCondition(ItemCarryonEntity.getEntity(main, player.level))), true);
return 1;
}
else if(carry.isCarrying(CarryType.PLAYER))
{
log(source, "Carrying Player.");
}
}
}
catch (CommandSyntaxException e)
{
}
return 0;
}
private static int handleClear(CommandSourceStack source, Collection<ServerPlayer> players)
{
int cleared = 0;
for (ServerPlayer player : players)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
cleared++;
}
if (cleared != 1)
source.sendSuccess(Component.literal("Cleared " + cleared + " Items!"), true);
else
source.sendSuccess(Component.literal("Cleared " + cleared + " Item!"), true);
return 1;
}
private static void log(CommandSourceStack source, String toLog)
{
source.sendSuccess(Component.literal(toLog), true);
Constants.LOG.info(toLog);
}
}

View File

@ -153,6 +153,12 @@ public class CarryConfig {
public String[] placementStateExceptions = { public String[] placementStateExceptions = {
"minecraft:chest[type]" "minecraft:chest[type]"
}; };
@Property(
type = PropertyType.BOOLEAN,
description = "Whether Players can be picked up. Creative players can't be picked up in Survival Mode"
)
public boolean pickupPlayers = true;
} }
@Property( @Property(
@ -196,7 +202,7 @@ public class CarryConfig {
description = "Blocks that cannot be picked up" description = "Blocks that cannot be picked up"
) )
public String[] forbiddenTiles = { public String[] forbiddenTiles = {
"#forge:immovable", "#forge:relocation_not_supported", "minecraft:end_portal", "#forge:immovable", "#forge:relocation_not_supported", "minecraft:end_portal", "minecraft:piston_head",
"minecraft:end_gateway", "minecraft:tall_grass", "minecraft:large_fern", "minecraft:peony", "minecraft:end_gateway", "minecraft:tall_grass", "minecraft:large_fern", "minecraft:peony",
"minecraft:rose_bush", "minecraft:lilac", "minecraft:sunflower", "minecraft:*_bed", "minecraft:rose_bush", "minecraft:lilac", "minecraft:sunflower", "minecraft:*_bed",
"minecraft:*_door", "minecraft:big_dripleaf_stem", "minecraft:waterlily", "minecraft:cake", "minecraft:*_door", "minecraft:big_dripleaf_stem", "minecraft:waterlily", "minecraft:cake",

View File

@ -0,0 +1,185 @@
package tschipp.carryon.common.scripting;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectBlock;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectEntity;
import tschipp.carryon.common.scripting.Matchables.*;
import java.util.Optional;
public record CarryOnScript(
long priority,
ScriptObject scriptObject,
ScriptConditions scriptConditions,
ScriptRender scriptRender,
ScriptEffects scriptEffects)
{
public boolean isValid()
{
return (isBlock() ^ isEntity()) && (scriptConditions != ScriptConditions.EMPTY || scriptRender != ScriptRender.EMPTY || scriptEffects != ScriptEffects.EMPTY);
}
public boolean isBlock()
{
return scriptObject.block() != ScriptObjectBlock.EMPTY;
}
public boolean isEntity()
{
return scriptObject.entity() != ScriptObjectEntity.EMPTY;
}
public static final Codec<CarryOnScript> CODEC = RecordCodecBuilder.create(instance -> // Given an instance
instance.group(
Codec.LONG.optionalFieldOf("priority", 0L).forGetter(CarryOnScript::priority),
ScriptObject.CODEC.fieldOf("object").forGetter(CarryOnScript::scriptObject),
ScriptConditions.CODEC.optionalFieldOf("conditions", ScriptConditions.EMPTY).forGetter(CarryOnScript::scriptConditions),
ScriptRender.CODEC.optionalFieldOf("render", ScriptRender.EMPTY).forGetter(CarryOnScript::scriptRender),
ScriptEffects.CODEC.optionalFieldOf("effects", ScriptEffects.EMPTY).forGetter(CarryOnScript::scriptEffects)
).apply(instance, CarryOnScript::new)
);
public boolean fulfillsConditions(ServerPlayer player)
{
ScriptConditions cond = this.scriptConditions();
boolean achievement = cond.conditionAchievement.matches(player);
boolean gamemode = cond.conditionGamemode.matches(player.gameMode.getGameModeForPlayer().getId());
boolean gamestage = cond.conditionGamestage.matches(player);
boolean position = cond.conditionPosition.matches(player);
boolean xp = cond.conditionXp.matches(player.experienceLevel);
boolean scoreboard = cond.conditionScoreboard.matches(player);
boolean effects = cond.conditionEffects.matches(player);
return achievement && gamemode && gamestage && position && xp && scoreboard && effects;
}
public record ScriptObject(ScriptObjectBlock block, ScriptObjectEntity entity)
{
public static final Codec<ScriptObject> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ScriptObjectBlock.CODEC.optionalFieldOf("block", ScriptObjectBlock.EMPTY).forGetter(ScriptObject::block),
ScriptObjectEntity.CODEC.optionalFieldOf("entity", ScriptObjectEntity.EMPTY).forGetter(ScriptObject::entity)
).apply(instance, ScriptObject::new)
);
public record ScriptObjectBlock(
Optional<ResourceKey<Block>> typeNameBlock,
MaterialCondition typeMaterial,
NumberBoundCondition typeHardness,
NumberBoundCondition typeResistance,
NBTCondition typeBlockTag
){
public static final ScriptObjectBlock EMPTY = new ScriptObjectBlock(Optional.empty(), MaterialCondition.NONE, NumberBoundCondition.NONE, NumberBoundCondition.NONE, NBTCondition.NONE);
public static final Codec<ScriptObjectBlock> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ResourceKey.codec(Registry.BLOCK_REGISTRY).optionalFieldOf("name").forGetter(ScriptObjectBlock::typeNameBlock),
MaterialCondition.CODEC.optionalFieldOf("material", MaterialCondition.NONE).forGetter(ScriptObjectBlock::typeMaterial),
NumberBoundCondition.CODEC.optionalFieldOf("hardness", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeHardness),
NumberBoundCondition.CODEC.optionalFieldOf("resistance", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeResistance),
NBTCondition.CODEC.optionalFieldOf("nbt", NBTCondition.NONE).forGetter(ScriptObjectBlock::typeBlockTag)
).apply(instance, ScriptObjectBlock::new)
);
}
public record ScriptObjectEntity(
Optional<ResourceKey<EntityType<?>>> typeNameEntity,
NumberBoundCondition typeHealth,
NumberBoundCondition typeHeight,
NumberBoundCondition typeWidth,
NBTCondition typeEntityTag
){
public static final ScriptObjectEntity EMPTY = new ScriptObjectEntity(Optional.empty(), NumberBoundCondition.NONE, NumberBoundCondition.NONE, NumberBoundCondition.NONE, NBTCondition.NONE);
public static final Codec<ScriptObjectEntity> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ResourceKey.codec(Registry.ENTITY_TYPE_REGISTRY).optionalFieldOf("name").forGetter(ScriptObjectEntity::typeNameEntity),
NumberBoundCondition.CODEC.optionalFieldOf("health", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeHealth),
NumberBoundCondition.CODEC.optionalFieldOf("height", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeHeight),
NumberBoundCondition.CODEC.optionalFieldOf("width", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeWidth),
NBTCondition.CODEC.optionalFieldOf("nbt", NBTCondition.NONE).forGetter(ScriptObjectEntity::typeEntityTag)
).apply(instance, ScriptObjectEntity::new)
);
}
}
public record ScriptConditions(
GamestageCondition conditionGamestage,
AdvancementCondition conditionAchievement,
NumberBoundCondition conditionXp,
NumberBoundCondition conditionGamemode,
ScoreboardCondition conditionScoreboard,
PositionCondition conditionPosition,
EffectsCondition conditionEffects
){
public static final ScriptConditions EMPTY = new ScriptConditions(GamestageCondition.NONE, AdvancementCondition.NONE, NumberBoundCondition.NONE, NumberBoundCondition.NONE, ScoreboardCondition.NONE, PositionCondition.NONE, EffectsCondition.NONE);
public static final Codec<ScriptConditions> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
GamestageCondition.CODEC.optionalFieldOf("gamestage", GamestageCondition.NONE).forGetter(ScriptConditions::conditionGamestage),
AdvancementCondition.CODEC.optionalFieldOf("advancement", AdvancementCondition.NONE).forGetter(ScriptConditions::conditionAchievement),
NumberBoundCondition.CODEC.optionalFieldOf("xp", NumberBoundCondition.NONE).forGetter(ScriptConditions::conditionXp),
NumberBoundCondition.CODEC.optionalFieldOf("gamemode", NumberBoundCondition.NONE).forGetter(ScriptConditions::conditionGamemode),
ScoreboardCondition.CODEC.optionalFieldOf("scoreboard", ScoreboardCondition.NONE).forGetter(ScriptConditions::conditionScoreboard),
PositionCondition.CODEC.optionalFieldOf("position", PositionCondition.NONE).forGetter(ScriptConditions::conditionPosition),
EffectsCondition.CODEC.optionalFieldOf("effects", EffectsCondition.NONE).forGetter(ScriptConditions::conditionEffects)
).apply(instance, ScriptConditions::new)
);
}
public record ScriptRender(
Optional<ResourceKey<Block>> renderNameBlock,
Optional<ResourceKey<EntityType<?>>> renderNameEntity,
Optional<CompoundTag> renderNBT,
OptionalVec3 renderTranslation,
OptionalVec3 renderRotation,
OptionalVec3 renderscale,
OptionalVec3 renderRotationLeftArm,
OptionalVec3 renderRotationRightArm,
boolean renderLeftArm,
boolean renderRightArm
){
public static final ScriptRender EMPTY = new ScriptRender(Optional.empty(), Optional.empty(), Optional.empty(), OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, true, true);
public static final Codec<ScriptRender> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ResourceKey.codec(Registry.BLOCK_REGISTRY).optionalFieldOf("name_block").forGetter(ScriptRender::renderNameBlock),
ResourceKey.codec(Registry.ENTITY_TYPE_REGISTRY).optionalFieldOf("name_entity").forGetter(ScriptRender::renderNameEntity),
CompoundTag.CODEC.optionalFieldOf("nbt").forGetter(ScriptRender::renderNBT),
OptionalVec3.CODEC.optionalFieldOf("translation", OptionalVec3.NONE).forGetter(ScriptRender::renderTranslation),
OptionalVec3.CODEC.optionalFieldOf("rotation", OptionalVec3.NONE).forGetter(ScriptRender::renderRotation),
OptionalVec3.CODEC.optionalFieldOf("scale", OptionalVec3.NONE).forGetter(ScriptRender::renderscale),
OptionalVec3.CODEC.optionalFieldOf("rotation_left_arm", OptionalVec3.NONE).forGetter(ScriptRender::renderRotationLeftArm),
OptionalVec3.CODEC.optionalFieldOf("rotation_right_arm", OptionalVec3.NONE).forGetter(ScriptRender::renderRotationRightArm),
Codec.BOOL.optionalFieldOf("render_left_arm", true).forGetter(ScriptRender::renderLeftArm),
Codec.BOOL.optionalFieldOf("render_right_arm", true).forGetter(ScriptRender::renderRightArm)
).apply(instance, ScriptRender::new)
);
}
public record ScriptEffects(
String commandInit,
String commandLoop,
String commandPlace
){
public static final ScriptEffects EMPTY = new ScriptEffects("", "", "");
public static final Codec<ScriptEffects> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
Codec.STRING.optionalFieldOf("commandPickup", "").forGetter(ScriptEffects::commandInit),
Codec.STRING.optionalFieldOf("commandLoop", "").forGetter(ScriptEffects::commandLoop),
Codec.STRING.optionalFieldOf("commandPlace", "").forGetter(ScriptEffects::commandPlace)
).apply(instance, ScriptEffects::new)
);
}
}

View File

@ -0,0 +1,402 @@
package tschipp.carryon.common.scripting;
import com.mojang.serialization.Codec;
import net.minecraft.advancements.Advancement;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.ServerAdvancementManager;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Objective;
import net.minecraft.world.scores.Score;
import net.minecraft.world.scores.Scoreboard;
import tschipp.carryon.platform.Services;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public final class Matchables
{
public interface Matchable<T>
{
boolean matches(T elem);
}
private static float getValueFromString(String toGetFrom, String key, float defaultValue)
{
if (toGetFrom == null || toGetFrom.isEmpty())
return defaultValue;
String[] s = toGetFrom.split(",");
for (String string : s)
{
if (string.contains(key) && string.contains("="))
{
float numb = 0;
string = string.replace(key + "=", "");
try
{
numb = Float.parseFloat(string);
}
catch (Exception e)
{
}
return numb;
}
}
return defaultValue;
}
public record NumberBoundCondition(String bounds) implements Matchable<Number>
{
public static final Codec<NumberBoundCondition> CODEC = Codec.STRING.xmap(NumberBoundCondition::new, NumberBoundCondition::bounds);
public static final NumberBoundCondition NONE = new NumberBoundCondition("");
@Override
public boolean matches(Number num)
{
double number = num.doubleValue();
if (bounds == null || bounds.isEmpty())
return true;
try
{
if (bounds.contains("<="))
return number <= Double.parseDouble(bounds.replace("<=", ""));
if (bounds.contains(">="))
return number >= Double.parseDouble(bounds.replace(">=", ""));
if (bounds.contains("<"))
return number < Double.parseDouble(bounds.replace("<", ""));
if (bounds.contains(">"))
return number > Double.parseDouble(bounds.replace(">", ""));
if (bounds.contains("="))
return number == Double.parseDouble(bounds.replace("=", ""));
else
return number == Double.parseDouble(bounds);
}
catch (Exception e)
{
throw new RuntimeException("Error while parsing Number bound for string: "+ bounds + ". Error: " + e.getMessage());
}
}
}
public record MaterialCondition(String material) implements Matchable<Material>
{
public static final Codec<MaterialCondition> CODEC = Codec.STRING.xmap(MaterialCondition::new, MaterialCondition::material);
public static final MaterialCondition NONE = new MaterialCondition("");
@Override
public boolean matches(Material material)
{
if (this.material == null || this.material.isEmpty())
return true;
switch (this.material) {
case "air":
return material == Material.AIR;
case "anvil":
return material == Material.HEAVY_METAL;
case "barrier":
return material == Material.BARRIER;
case "cactus":
return material == Material.CACTUS;
case "cake":
return material == Material.CAKE;
case "carpet":
return material == Material.CLOTH_DECORATION;
case "clay":
return material == Material.CLAY;
case "cloth":
return material == Material.WOOL;
case "dragon_egg":
return material == Material.EGG;
case "fire":
return material == Material.FIRE;
case "glass":
return material == Material.GLASS;
case "gourd":
return material == Material.VEGETABLE;
case "grass":
return material == Material.GRASS;
case "ground":
return material == Material.GRASS;
case "ice":
return material == Material.ICE;
case "iron":
return material == Material.METAL;
case "lava":
return material == Material.LAVA;
case "leaves":
return material == Material.LEAVES;
case "packed_ice":
return material == Material.ICE_SOLID;
case "piston":
return material == Material.PISTON;
case "plants":
return material == Material.PLANT;
case "portal":
return material == Material.PORTAL;
case "redstone_light":
return material == Material.BUILDABLE_GLASS;
case "rock":
return material == Material.STONE;
case "sand":
return material == Material.SAND;
case "snow":
return material == Material.TOP_SNOW;
case "sponge":
return material == Material.SPONGE;
case "structure_void":
return material == Material.STRUCTURAL_AIR;
case "tnt":
return material == Material.EXPLOSIVE;
case "vine":
return material == Material.PLANT;
case "water":
return material == Material.WATER;
case "web":
return material == Material.WEB;
case "wood":
return material == Material.WOOD;
default:
return false;
}
}
}
public record AdvancementCondition(String advancement) implements Matchable<ServerPlayer>
{
public static final Codec<AdvancementCondition> CODEC = Codec.STRING.xmap(AdvancementCondition::new, AdvancementCondition::advancement);
public static final AdvancementCondition NONE = new AdvancementCondition("");
@Override
public boolean matches(ServerPlayer player)
{
ServerAdvancementManager manager = player.server.getAdvancements();
Advancement adv = manager.getAdvancement(new ResourceLocation(advancement.isEmpty() ? "" : advancement));
boolean achievement = adv == null ? true : player.getAdvancements().getOrStartProgress(adv).isDone();
return achievement;
}
}
public record GamestageCondition(String gamestage) implements Matchable<ServerPlayer>
{
public static final Codec<GamestageCondition> CODEC = Codec.STRING.xmap(GamestageCondition::new, GamestageCondition::gamestage);
public static final GamestageCondition NONE = new GamestageCondition("");
@Override
public boolean matches(ServerPlayer elem)
{
if(!Services.PLATFORM.isModLoaded("gamestages"))
return true;
//TODO: Gamestages
return true;
}
}
public record ScoreboardCondition(String cond) implements Matchable<ServerPlayer>
{
public static final Codec<ScoreboardCondition> CODEC = Codec.STRING.xmap(ScoreboardCondition::new, ScoreboardCondition::cond);
public static final ScoreboardCondition NONE = new ScoreboardCondition("");
@Override
public boolean matches(ServerPlayer player)
{
if (cond == null || cond.isEmpty())
return true;
Scoreboard score = player.getScoreboard();
String numb;
String scorename;
int iE = cond.indexOf("=");
int iG = cond.indexOf(">");
int iL = cond.indexOf("<");
if (iG == -1 ? true : iE < iG && iL == -1 ? true : iE < iL && iE != -1)
numb = cond.substring(iE);
else if (iE == -1 ? true : iG < iE && iL == -1 ? true : iG < iL && iG != -1)
numb = cond.substring(iG);
else
numb = cond.substring(iL);
scorename = cond.replace(numb, "");
Map<Objective, Score> o = score.getPlayerScores(player.getGameProfile().getName());
if (o != null)
{
Score sc = o.get(score.getObjective(scorename));
if (sc != null)
{
int points = sc.getScore();
return new NumberBoundCondition(numb).matches(points);
}
}
return false;
}
}
public record PositionCondition(String cond) implements Matchable<ServerPlayer>
{
public static final Codec<PositionCondition> CODEC = Codec.STRING.xmap(PositionCondition::new, PositionCondition::cond);
public static final PositionCondition NONE = new PositionCondition("");
@Override
public boolean matches(ServerPlayer elem)
{
if (cond == null || cond.isEmpty())
return true;
BlockPos blockpos = new BlockPos(getValueFromString(cond, "x", 0), getValueFromString(cond, "y", 0), getValueFromString(cond, "z", 0));
BlockPos expand = new BlockPos(getValueFromString(cond, "dx", 0), getValueFromString(cond, "dy", 0), getValueFromString(cond, "dz", 0));
BlockPos expanded = blockpos.offset(expand);
BlockPos pos = elem.blockPosition();
boolean x = pos.getX() >= blockpos.getX() && pos.getX() <= expanded.getX() || blockpos.getX() == 0;
boolean y = pos.getY() >= blockpos.getY() && pos.getY() <= expanded.getY() || blockpos.getY() == 0;
boolean z = pos.getZ() >= blockpos.getZ() && pos.getZ() <= expanded.getZ() || blockpos.getZ() == 0;
return x && y && z;
}
}
public record EffectsCondition(String effects) implements Matchable<ServerPlayer>
{
public static final Codec<EffectsCondition> CODEC = Codec.STRING.xmap(EffectsCondition::new, EffectsCondition::effects);
public static final EffectsCondition NONE = new EffectsCondition("");
@Override
public boolean matches(ServerPlayer player)
{
if (effects == null || effects.isEmpty())
return true;
Collection<MobEffectInstance> fx = player.getActiveEffects();
String[] potions = effects.split(",");
List<String> names = new ArrayList<>();
List<Integer> levels = new ArrayList<>();
for (String pot : potions)
{
if (pot.contains("#"))
{
String level = pot.substring(pot.indexOf("#"));
String name = pot.substring(0, pot.indexOf("#"));
level = level.replace("#", "");
int lev = 0;
try
{
lev = Integer.parseInt(level);
}
catch (Exception e)
{
}
levels.add(lev);
names.add(name);
}
else
{
levels.add(0);
names.add(pot);
}
}
int matches = 0;
for (MobEffectInstance effect : fx)
{
int amp = effect.getAmplifier();
String name = Registry.MOB_EFFECT.getKey(effect.getEffect()).toString();
if (names.contains(name))
{
int idx = names.indexOf(name);
int lev = levels.get(idx);
if (lev == amp)
matches++;
}
}
return matches == potions.length;
}
}
public record NBTCondition(CompoundTag tag) implements Matchable<CompoundTag>
{
public static final Codec<NBTCondition> CODEC = CompoundTag.CODEC.xmap(NBTCondition::new, NBTCondition::tag);
public static final NBTCondition NONE = new NBTCondition(new CompoundTag());
@Override
public boolean matches(CompoundTag other)
{
if(other == null)
return true;
return NbtUtils.compareNbt(tag, other, true);
}
}
public static class OptionalVec3 {
public static final Codec<OptionalVec3> CODEC = Codec.STRING.xmap(OptionalVec3::new, OptionalVec3::source);
public static final OptionalVec3 NONE = new OptionalVec3("");
String source;
Vec3 vec;
public OptionalVec3(String source)
{
this.source = source;
double x = getValueFromString(source, "x", 0);
double y = getValueFromString(source, "y", 0);
double z = getValueFromString(source, "z", 0);
vec = new Vec3(x, y, z);
}
private String source()
{
return source;
}
public Vec3 getVec()
{
return vec;
}
public Vec3 getVec(double defaultValue)
{
double x = vec.x == 0f ? defaultValue : vec.x;
double y = vec.y == 0f ? defaultValue : vec.y;
double z = vec.z == 0f ? defaultValue : vec.z;
return new Vec3(x, y, z);
}
}
}

View File

@ -0,0 +1,93 @@
package tschipp.carryon.common.scripting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectBlock;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectEntity;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ScriptManager
{
public static final List<CarryOnScript> SCRIPTS = new ArrayList<>();
public static Optional<CarryOnScript> inspectBlock(BlockState state, Level level, BlockPos pos, @Nullable CompoundTag tag)
{
if (!Constants.COMMON_CONFIG.settings.useScripts)
return Optional.empty();
Block block = state.getBlock();
Material material = state.getMaterial();
float hardness = state.getDestroySpeed(level, pos);
float resistance = block.getExplosionResistance();
for (CarryOnScript script : SCRIPTS)
{
if (script.isBlock() && matchesAll(script, block, material, hardness, resistance, tag))
return Optional.of(script);
}
return Optional.empty();
}
public static Optional<CarryOnScript> inspectEntity(Entity entity)
{
if (!Constants.COMMON_CONFIG.settings.useScripts)
return Optional.empty();
float height = entity.getBbHeight();
float width = entity.getBbWidth();
float health = entity instanceof LivingEntity ? ((LivingEntity) entity).getHealth() : 0.0f;
CompoundTag tag = new CompoundTag();
entity.save(tag);
for (CarryOnScript script : SCRIPTS)
{
if (script.isEntity() && matchesAll(script, entity, height, width, health, tag))
return Optional.of(script);
}
return Optional.empty();
}
private static boolean matchesAll(CarryOnScript script, Entity entity, float height, float width, float health, CompoundTag tag)
{
ScriptObjectEntity scEntity = script.scriptObject().entity();
boolean matchname = true;
if(scEntity.typeNameEntity().isPresent())
matchname = entity.getType().equals(Registry.ENTITY_TYPE.get(scEntity.typeNameEntity().get()));
boolean matchheight = scEntity.typeHeight().matches(height);
boolean matchwidth = scEntity.typeWidth().matches(width);
boolean matchhealth = scEntity.typeHealth().matches(health);
boolean matchnbt = scEntity.typeEntityTag().matches(tag);
return matchname && matchheight && matchwidth && matchhealth && matchnbt;
}
private static boolean matchesAll(CarryOnScript script, Block block, Material material, float hardness, float resistance, CompoundTag nbt)
{
ScriptObjectBlock scBlock = script.scriptObject().block();
boolean matchblock = true;
if(scBlock.typeNameBlock().isPresent())
matchblock = block == Registry.BLOCK.get(scBlock.typeNameBlock().get());
boolean matchnbt = scBlock.typeBlockTag().matches(nbt);
boolean matchmaterial = scBlock.typeMaterial().matches(material);
boolean matchhardness = scBlock.typeHardness().matches(hardness);
boolean matchresistance = scBlock.typeResistance().matches(resistance);
return matchnbt && matchblock && matchmaterial && matchhardness && matchresistance;
}
}

View File

@ -0,0 +1,65 @@
package tschipp.carryon.common.scripting;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
import net.minecraft.util.profiling.ProfilerFiller;
import tschipp.carryon.Constants;
import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket;
import tschipp.carryon.platform.Services;
import java.util.Collections;
import java.util.Map;
public class ScriptReloadListener extends SimpleJsonResourceReloadListener
{
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
public ScriptReloadListener()
{
super(GSON, "carryon/scripts");
}
@Override
protected void apply(Map<ResourceLocation, JsonElement> objects, ResourceManager manager, ProfilerFiller profiler)
{
ScriptManager.SCRIPTS.clear();
try {
objects.forEach((path, jsonElem) -> {
DataResult<CarryOnScript> res = CarryOnScript.CODEC.parse(JsonOps.INSTANCE, jsonElem);
CarryOnScript script = res.getOrThrow(false, (s) -> {throw new RuntimeException(s);});
if (script.isValid())
ScriptManager.SCRIPTS.add(script);
});
}
catch (Exception e)
{
e.printStackTrace();
}
Collections.sort(ScriptManager.SCRIPTS, (s1, s2) -> Long.compare(s2.priority(), s1.priority()));
}
public static void syncScriptsWithClient(ServerPlayer player)
{
if (player != null)
{
DataResult<Tag> result = Codec.list(CarryOnScript.CODEC).encodeStart(NbtOps.INSTANCE, ScriptManager.SCRIPTS);
Tag tag = result.getOrThrow(false, s -> {throw new RuntimeException("Error while synching Carry On Scripts: " + s);});
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_SYNC_SCRIPTS, new ClientboundSyncScriptsPacket(tag), player);
}
}
}

View File

@ -0,0 +1,87 @@
package tschipp.carryon.mixin;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Entity.MoveFunction;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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 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.networking.clientbound.ClientboundStartRidingPacket;
import tschipp.carryon.platform.Services;
@Mixin(Entity.class)
public abstract class EntityMixin
{
@Shadow
public boolean hasPassenger(Entity pEntity) {throw new IllegalStateException("EntityMixin application failed");}
@Shadow public abstract void onPassengerTurned(Entity $$0);
@Inject(method = "positionRider(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/entity/Entity$MoveFunction;)V", at = @At("HEAD"), cancellable = true)
private void onPositionPassenger(Entity entity, MoveFunction move, CallbackInfo ci)
{
if((Object)this instanceof Player thisPlayer && entity instanceof Player otherPlayer)
{
if(hasPassenger(otherPlayer) && CarryOnDataManager.getCarryData(thisPlayer).isCarrying(CarryType.PLAYER))
{
Vec3 forward = new Vec3(0, 0, 0.6);
Vec3 otherPos = thisPlayer.position().add(forward.yRot((float) Math.toRadians(-thisPlayer.yBodyRot)));
otherPos = otherPos.add(0, 0.4,0);
move.accept(otherPlayer, otherPos.x, otherPos.y, otherPos.z);
((Entity)((Object)this)).onPassengerTurned(otherPlayer);
ci.cancel();
}
}
}
@Inject(method = "getDismountLocationForPassenger(Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/phys/Vec3;", at = @At("HEAD"))
private void onDismountPassenger(LivingEntity living, CallbackInfoReturnable<Vec3> cir)
{
if((Object)this instanceof Player thisPlayer && living instanceof Player otherPlayer)
{
CarryOnData carry = CarryOnDataManager.getCarryData(thisPlayer);
if(carry.isCarrying(CarryType.PLAYER))
{
carry.clear();
CarryOnDataManager.setCarryData(thisPlayer, carry);
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_START_RIDING, new ClientboundStartRidingPacket(otherPlayer.getId(), false), (ServerPlayer) thisPlayer);
}
}
}
@Inject(method = "onPassengerTurned(Lnet/minecraft/world/entity/Entity;)V", at = @At("HEAD"))
private void onPassengerTurned(Entity toUpdate, CallbackInfo ci)
{
if((Object)this instanceof Player thisPlayer && toUpdate instanceof Player otherPlayer)
{
CarryOnData carry = CarryOnDataManager.getCarryData(thisPlayer);
if(carry.isCarrying(CarryType.PLAYER)) {
this.clampRotation(toUpdate);
}
}
}
@Unique
private void clampRotation(Entity pEntityToUpdate) {
Entity thisEntity = (Entity)((Object)this);
pEntityToUpdate.setYBodyRot(thisEntity.getYRot());
float f = Mth.wrapDegrees(pEntityToUpdate.getYRot() - thisEntity.getYRot());
float f1 = Mth.clamp(f, -30.0F, 30.0F);
pEntityToUpdate.yRotO += f1 - f;
pEntityToUpdate.setYRot(pEntityToUpdate.getYRot() + f1 - f);
pEntityToUpdate.setYHeadRot(pEntityToUpdate.getYRot());
}
}

View File

@ -4,13 +4,17 @@ import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.Vec3;
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.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 tschipp.carryon.client.render.CarryRenderHelper;
import tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
@Mixin(HumanoidModel.class) @Mixin(HumanoidModel.class)
public class HumanoidModelMixin { public class HumanoidModelMixin {
@ -24,32 +28,50 @@ public class HumanoidModelMixin {
@Inject(at = @At("RETURN"), method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V") @Inject(at = @At("RETURN"), method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V")
private void onSetupAnimations(LivingEntity living, float f1, float f2, float f3, float f4, float f5, CallbackInfo ci) private void onSetupAnimations(LivingEntity living, float f1, float f2, float f3, float f4, float f5, CallbackInfo ci)
{ {
System.out.println("Reached model injectiob");
if(living instanceof Player player) if(living instanceof Player player)
{ {
System.out.println("Model is player");
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying() && !player.isVisuallySwimming() && !player.isFallFlying()) if(carry.isCarrying() && !player.isVisuallySwimming() && !player.isFallFlying())
{ {
System.out.println("Player is carrying");
boolean sneaking = !player.getAbilities().flying && player.isShiftKeyDown() || player.isCrouching(); boolean sneaking = !player.getAbilities().flying && player.isShiftKeyDown() || player.isCrouching();
float x = 1.0f + (sneaking ? 0.2f : 0.0f) - (carry.isCarrying(CarryOnData.CarryType.BLOCK) ? 0.0f : 0.3f); float x = 1.0f + (sneaking ? 0.2f : 0.0f) + (carry.isCarrying(CarryOnData.CarryType.BLOCK) ? 0.0f : 0.3f);
float z = 0.15f; float z = 0.05f;
rightArm.yRot = 0; float width = CarryRenderHelper.getRenderWidth(player);
leftArm.yRot = 0; float offset = Math.min((width - 1) / 1.5f, 0.2f);
rightArm.xRot = -x; if(carry.getActiveScript().isPresent())
leftArm.xRot = -x; {
ScriptRender render = carry.getActiveScript().get().scriptRender();
boolean renderLeft = render.renderLeftArm();
boolean renderRight = render.renderRightArm();
Vec3 rotLeft = render.renderRotationLeftArm().getVec();
Vec3 rotRight = render.renderRotationRightArm().getVec();
if(renderLeft)
changeRotation(leftArm, (float) rotLeft.x, (float) rotLeft.y, (float) rotLeft.z);
if(renderRight)
changeRotation(rightArm, (float) rotRight.x, (float) rotRight.y, (float) rotRight.z);
}
else {
changeRotation(rightArm, -x, offset, -z);
changeRotation(leftArm, -x, -offset, z);
}
rightArm.zRot = z;
leftArm.zRot = -z;
} }
} }
} }
@Unique
private void changeRotation(ModelPart part, float x, float y, float z)
{
part.xRot = x;
part.yRot = y;
part.zRot = z;
}
} }

View File

@ -1,11 +1,15 @@
package tschipp.carryon.mixin; package tschipp.carryon.mixin;
import net.minecraft.core.NonNullList;
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.level.block.Blocks;
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.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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
@ -15,16 +19,26 @@ public class InventoryMixin
@Shadow @Shadow
public Player player; public Player player;
// @Redirect(method = "selected:I", at = @At()) @Shadow
// private void setSelected(Inventory inv, int value) public int selected;
// {
// @Shadow
// } public NonNullList<ItemStack> items;
@Redirect(method = "getFreeSlot()I", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/core/NonNullList;get(I)Ljava/lang/Object;"))
private <E> E getFreeSlotEmptyCheck(NonNullList<E> instance, int i)
{
if(i == selected && CarryOnDataManager.getCarryData(player).isCarrying())
{
return (E) new ItemStack(Blocks.STONE, 1);
}
else
return instance.get(i);
}
@Inject(method = "setPickedItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true) @Inject(method = "setPickedItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true)
private void onPickBlock(CallbackInfo info) private void onPickBlock(CallbackInfo info)
{ {
System.out.println("onPickBlock");
if(CarryOnDataManager.getCarryData(player).isCarrying()) if(CarryOnDataManager.getCarryData(player).isCarrying())
info.cancel(); info.cancel();
} }
@ -32,7 +46,6 @@ public class InventoryMixin
@Inject(method = "pickSlot(I)V", at = @At("HEAD"), cancellable = true) @Inject(method = "pickSlot(I)V", at = @At("HEAD"), cancellable = true)
private void onPickSlot(int slot, CallbackInfo info) private void onPickSlot(int slot, CallbackInfo info)
{ {
System.out.println("onPickSlot");
if(CarryOnDataManager.getCarryData(player).isCarrying()) if(CarryOnDataManager.getCarryData(player).isCarrying())
info.cancel(); info.cancel();
} }
@ -40,9 +53,6 @@ public class InventoryMixin
@Inject(method = "swapPaint(D)V", at = @At("HEAD"), cancellable = true) @Inject(method = "swapPaint(D)V", at = @At("HEAD"), cancellable = true)
private void onSwapPaint(double direction, CallbackInfo info) 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()) if(CarryOnDataManager.getCarryData(player).isCarrying())
info.cancel(); info.cancel();
} }

View File

@ -36,10 +36,9 @@ public abstract class PlayerMixin extends LivingEntity {
@Inject(method = "readAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("RETURN")) @Inject(method = "readAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("RETURN"))
private void onReadAdditionalSaveData(CompoundTag tag, CallbackInfo info) private void onReadAdditionalSaveData(CompoundTag tag, CallbackInfo info)
{ {
if(tag.contains("CarryOnData")) if (tag.contains("CarryOnData")) {
{
CarryOnData data = new CarryOnData(tag.getCompound("CarryOnData")); CarryOnData data = new CarryOnData(tag.getCompound("CarryOnData"));
CarryOnDataManager.setCarryData((Player)(Object)this, data); CarryOnDataManager.setCarryData((Player) (Object) this, data);
} }
} }

View File

@ -0,0 +1,11 @@
package tschipp.carryon.networking;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
public abstract class PacketBase
{
public abstract void toBytes(FriendlyByteBuf buf);
public abstract void handle(Player player);
}

View File

@ -0,0 +1,42 @@
package tschipp.carryon.networking.clientbound;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.networking.PacketBase;
public class ClientboundStartRidingPacket extends PacketBase
{
int entityId;
boolean ride;
public ClientboundStartRidingPacket(FriendlyByteBuf buf)
{
this.entityId = buf.readInt();
this.ride = buf.readBoolean();
}
public ClientboundStartRidingPacket(int id, boolean ride)
{
this.entityId = id;
this.ride = ride;
}
@Override
public void toBytes(FriendlyByteBuf buf)
{
buf.writeInt(entityId);
buf.writeBoolean(ride);
}
@Override
public void handle(Player player)
{
Entity otherPlayer = player.level.getEntity(this.entityId);
if(otherPlayer != null)
if(ride)
otherPlayer.startRiding(player);
else
otherPlayer.stopRiding();
}
}

View File

@ -0,0 +1,46 @@
package tschipp.carryon.networking.clientbound;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.ScriptManager;
import tschipp.carryon.networking.PacketBase;
import java.util.List;
public class ClientboundSyncScriptsPacket extends PacketBase
{
private Tag serialized;
public ClientboundSyncScriptsPacket(FriendlyByteBuf buf)
{
this.serialized = buf.readNbt().get("data");
}
public ClientboundSyncScriptsPacket(Tag serialized)
{
this.serialized = serialized;
}
@Override
public void toBytes(FriendlyByteBuf buf)
{
CompoundTag tag = new CompoundTag();
tag.put("data", serialized);
buf.writeNbt(tag);
}
@Override
public void handle(Player player)
{
DataResult<List<CarryOnScript>> res = Codec.list(CarryOnScript.CODEC).parse(NbtOps.INSTANCE, serialized);
List<CarryOnScript> scripts = res.getOrThrow(false, (s) -> {throw new RuntimeException("Failed deserializing carry on scripts on the client: " + s);});
ScriptManager.SCRIPTS.clear();
ScriptManager.SCRIPTS.addAll(scripts);
}
}

View File

@ -0,0 +1,37 @@
package tschipp.carryon.networking.serverbound;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.networking.PacketBase;
public class ServerboundCarryKeyPressedPacket extends PacketBase
{
boolean pressed;
public ServerboundCarryKeyPressedPacket(FriendlyByteBuf buf)
{
this.pressed = buf.readBoolean();
}
public ServerboundCarryKeyPressedPacket(boolean pressed)
{
this.pressed = pressed;
}
@Override
public void toBytes(FriendlyByteBuf buf)
{
buf.writeBoolean(pressed);
}
@Override
public void handle(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
carry.setKeyPressed(this.pressed);
CarryOnDataManager.setCarryData(player, carry);
}
}

View File

@ -1,6 +1,14 @@
package tschipp.carryon.platform.services; package tschipp.carryon.platform.services;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.config.BuiltConfig; import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.networking.PacketBase;
import java.util.function.BiConsumer;
import java.util.function.Function;
public interface IPlatformHelper { public interface IPlatformHelper {
@ -27,4 +35,13 @@ public interface IPlatformHelper {
boolean isDevelopmentEnvironment(); boolean isDevelopmentEnvironment();
void registerConfig(BuiltConfig cfg); void registerConfig(BuiltConfig cfg);
<T extends PacketBase> void registerServerboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler);
<T extends PacketBase> void registerClientboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler);
void sendPacketToServer(ResourceLocation id, PacketBase packet);
void sendPacketToPlayer(ResourceLocation id, PacketBase packet, ServerPlayer player);
} }

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "sᵷuᴉʇʇǝS",
"carryon.category.blacklist": "ʇsᴉꞁʞɔɐꞁᗺ",
"carryon.category.modeloverrides": "(pǝɔuɐʌpⱯ) sǝpᴉɹɹǝʌO ꞁǝpoW",
"carryon.category.custompickupconditions": "(pǝɔuɐʌpⱯ) suoᴉʇᴉpuoƆ dnʞɔᴉԀ ɯoʇsnƆ",
"carryon.category.whitelist": "ʇsᴉꞁǝʇᴉɥM",
"carryon.general.modeloverrides.modeloverrides": "sǝpᴉɹɹǝʌO ꞁǝpoW",
"carryon.general.blacklist.forbiddenentities": "dn ʞɔᴉd ʇouuɐɔ ɹǝʎɐꞁԀ ǝɥʇ ʇɐɥʇ sǝᴉʇᴉʇuƎ",
"carryon.general.blacklist.forbiddentiles": "dn ʞɔᴉd ʇouuɐɔ ɹǝʎɐꞁԀ ǝɥʇ ʇɐɥʇ sʞɔoꞁᗺ",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "suoᴉʇᴉpuoƆ dnʞɔᴉԀ ʞɔoꞁᗺ ɯoʇsnƆ",
"carryon.category.custompickupconditions.custompickupconditionsentities": "suoᴉʇᴉpuoƆ dnʞɔᴉԀ ʎʇᴉʇuƎ ɯoʇsnƆ",
"key.carry.desc": "ʎɹɹɐƆ",
"key.carry.category": "uO ʎɹɹɐƆ"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Settings",
"carryon.category.blacklist": "Blacklist",
"carryon.category.modeloverrides": "Model Overrides (Advanced)",
"carryon.category.custompickupconditions": "Custom Pickup Conditions (Advanced)",
"carryon.category.whitelist": "Whitelist",
"carryon.general.modeloverrides.modeloverrides": "Model Overrides",
"carryon.general.blacklist.forbiddenentities": "Entities that the Player cannot pick up",
"carryon.general.blacklist.forbiddentiles": "Blocks that the Player cannot pick up",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Custom Block Pickup Conditions",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Custom Entity Pickup Conditions",
"key.carry.desc": "Carry",
"key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Configuración",
"carryon.category.blacklist": "Lista negra",
"carryon.category.modeloverrides": "Reescribir modelo (Avanzado)",
"carryon.category.custompickupconditions": "Customizar condiciones de recoger (Avanzado)",
"carryon.category.whitelist": "Lista blanca",
"carryon.general.modeloverrides.modeloverrides": "Reescribir modelo",
"carryon.general.blacklist.forbiddenentities": "Entidades que el jugador no puede recoger",
"carryon.general.blacklist.forbiddentiles": "Bloques que el jugador no puede recoger",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Customizar condiciones para recoger bloques",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Customizar condiciones para recoger entidades",
"key.carry.desc": "Agarrar",
"key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Inpostazioni",
"carryon.category.blacklist": "Blacklist",
"carryon.category.modeloverrides": "Sostituzioni modello (avanzate)",
"carryon.category.custompickupconditions": "Condizioni di prelievo personalizzate (avanzate)",
"carryon.category.whitelist": "Whitelist",
"carryon.general.modeloverrides.modeloverrides": "Sostituzioni modello",
"carryon.general.blacklist.forbiddenentities": "Entità che il giocatore non può raccogliere",
"carryon.general.blacklist.forbiddentiles": "Blocchi che il giocatore non può raccogliere",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Condizioni di prelievo blocco personalizzate",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Condizioni di prelievo entità personalizzate",
"key.carry.desc": "Afferra",
"key.carry.category": "Carry On Mod"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "설정",
"carryon.category.blacklist": "블랙리스트",
"carryon.category.modeloverrides": "모델 오버라이딩 (고급)",
"carryon.category.custompickupconditions": "커스텀 들기 컨디션 (고급)",
"carryon.category.whitelist": "화이트리스트",
"carryon.general.modeloverrides.modeloverrides": "모델 오버라이딩",
"carryon.general.blacklist.forbiddenentities": "플레이어가 들 수 없는 엔티티",
"carryon.general.blacklist.forbiddentiles": "플레이어가 들 수 없는 블록",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "커스텀 블록 들기 컨디션",
"carryon.category.custompickupconditions.custompickupconditionsentities": "커스텀 엔티티 들기 컨디션",
"key.carry.desc": "들고 나르기",
"key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Настройки",
"carryon.category.blacklist": "Чёрный список",
"carryon.category.modeloverrides": "Переопределения модели (Улучшенное)",
"carryon.category.custompickupconditions": "Индивидуальные условия поднятия (Улучшенное)",
"carryon.category.whitelist": "Белый список",
"carryon.general.modeloverrides.modeloverrides": "Переопределения модели",
"carryon.general.blacklist.forbiddenentities": "Сущности, которых игрок не может поднять",
"carryon.general.blacklist.forbiddentiles": "Блоки, которые игрок не может поднять",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Пользовательские условия поднятия блока",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Пользовательские условия поднятия сущности",
"key.carry.desc": "Поднять",
"key.carry.category": "Carry On"
}

View File

@ -4,12 +4,13 @@
"package": "tschipp.carryon.mixin", "package": "tschipp.carryon.mixin",
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_17",
"mixins": [ "mixins": [
"EntityMixin",
"InventoryMixin", "InventoryMixin",
"PlayerMixin" "PlayerMixin"
], ],
"client": [ "client": [
"MinecraftMixin", "HumanoidModelMixin",
"HumanoidModelMixin" "MinecraftMixin"
], ],
"server": [ "server": [
], ],

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -4,7 +4,7 @@ plugins {
id 'idea' id 'idea'
} }
archivesBaseName = "${mod_name}-fabric-${minecraft_version}" archivesBaseName = "${mod_id}-fabric-${minecraft_version}"
dependencies { dependencies {
minecraft "com.mojang:minecraft:${minecraft_version}" minecraft "com.mojang:minecraft:${minecraft_version}"

View File

@ -0,0 +1,43 @@
package tschipp.carryon;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.client.keybinds.CarryOnKeybinds;
import tschipp.carryon.events.ClientEvents;
import tschipp.carryon.networking.PacketBase;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class CarryOnFabricClientMod implements ClientModInitializer
{
@Override
public void onInitializeClient()
{
CarryOnKeybinds.registerKeybinds(KeyBindingHelper::registerKeyBinding);
ClientEvents.registerEvents();
CarryOnCommon.registerClientPackets();
}
public static void sendPacketToServer(ResourceLocation id, PacketBase packet)
{
FriendlyByteBuf buf = PacketByteBufs.create();
packet.toBytes(buf);
ClientPlayNetworking.send(id, buf);
}
public static <T extends PacketBase> void registerClientboundPacket(ResourceLocation id, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler)
{
ClientPlayNetworking.registerGlobalReceiver(id, (client, packetHandler, buf, responseSender) -> {
T packet = reader.apply(buf);
client.execute(() -> {
handler.accept(packet, client.player);
});
});
}
}

View File

@ -14,9 +14,9 @@ public class CarryOnFabricMod implements ModInitializer {
// This method is invoked by the Fabric mod loader when it is ready // This method is invoked by the Fabric mod loader when it is ready
// to load your mod. You can access Fabric and Common code in this // to load your mod. You can access Fabric and Common code in this
// project. // project.
CarryOnCommon.registerConfig();
// Use Fabric to bootstrap the Common mod.
Constants.LOG.info("Hello Fabric world!");
try { try {
ConfigLoaderImpl.initialize(); ConfigLoaderImpl.initialize();
} catch (IOException e) { } catch (IOException e) {
@ -24,7 +24,7 @@ public class CarryOnFabricMod implements ModInitializer {
} }
CommonEvents.registerEvents(); CommonEvents.registerEvents();
CarryOnCommon.registerServerPackets();
} }
} }

View File

@ -1,4 +1,15 @@
package tschipp.carryon.events; package tschipp.carryon.events;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import tschipp.carryon.CarryOnCommonClient;
public class ClientEvents { public class ClientEvents {
public static void registerEvents()
{
ClientTickEvents.END_CLIENT_TICK.register(mc -> {
CarryOnCommonClient.checkForKeybinds();
});
}
} }

View File

@ -1,15 +1,24 @@
package tschipp.carryon.events; package tschipp.carryon.events;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.fabricmc.fabric.api.event.player.UseEntityCallback; import net.fabricmc.fabric.api.event.player.UseEntityCallback;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.packs.PackType;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import tschipp.carryon.CarryOnCommon;
import tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.carry.PickupHandler; 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.scripting.IdentifiableScriptReloadListener;
public class CommonEvents { public class CommonEvents {
@ -62,14 +71,32 @@ public class CommonEvents {
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }
} }
else if(carry.isCarrying(CarryOnData.CarryType.ENTITY)) else if(carry.isCarrying(CarryOnData.CarryType.ENTITY) || carry.isCarrying(CarryType.PLAYER))
{ {
//TODO: Stacking PlacementHandler.tryStackEntity((ServerPlayer) player, entity);
} }
return InteractionResult.PASS; return InteractionResult.PASS;
}); });
CommandRegistrationCallback.EVENT.register(((dispatcher, registryAccess, environment) -> {
CarryOnCommon.registerCommands(dispatcher);
}));
ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(new IdentifiableScriptReloadListener());
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.register((player, joined) -> {
ScriptReloadListener.syncScriptsWithClient(player);
});
ServerTickEvents.END_SERVER_TICK.register(server -> {
for(ServerPlayer player : server.getPlayerList().getPlayers())
PickupHandler.onCarryTick(player);
});
} }
} }

View File

@ -1,21 +0,0 @@
package tschipp.carryon.mixin;
import tschipp.carryon.Constants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
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;
@Mixin(TitleScreen.class)
public class ExampleMixin {
@Inject(at = @At("HEAD"), method = "init()V")
private void init(CallbackInfo info) {
Constants.LOG.info("This line is printed by an example mod mixin from Fabric!");
Constants.LOG.info("MC Version: {}", Minecraft.getInstance().getVersionType());
Constants.LOG.info("Classloader: {}", this.getClass().getClassLoader());
}
}

View File

@ -0,0 +1,31 @@
package tschipp.carryon.mixin;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
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.Redirect;
import tschipp.carryon.client.render.CarriedObjectRender;
import tschipp.carryon.client.render.CarryRenderHelper;
@Mixin(ItemInHandRenderer.class)
public class ItemInHandRendererMixin
{
@Shadow
private void renderArmWithItem(AbstractClientPlayer player, float partialTicks, float f2, InteractionHand hand, float f3, ItemStack stack, float f4, PoseStack poseStack, MultiBufferSource source, int light) {throw new RuntimeException("CarryOn InHandRendererMixin failed");}
@Redirect(at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;renderArmWithItem(Lnet/minecraft/client/player/AbstractClientPlayer;FFLnet/minecraft/world/InteractionHand;FLnet/minecraft/world/item/ItemStack;FLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V"), method = "renderHandsWithItems(FLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;Lnet/minecraft/client/player/LocalPlayer;I)V")
private void onRenderHand(ItemInHandRenderer instance, AbstractClientPlayer player, float partialTicks, float f2, InteractionHand hand, float f3, ItemStack stack, float f4, PoseStack poseStack, MultiBufferSource source, int light)
{
if(!CarriedObjectRender.drawFirstPerson(player, source, poseStack, light, partialTicks) && CarryRenderHelper.getPerspective() == 0)
renderArmWithItem(player, partialTicks, f2, hand, f3, stack, f4, poseStack, source, light);
}
}

View File

@ -0,0 +1,23 @@
package tschipp.carryon.mixin;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
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.client.render.CarriedObjectRender;
@Mixin(LevelRenderer.class)
public class LevelRendererMixin
{
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleEngine;render(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;Lnet/minecraft/client/renderer/LightTexture;Lnet/minecraft/client/Camera;F)V"), method = "renderLevel(Lcom/mojang/blaze3d/vertex/PoseStack;FJZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lnet/minecraft/client/renderer/LightTexture;Lcom/mojang/math/Matrix4f;)V")
private void onRenderLevel(PoseStack poseStack, float f, long l, boolean bl, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci)
{
CarriedObjectRender.drawThirdPerson(gameRenderer.getMinecraft().getFrameTime(), poseStack);
}
}

View File

@ -0,0 +1,28 @@
package tschipp.carryon.mixin;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.world.entity.player.Player;
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(Screen.class)
public class ScreenMixin
{
@Inject(at = @At(value = "TAIL"), method = "init(Lnet/minecraft/client/Minecraft;II)V")
private void onInit(Minecraft mc, int i, int j, CallbackInfo ci)
{
Player player = mc.player;
if((Object)this instanceof AbstractContainerScreen && player != null)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
mc.setScreen((Screen)null);
}
}
}

View File

@ -1,9 +1,20 @@
package tschipp.carryon.platform; package tschipp.carryon.platform;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.CarryOnFabricClientMod;
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.platform.services.IPlatformHelper; import tschipp.carryon.platform.services.IPlatformHelper;
import net.fabricmc.loader.api.FabricLoader;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class FabricPlatformHelper implements IPlatformHelper { public class FabricPlatformHelper implements IPlatformHelper {
@ -28,4 +39,35 @@ public class FabricPlatformHelper implements IPlatformHelper {
public void registerConfig(BuiltConfig cfg) { public void registerConfig(BuiltConfig cfg) {
ConfigLoaderImpl.registerConfig(cfg); ConfigLoaderImpl.registerConfig(cfg);
} }
@Override
public <T extends PacketBase> void registerServerboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler)
{
ServerPlayNetworking.registerGlobalReceiver(id, (server, player, packetHandler, buf, responseSender) -> {
T packet = reader.apply(buf);
server.execute(() -> {
handler.accept(packet, player);
});
});
}
@Override
public <T extends PacketBase> void registerClientboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler)
{
CarryOnFabricClientMod.registerClientboundPacket(id, reader, handler);
}
@Override
public void sendPacketToServer(ResourceLocation id, PacketBase packet)
{
CarryOnFabricClientMod.sendPacketToServer(id, packet);
}
@Override
public void sendPacketToPlayer(ResourceLocation id, PacketBase packet, ServerPlayer player)
{
FriendlyByteBuf buf = PacketByteBufs.create();
packet.toBytes(buf);
ServerPlayNetworking.send(player, id, buf);
}
} }

View File

@ -0,0 +1,15 @@
package tschipp.carryon.scripting;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.resources.ResourceLocation;
import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.ScriptReloadListener;
public class IdentifiableScriptReloadListener extends ScriptReloadListener implements IdentifiableResourceReloadListener
{
@Override
public ResourceLocation getFabricId()
{
return new ResourceLocation(Constants.MOD_ID, "carryon_scripts");
}
}

View File

@ -6,6 +6,9 @@
"mixins": [ "mixins": [
], ],
"client": [ "client": [
"ItemInHandRendererMixin",
"LevelRendererMixin",
"ScreenMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

@ -20,6 +20,9 @@
"entrypoints": { "entrypoints": {
"main": [ "main": [
"tschipp.carryon.CarryOnFabricMod" "tschipp.carryon.CarryOnFabricMod"
],
"client": [
"tschipp.carryon.CarryOnFabricClientMod"
] ]
}, },
"mixins": [ "mixins": [

View File

@ -2,11 +2,13 @@ buildscript {
repositories { repositories {
maven { url = 'https://maven.minecraftforge.net' } maven { url = 'https://maven.minecraftforge.net' }
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } maven { url = 'https://repo.spongepowered.org/repository/maven-public/' }
maven { url = 'https://maven.parchmentmc.org' }
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT'
classpath 'org.parchmentmc:librarian:1.+'
} }
} }
apply plugin: 'java' apply plugin: 'java'
@ -14,8 +16,9 @@ apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse' apply plugin: 'eclipse'
apply plugin: 'org.spongepowered.mixin' apply plugin: 'org.spongepowered.mixin'
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
apply plugin: 'org.parchmentmc.librarian.forgegradle'
archivesBaseName = "${mod_name}-forge-${minecraft_version}" archivesBaseName = "${mod_id}-forge-${minecraft_version}"
mixin { mixin {
add sourceSets.main, "${mod_id}.refmap.json" add sourceSets.main, "${mod_id}.refmap.json"
@ -25,7 +28,7 @@ mixin {
} }
minecraft { minecraft {
mappings channel: 'official', version: minecraft_version mappings channel: 'parchment', version: "${parchment_mappings}"
if (project.hasProperty('forge_ats_enabled') && project.findProperty('forge_ats_enabled').toBoolean()) { if (project.hasProperty('forge_ats_enabled') && project.findProperty('forge_ats_enabled').toBoolean()) {
// This location is hardcoded in Forge and can not be changed. // This location is hardcoded in Forge and can not be changed.

View File

@ -1,11 +1,20 @@
package tschipp.carryon; package tschipp.carryon;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.simple.SimpleChannel;
import tschipp.carryon.config.forge.ConfigLoaderImpl; import tschipp.carryon.config.forge.ConfigLoaderImpl;
@Mod(Constants.MOD_ID) @Mod(Constants.MOD_ID)
@EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class CarryOnForge { public class CarryOnForge {
public static SimpleChannel network;
public CarryOnForge() { public CarryOnForge() {
// 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
@ -13,9 +22,19 @@ public class CarryOnForge {
// project. // project.
// Use Forge to bootstrap the Common mod. // Use Forge to bootstrap the Common mod.
Constants.LOG.info("Hello Forge world!"); CarryOnCommon.registerConfig();
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
ConfigLoaderImpl.initialize(); ConfigLoaderImpl.initialize();
} }
private void setup(final FMLCommonSetupEvent event)
{
network = NetworkRegistry.newSimpleChannel(new ResourceLocation(Constants.MOD_ID, "carryonpackets"), () -> "1.0", "1.0"::equals, "1.0"::equals);
CarryOnCommon.registerServerPackets();
CarryOnCommon.registerClientPackets();
}
} }

View File

@ -2,16 +2,25 @@ package tschipp.carryon.events;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.client.event.RenderLevelStageEvent;
import net.minecraftforge.client.event.RenderLevelStageEvent.Stage;
import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.event.TickEvent.ClientTickEvent;
import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import tschipp.carryon.CarryOnCommonClient;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.client.render.CarriedObjectRender; import tschipp.carryon.client.render.CarriedObjectRender;
import tschipp.carryon.client.render.CarryRenderHelper; import tschipp.carryon.client.render.CarryRenderHelper;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, modid = Constants.MOD_ID, value = Dist.CLIENT) @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, modid = Constants.MOD_ID, value = Dist.CLIENT)
public class ClientEvents { public class ClientEvents {
@ -29,4 +38,47 @@ public class ClientEvents {
if(CarriedObjectRender.drawFirstPerson(player, buffer, matrix, light, partialTicks) && CarryRenderHelper.getPerspective() == 0) if(CarriedObjectRender.drawFirstPerson(player, buffer, matrix, light, partialTicks) && CarryRenderHelper.getPerspective() == 0)
event.setCanceled(true); event.setCanceled(true);
} }
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void onRenderLevel(RenderLevelStageEvent event)
{
if(event.getStage() == Stage.AFTER_PARTICLES)
CarriedObjectRender.drawThirdPerson(event.getPartialTick(), event.getPoseStack());
}
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void onGuiInit(ScreenEvent.Init.Pre event)
{
if (event.getScreen() != null)
{
boolean inventory = event.getScreen() instanceof AbstractContainerScreen;
Minecraft mc = Minecraft.getInstance();
Player player = mc.player;
if (player != null && inventory)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (carry.isCarrying())
{
mc.player.closeContainer();
mc.screen = null;
mc.mouseHandler.grabMouse();
event.setCanceled(true);
}
}
}
}
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void onClientTick(ClientTickEvent event)
{
if(event.phase == Phase.END)
{
CarryOnCommonClient.checkForKeybinds();
}
}
} }

View File

@ -8,19 +8,28 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
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.event.AddReloadListenerEvent;
import net.minecraftforge.event.OnDatapackSyncEvent;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.event.TickEvent.ServerTickEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.level.BlockEvent.EntityPlaceEvent; import net.minecraftforge.event.level.BlockEvent.EntityPlaceEvent;
import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.eventbus.api.Event.Result; import net.minecraftforge.eventbus.api.Event.Result;
import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.InterModComms;
import net.minecraftforge.fml.InterModComms.IMCMessage;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent;
import tschipp.carryon.CarryOnCommon;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.*;
import tschipp.carryon.common.carry.CarryOnData.CarryType; import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.scripting.ScriptReloadListener;
import tschipp.carryon.common.carry.PickupHandler;
import tschipp.carryon.common.carry.PlacementHandler; import java.util.stream.Stream;
@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
@ -95,10 +104,86 @@ public class CommonEvents
return; return;
} }
} }
else if(carry.isCarrying(CarryType.ENTITY)) else if(carry.isCarrying(CarryType.ENTITY) || carry.isCarrying(CarryType.PLAYER))
{ {
//TODO: Stacking PlacementHandler.tryStackEntity((ServerPlayer)player, target);
} }
} }
@SubscribeEvent
public static void onRegisterCommands(RegisterCommandsEvent event)
{
CarryOnCommon.registerCommands(event.getDispatcher());
}
@SubscribeEvent(priority = EventPriority.LOW)
public void serverLoad(FMLDedicatedServerSetupEvent event)
{
Stream<IMCMessage> messages = InterModComms.getMessages(Constants.MOD_ID);
messages.forEach(msg -> {
String method = msg.method();
Object obj = msg.messageSupplier().get();
if (!(obj instanceof String str))
return;
switch (method)
{
case "blacklistBlock":
ListHandler.addForbiddenTiles(str);
break;
case "blacklistEntity":
ListHandler.addForbiddenEntities(str);
break;
case "whitelistBlock":
ListHandler.addAllowedTiles(str);
break;
case "whitelistEntity":
ListHandler.addAllowedEntities(str);
break;
case "blacklistStacking":
ListHandler.addForbiddenStacking(str);
break;
case "whitelistStacking":
ListHandler.addAllowedStacking(str);
break;
//TODO
// case "addModelOverride":
// ModelOverridesHandler.parseOverride(str, 0);
// break;
}
});
}
@SubscribeEvent
public static void onDatapackRegister(AddReloadListenerEvent event)
{
event.addListener(new ScriptReloadListener());
}
@SubscribeEvent
public static void onDatapackSync(OnDatapackSyncEvent event)
{
ServerPlayer player = event.getPlayer();
if(player == null)
{
for(ServerPlayer p : event.getPlayerList().getPlayers())
ScriptReloadListener.syncScriptsWithClient(p);
}
else
ScriptReloadListener.syncScriptsWithClient(player);
}
@SubscribeEvent
public static void onServerTick(ServerTickEvent event)
{
if(event.phase == Phase.END)
for(ServerPlayer player : event.getServer().getPlayerList().getPlayers())
PickupHandler.onCarryTick(player);
}
} }

View File

@ -0,0 +1,21 @@
package tschipp.carryon.events;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
import tschipp.carryon.Constants;
import tschipp.carryon.client.keybinds.CarryOnKeybinds;
@Mod.EventBusSubscriber(bus = Bus.MOD, modid = Constants.MOD_ID, value = Dist.CLIENT)
public class ModClientEvents
{
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void registerKeybinds(RegisterKeyMappingsEvent event)
{
CarryOnKeybinds.registerKeybinds(event::register);
}
}

View File

@ -1,10 +1,25 @@
package tschipp.carryon.platform; package tschipp.carryon.platform;
import tschipp.carryon.config.BuiltConfig; import net.minecraft.network.FriendlyByteBuf;
import tschipp.carryon.config.forge.ConfigLoaderImpl; import net.minecraft.resources.ResourceLocation;
import tschipp.carryon.platform.services.IPlatformHelper; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkEvent.Context;
import net.minecraftforge.network.PacketDistributor;
import tschipp.carryon.CarryOnForge;
import tschipp.carryon.client.CarryOnClient;
import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.forge.ConfigLoaderImpl;
import tschipp.carryon.networking.PacketBase;
import tschipp.carryon.platform.services.IPlatformHelper;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class ForgePlatformHelper implements IPlatformHelper { public class ForgePlatformHelper implements IPlatformHelper {
@ -30,4 +45,49 @@ public class ForgePlatformHelper implements IPlatformHelper {
public void registerConfig(BuiltConfig cfg) { public void registerConfig(BuiltConfig cfg) {
ConfigLoaderImpl.registerConfig(cfg); ConfigLoaderImpl.registerConfig(cfg);
} }
@Override
public <T extends PacketBase> void registerServerboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler)
{
BiConsumer<T, Supplier<Context>> serverHandler = (packet, ctx) -> {
if(ctx.get().getDirection().getReceptionSide().isServer())
{
ctx.get().setPacketHandled(true);
ctx.get().enqueueWork(() -> {
handler.accept(packet, ctx.get().getSender());
});
}
};
CarryOnForge.network.registerMessage(numericalId, clazz, writer, reader, serverHandler, Optional.of(NetworkDirection.PLAY_TO_SERVER));
}
@Override
public <T extends PacketBase> void registerClientboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler)
{
BiConsumer<T, Supplier<Context>> clientHandler = (packet, ctx) -> {
if(ctx.get().getDirection().getReceptionSide().isClient())
{
ctx.get().setPacketHandled(true);
ctx.get().enqueueWork(() -> {
handler.accept(packet, CarryOnClient.getPlayer());
});
}
};
CarryOnForge.network.registerMessage(numericalId, clazz, writer, reader, clientHandler, Optional.of(NetworkDirection.PLAY_TO_CLIENT));
}
@Override
public void sendPacketToServer(ResourceLocation id, PacketBase packet)
{
CarryOnForge.network.sendToServer(packet);
}
@Override
public void sendPacketToPlayer(ResourceLocation id, PacketBase packet, ServerPlayer player)
{
CarryOnForge.network.send(PacketDistributor.PLAYER.with(() -> player), packet);
}
} }

View File

@ -4,13 +4,13 @@ group=tschipp.carryon
# Common # Common
minecraft_version=1.19.2 minecraft_version=1.19.2
parchment_mappings=2022.09.18
common_runs_enabled=false common_runs_enabled=false
common_client_run_name=Common Client common_client_run_name=Common Client
common_server_run_name=Common Server common_server_run_name=Common Server
# Forge # Forge
forge_version=43.1.30 forge_version=43.1.30
parchment_mappings=2022.11.20-1.19.2
//forge_ats_enabled=true //forge_ats_enabled=true
# Fabric # Fabric

View File

@ -20,6 +20,8 @@ import net.minecraftforge.registries.ForgeRegistries;
public class ScriptParseHelper public class ScriptParseHelper
{ {
public static boolean matches(double number, String cond) public static boolean matches(double number, String cond)
{ {
if (cond == null || cond.isEmpty()) if (cond == null || cond.isEmpty())