diff --git a/src/main/java/carpet/CarpetExtension.java b/src/main/java/carpet/CarpetExtension.java index 81ff11b3..7ffe485d 100644 --- a/src/main/java/carpet/CarpetExtension.java +++ b/src/main/java/carpet/CarpetExtension.java @@ -2,49 +2,49 @@ package carpet; import carpet.settings.SettingsManager; import com.mojang.brigadier.CommandDispatcher; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; -public abstract class CarpetExtension +public interface CarpetExtension { /** * When game started before world is loaded */ - public void onGameStarted() {} + default void onGameStarted() {} /** * Runs once per loaded world once the World files / gamerules etc are fully loaded * Can be loaded multiple times in SinglePlayer */ - public void onServerLoaded(MinecraftServer server) {} + default void onServerLoaded(MinecraftServer server) {} /** * Runs once per game tick, as a first thing in the tick */ - public void onTick(MinecraftServer server) {} + default void onTick(MinecraftServer server) {} /** * Register your own commands right after vanilla commands are added * If that matters for you */ - public void registerCommands(CommandDispatcher dispatcher) {} + default void registerCommands(CommandDispatcher dispatcher) {} /** * Provide your own custom settings manager managed in the same way as base /carpet * command, but separated to its own command as defined in SettingsManager. */ - public SettingsManager customSettingsManager() {return null;} + default SettingsManager customSettingsManager() {return null;} /** * todiddalidoo */ - public void onPlayerLoggedIn(PlayerEntity player) {} + default void onPlayerLoggedIn(ServerPlayerEntity player) {} /** * todiddalidoo */ - public void onPlayerLoggedOut(PlayerEntity player) {} + default void onPlayerLoggedOut(ServerPlayerEntity player) {} - default void onServerClosed(MinecraftServer server) {}; + default void onServerClosed(MinecraftServer server) {} } diff --git a/src/main/java/carpet/commands/PlayerCommand.java b/src/main/java/carpet/commands/PlayerCommand.java index eba82471..0f53ec98 100644 --- a/src/main/java/carpet/commands/PlayerCommand.java +++ b/src/main/java/carpet/commands/PlayerCommand.java @@ -1,21 +1,28 @@ package carpet.commands; +import carpet.helpers.EntityPlayerActionPack; import carpet.settings.CarpetSettings; import carpet.fakes.ServerPlayerEntityInterface; import carpet.patches.EntityPlayerMPFake; import carpet.utils.Messenger; import com.google.common.collect.Sets; +import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.command.arguments.DimensionArgumentType; import net.minecraft.command.arguments.RotationArgumentType; import net.minecraft.command.arguments.Vec3ArgumentType; +import net.minecraft.server.PlayerManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec3d; import net.minecraft.world.GameMode; @@ -24,147 +31,98 @@ import net.minecraft.world.dimension.DimensionType; import java.util.Arrays; import java.util.Collection; import java.util.Set; +import java.util.function.Consumer; -import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger; -import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.word; import static net.minecraft.server.command.CommandManager.argument; import static net.minecraft.server.command.CommandManager.literal; import static net.minecraft.server.command.CommandSource.suggestMatching; public class PlayerCommand { + + // TODO: allow any order like execute public static void register(CommandDispatcher dispatcher) { - LiteralArgumentBuilder literalargumentbuilder = literal("player"). - requires((player) -> CarpetSettings.commandPlayer). - then(argument("player", word()). - suggests( (c, b) -> suggestMatching(getPlayers(c.getSource()), b)). - then(literal("stop"). - executes(PlayerCommand::stop)). - then(literal("use"). - executes(PlayerCommand::useOnce). - then(literal("once"). - executes( PlayerCommand::useOnce)). - then(literal("continuous"). - executes( PlayerCommand::useContinuous)). - then(literal("interval"). - then(argument("ticks",integer(2)). - executes( PlayerCommand::useInterval)))). - then(literal("jump"). - executes( PlayerCommand::jumpOnce). - then(literal("once"). - executes( PlayerCommand::jumpOnce)). - then(literal("continuous"). - executes( PlayerCommand::jumpContinuous)). - then(literal("interval"). - then(argument("ticks",integer(2)). - executes( PlayerCommand::jumpInterval )))). - then(literal("attack"). - executes(PlayerCommand::attackOnce). - then(literal("once"). - executes(PlayerCommand::attackOnce)). - then(literal("continuous"). - executes(PlayerCommand::attackContinuous)). - then(literal("interval"). - then(argument("ticks",integer(2)). - executes(PlayerCommand::attackInterval)))). - then(literal("drop"). - executes(PlayerCommand::dropItem)). - then(literal("swapHands"). - executes(PlayerCommand::swapHands)). - then(literal("kill"). - executes(PlayerCommand::kill)). - then(literal("shadow"). - executes(PlayerCommand::shadow)). - then(literal("mount"). - executes(PlayerCommand::mount)). - then(literal("dismount"). - executes(PlayerCommand::dismount)). - then(literal("sneak"). - executes(PlayerCommand::sneak)). - then(literal("sprint"). - executes(PlayerCommand::sprint)). - then(literal("look"). - then(literal("north"). - executes(PlayerCommand::lookNorth)). - then(literal("south"). - executes(PlayerCommand::lookSouth)). - then(literal("east"). - executes(PlayerCommand::lookEast)). - then(literal("west"). - executes(PlayerCommand::lookWest)). - then(literal("up"). - executes(PlayerCommand::lookUp)). - then(literal("down"). - executes(PlayerCommand::lookDown)). - then(argument("direction", RotationArgumentType.rotation()). - executes(PlayerCommand::lookAround))). - then(literal("turn"). - then(literal("left"). - executes(PlayerCommand::turnLeft)). - then(literal("right"). - executes(PlayerCommand::turnRight)). - then(literal("back"). - executes(PlayerCommand::turnBack)). - then(argument("direction",RotationArgumentType.rotation()). - executes(PlayerCommand::turn))). - then(literal("move"). - then(literal("forward"). - executes(PlayerCommand::moveForward)). - then(literal("backward"). - executes(PlayerCommand::moveBackward)). - then(literal("left"). - executes(PlayerCommand::strafeLeft)). - then(literal("right"). - executes(PlayerCommand::strafeRight))). - then(literal("spawn"). - executes(PlayerCommand::spawn). - then(literal("at"). - then(argument("position", Vec3ArgumentType.vec3()). - executes(PlayerCommand::spawn). - then(literal("facing"). - then(argument("direction",RotationArgumentType.rotation()). - executes(PlayerCommand::spawn). - then(literal("in"). - then(argument("dimension", DimensionArgumentType.dimension()). - executes(PlayerCommand::spawn))))))))); - + LiteralArgumentBuilder literalargumentbuilder = literal("player") + .requires((player) -> CarpetSettings.commandPlayer) + .then(argument("player", StringArgumentType.word()) + .suggests( (c, b) -> suggestMatching(getPlayers(c.getSource()), b)) + .then(literal("stop").executes(PlayerCommand::stop)) + .then(makeActionCommand("use", EntityPlayerActionPack.ActionType.USE)) + .then(makeActionCommand("jump", EntityPlayerActionPack.ActionType.JUMP)) + .then(makeActionCommand("attack", EntityPlayerActionPack.ActionType.ATTACK)) + .then(makeActionCommand("drop", EntityPlayerActionPack.ActionType.DROP_ITEM)) + .then(makeActionCommand("dropStack", EntityPlayerActionPack.ActionType.DROP_STACK)) + .then(makeActionCommand("swapHands", EntityPlayerActionPack.ActionType.SWAP_HANDS)) + .then(literal("kill").executes(PlayerCommand::kill)) + .then(literal("shadow"). executes(PlayerCommand::shadow)) + .then(literal("mount").executes(manipulation(EntityPlayerActionPack::mount))) + .then(literal("dismount").executes(manipulation(EntityPlayerActionPack::dismount))) + .then(literal("sneak").executes(manipulation(ap -> ap.setSneaking(true)))) + .then(literal("unsneak").executes(manipulation(ap -> ap.setSneaking(false)))) + .then(literal("sprint").executes(manipulation(ap -> ap.setSprinting(true)))) + .then(literal("unsprint").executes(manipulation(ap -> ap.setSprinting(false)))) + .then(literal("look") + .then(literal("north").executes(manipulation(ap -> ap.look(Direction.NORTH)))) + .then(literal("south").executes(manipulation(ap -> ap.look(Direction.SOUTH)))) + .then(literal("east").executes(manipulation(ap -> ap.look(Direction.EAST)))) + .then(literal("west").executes(manipulation(ap -> ap.look(Direction.WEST)))) + .then(literal("up").executes(manipulation(ap -> ap.look(Direction.UP)))) + .then(literal("down").executes(manipulation(ap -> ap.look(Direction.DOWN)))) + .then(argument("direction", RotationArgumentType.rotation()) + .executes(c -> manipulate(c, ap -> ap.look(RotationArgumentType.getRotation(c, "direction").toAbsoluteRotation(c.getSource()))))) + ).then(literal("turn") + .then(literal("left").executes(c -> manipulate(c, ap -> ap.turn(-90, 0)))) + .then(literal("right").executes(c -> manipulate(c, ap -> ap.turn(90, 0)))) + .then(literal("back").executes(c -> manipulate(c, ap -> ap.turn(180, 0)))) + .then(argument("rotation", RotationArgumentType.rotation()) + .executes(c -> manipulate(c, ap -> ap.turn(RotationArgumentType.getRotation(c, "rotation").toAbsoluteRotation(c.getSource()))))) + ).then(literal("move") + .then(literal("forward").executes(c -> manipulate(c, ap -> ap.setForward(1)))) + .then(literal("backward").executes(c -> manipulate(c, ap -> ap.setForward(-1)))) + .then(literal("left").executes(c -> manipulate(c, ap -> ap.setStrafing(1)))) + .then(literal("right").executes(c -> manipulate(c, ap -> ap.setStrafing(-1)))) + ).then(literal("spawn").executes(PlayerCommand::spawn) + .then(literal("at").then(argument("position", Vec3ArgumentType.vec3()).executes(PlayerCommand::spawn) + .then(literal("facing").then(argument("direction", RotationArgumentType.rotation()).executes(PlayerCommand::spawn) + .then(literal("in").then(argument("dimension", DimensionArgumentType.dimension()).executes(PlayerCommand::spawn))) + )) + )) + ) + ); dispatcher.register(literalargumentbuilder); } + + private static LiteralArgumentBuilder makeActionCommand(String actionName, EntityPlayerActionPack.ActionType type) + { + return literal(actionName) + .executes(c -> action(c, type, EntityPlayerActionPack.Action.once())) + .then(literal("once").executes(c -> action(c, type, EntityPlayerActionPack.Action.once()))) + .then(literal("continuous").executes(c -> action(c, type, EntityPlayerActionPack.Action.continuous()))) + .then(literal("interval").then(argument("ticks", IntegerArgumentType.integer(2)) + .executes(c -> action(c, type, EntityPlayerActionPack.Action.interval(IntegerArgumentType.getInteger(c, "ticks")))))); + } + private static Collection getPlayers(ServerCommandSource source) { - Set players = Sets.newLinkedHashSet( Arrays.asList("Steve","Alex")); + Set players = Sets.newLinkedHashSet(Arrays.asList("Steve", "Alex")); players.addAll(source.getPlayerNames()); return players; } private static ServerPlayerEntity getPlayer(CommandContext context) { - String playerName = getString(context,"player"); + String playerName = StringArgumentType.getString(context, "player"); MinecraftServer server = context.getSource().getMinecraftServer(); return server.getPlayerManager().getPlayer(playerName); } - private static boolean cantSpawn(CommandContext context) - { - String playerName = getString(context,"player"); - PlayerEntity player = context.getSource().getMinecraftServer().getPlayerManager().getPlayer(playerName); - if (player != null) - { - Messenger.m(context.getSource(), "r Player ", "rb "+playerName, "r is already logged on"); - return true; - } - return false; - } - private static boolean cantManipulate(CommandContext context) { PlayerEntity player = getPlayer(context); if (player == null) { - Messenger.m(context.getSource(),"r Can only manipulate existing players"); + Messenger.m(context.getSource(), "r Can only manipulate existing players"); return true; } PlayerEntity sendingPlayer; @@ -177,301 +135,145 @@ public class PlayerCommand return false; } - if (!(context.getSource().getMinecraftServer().getPlayerManager().isOperator(sendingPlayer.getGameProfile()))) + if (!context.getSource().getMinecraftServer().getPlayerManager().isOperator(sendingPlayer.getGameProfile())) { - if (!(sendingPlayer == player || player instanceof EntityPlayerMPFake)) + if (sendingPlayer != player && !(player instanceof EntityPlayerMPFake)) { - Messenger.m(context.getSource(),"r Non OP players can't control other real players"); + Messenger.m(context.getSource(), "r Non OP players can't control other real players"); return true; } } return false; } - private static boolean cantShadow(CommandContext context) - { - if (cantManipulate(context)) - return true; - PlayerEntity player = getPlayer(context); - if (player instanceof EntityPlayerMPFake) - { - Messenger.m(context.getSource(), "r Only real players can be shadowed"); - return true; - } - return false; - } - private static boolean cantReMove(CommandContext context) { - if (cantManipulate(context)) - return true; + if (cantManipulate(context)) return true; PlayerEntity player = getPlayer(context); - if (!(player instanceof EntityPlayerMPFake)) + if (player instanceof EntityPlayerMPFake) return false; + Messenger.m(context.getSource(), "r Only fake players can be moved or killed"); + return true; + } + + private static boolean cantSpawn(CommandContext context) + { + String playerName = StringArgumentType.getString(context, "player"); + MinecraftServer server = context.getSource().getMinecraftServer(); + PlayerManager manager = server.getPlayerManager(); + PlayerEntity player = manager.getPlayer(playerName); + if (player != null) { - Messenger.m(context.getSource(), "r Only fake players can be moved or killed"); + Messenger.m(context.getSource(), "r Player ", "rb " + playerName, "r is already logged on"); + return true; + } + GameProfile profile = server.getUserCache().findByName(playerName); + if (manager.getUserBanList().contains(profile)) + { + Messenger.m(context.getSource(), "r Player ", "rb " + playerName, "r is banned"); + return true; + } + if (manager.isWhitelistEnabled() && profile != null && manager.isWhitelisted(profile) && !context.getSource().hasPermissionLevel(2)) + { + Messenger.m(context.getSource(), "r Whitelisted players can only be spawned by operators"); return true; } return false; } - private static int stop(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().stop(); - return 1; - } - private static int useOnce(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().useOnce(); - return 1; - } - private static int useContinuous(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setUseForever(); - return 1; - } - private static int useInterval(CommandContext context) - { - if (cantManipulate(context)) return 0; - int ticks = getInteger(context, "ticks"); - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setUse(ticks, 0); - return 1; - } - private static int jumpOnce(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().jumpOnce(); - return 1; - } - private static int jumpContinuous(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setJumpForever(); - return 1; - } - private static int jumpInterval(CommandContext context) - { - if (cantManipulate(context)) return 0; - int ticks = getInteger(context, "ticks"); - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setJump(ticks, 0); - return 1; - } - private static int attackOnce(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().attackOnce(); - //((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().resetBlockRemoving(true); - - return 1; - } - private static int attackContinuous(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setAttackForever(); - return 1; - } - private static int attackInterval(CommandContext context) - { - if (cantManipulate(context)) return 0; - int ticks = getInteger(context, "ticks"); - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setAttack(ticks, 0); - return 1; - } - private static int dropItem(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().dropItem(); - return 1; - } - private static int swapHands(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().swapHands(); - return 1; - } private static int kill(CommandContext context) { if (cantReMove(context)) return 0; getPlayer(context).kill(); return 1; } - private static int shadow(CommandContext context) + + @FunctionalInterface + interface SupplierWithCommandSyntaxException { - if (cantShadow(context)) return 0; - EntityPlayerMPFake.createShadow( - context.getSource().getMinecraftServer(), - getPlayer(context)); - return 1; + T get() throws CommandSyntaxException; } - private static int mount(CommandContext context) + + private static T tryGetArg(SupplierWithCommandSyntaxException a, SupplierWithCommandSyntaxException b) throws CommandSyntaxException { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().mount(); - return 1; - } - private static int dismount(CommandContext context) - { - if (cantManipulate(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().dismount(); - return 1; - } - private static int sneak(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setSneaking(true); - return 1; - } - private static int sprint(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setSprinting(true); - return 1; - } - private static int lookNorth(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().look("north"); - return 1; - } - private static int lookSouth(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().look("south"); - return 1; - } - private static int lookEast(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().look("east"); - return 1; - } - private static int lookWest(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().look("west"); - return 1; - } - private static int lookUp(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().look("up"); - return 1; - } - private static int lookDown(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().look("down"); - return 1; - } - private static int lookAround(CommandContext context) - { - if (cantReMove(context)) return 0; - Vec2f vec2f = RotationArgumentType.getRotation(context, "direction").toAbsoluteRotation(context.getSource()); - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().look(vec2f.y,vec2f.x); - return 1; - } - private static int turnRight(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().turn("right"); - return 1; - } - private static int turnLeft(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().turn("left"); - return 1; - } - private static int turnBack(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().turn("back"); - return 1; - } - private static int turn(CommandContext context) - { - if (cantReMove(context)) return 0; - Vec2f vec2f = RotationArgumentType.getRotation(context, "direction").toAbsoluteRotation(context.getSource()); - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().turn(vec2f.y,vec2f.x); - return 1; - } - private static int moveForward(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setForward(1.0F); - return 1; - } - private static int moveBackward(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setForward(-1.0F); - return 1; - } - private static int strafeLeft(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setStrafing(-1.0F); - return 1; - } - private static int strafeRight(CommandContext context) - { - if (cantReMove(context)) return 0; - ((ServerPlayerEntityInterface)getPlayer(context)).getActionPack().setStrafing(1.0F); - return 1; + try + { + return a.get(); + } + catch (IllegalArgumentException e) + { + return b.get(); + } } + private static int spawn(CommandContext context) throws CommandSyntaxException { if (cantSpawn(context)) return 0; - Vec3d pos; - Vec2f facing; - DimensionType dim; - try - { - pos = Vec3ArgumentType.getVec3(context, "position"); - } - catch (IllegalArgumentException e) - { - pos = context.getSource().getPosition(); - } - try - { - facing = RotationArgumentType.getRotation(context, "direction").toAbsoluteRotation(context.getSource()); - } - catch (IllegalArgumentException e) - { - facing = context.getSource().getRotation(); - } - try - { - dim = DimensionArgumentType.getDimensionArgument(context, "dimension"); - } - catch (IllegalArgumentException e) - { - dim = context.getSource().getWorld().dimension.getType(); - } + ServerCommandSource source = context.getSource(); + Vec3d pos = tryGetArg( + () -> Vec3ArgumentType.getVec3(context, "position"), + source::getPosition + ); + Vec2f facing = tryGetArg( + () -> RotationArgumentType.getRotation(context, "direction").toAbsoluteRotation(context.getSource()), + source::getRotation + ); + DimensionType dim = tryGetArg( + () -> DimensionArgumentType.getDimensionArgument(context, "dimension"), + () -> source.getWorld().dimension.getType() + ); GameMode mode = GameMode.CREATIVE; try { ServerPlayerEntity player = context.getSource().getPlayer(); mode = player.interactionManager.getGameMode(); } - catch (CommandSyntaxException ignored) + catch (CommandSyntaxException ignored) {} + String playerName = StringArgumentType.getString(context, "player"); + MinecraftServer server = source.getMinecraftServer(); + PlayerEntity player = EntityPlayerMPFake.createFake(playerName, server, pos.x, pos.y, pos.z, facing.y, facing.x, dim, mode); + if (player == null) { - } - PlayerEntity p = EntityPlayerMPFake.createFake( - getString(context,"player"), - context.getSource().getMinecraftServer(), - pos.x, pos.y, pos.z, - facing.y, facing.x, - dim, - mode); - if (p == null) - { - Messenger.m(context.getSource(), "rb Player "+getString(context,"player")+" doesn't exist " + + Messenger.m(context.getSource(), "rb Player " + StringArgumentType.getString(context, "player") + " doesn't exist " + "and cannot spawn in online mode. Turn the server offline to spawn non-existing players"); } return 1; } + + private static int stop(CommandContext context) + { + if (cantManipulate(context)) return 0; + ServerPlayerEntity player = getPlayer(context); + ((ServerPlayerEntityInterface) player).getActionPack().stop(); + return 1; + } + + private static int manipulate(CommandContext context, Consumer action) + { + if (cantManipulate(context)) return 0; + ServerPlayerEntity player = getPlayer(context); + action.accept(((ServerPlayerEntityInterface) player).getActionPack()); + return 1; + } + + private static Command manipulation(Consumer action) + { + return c -> manipulate(c, action); + } + + private static int action(CommandContext context, EntityPlayerActionPack.ActionType type, EntityPlayerActionPack.Action action) + { + return manipulate(context, ap -> ap.start(type, action)); + } + + private static int shadow(CommandContext context) + { + ServerPlayerEntity player = getPlayer(context); + if (player instanceof EntityPlayerMPFake) + { + Messenger.m(context.getSource(), "r Cannot shadow fake players"); + return 0; + } + EntityPlayerMPFake.createShadow(player.server, player); + return 1; + } } diff --git a/src/main/java/carpet/helpers/EntityPlayerActionPack.java b/src/main/java/carpet/helpers/EntityPlayerActionPack.java index f0e0eb55..114bb3e7 100644 --- a/src/main/java/carpet/helpers/EntityPlayerActionPack.java +++ b/src/main/java/carpet/helpers/EntityPlayerActionPack.java @@ -1,32 +1,35 @@ package carpet.helpers; -import carpet.settings.CarpetSettings; +import carpet.fakes.ServerPlayerEntityInterface; import carpet.mixins.PlayerActionC2SPacketMixin; +import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.packet.PlayerActionC2SPacket; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; import java.util.List; +import java.util.Map; +import java.util.TreeMap; public class EntityPlayerActionPack { private ServerPlayerEntity player; - private boolean doesAttack; - private int attackInterval; - private int attackCooldown; + private Map actions = new TreeMap<>(); - private boolean doesUse; - private int useInterval; - private int useCooldown; - - private boolean doesJump; - private int jumpInterval; - private int jumpCooldown; - - private BlockPos currentBlock = new BlockPos(-1,-1,-1); + private BlockPos currentBlock; private int blockHitDelay; private boolean isHittingBlock; private float curBlockDamageMP; @@ -43,19 +46,7 @@ public class EntityPlayerActionPack } public void copyFrom(EntityPlayerActionPack other) { - doesAttack = other.doesAttack; - attackInterval = other.attackInterval; - attackCooldown = other.attackCooldown; - - doesUse = other.doesUse; - useInterval = other.useInterval; - useCooldown = other.useCooldown; - - doesJump = other.doesJump; - jumpInterval = other.jumpInterval; - jumpCooldown = other.jumpCooldown; - - + actions.putAll(other.actions); currentBlock = other.currentBlock; blockHitDelay = other.blockHitDelay; isHittingBlock = other.isHittingBlock; @@ -67,63 +58,18 @@ public class EntityPlayerActionPack strafing = other.strafing; } - public EntityPlayerActionPack setAttack(int interval, int offset) + public EntityPlayerActionPack start(ActionType type, Action action) { - if (interval < 1) + Action previous = actions.remove(type); + if (previous != null) type.stop(player, previous); + if (action != null) { - CarpetSettings.LOG.error("attack interval needs to be positive"); - return this; + actions.put(type, action); + type.start(player, action); // noop } - this.doesAttack = true; - this.attackInterval = interval; - this.attackCooldown = interval+offset; - return this; - } - public EntityPlayerActionPack setUse(int interval, int offset) - { - if (interval < 1) - { - CarpetSettings.LOG.error("use interval needs to be positive"); - return this; - } - this.doesUse = true; - this.useInterval = interval; - this.useCooldown = interval+offset; - return this; - } - public EntityPlayerActionPack setUseForever() - { - this.doesUse = true; - this.useInterval = 1; - this.useCooldown = 1; - return this; - } - public EntityPlayerActionPack setAttackForever() - { - this.doesAttack = true; - this.attackInterval = 1; - this.attackCooldown = 1; - return this; - } - public EntityPlayerActionPack setJump(int interval, int offset) - { - if (interval < 1) - { - CarpetSettings.LOG.error("jump interval needs to be positive"); - return this; - } - this.doesJump = true; - this.jumpInterval = interval; - this.jumpCooldown = interval+offset; - return this; - } - public EntityPlayerActionPack setJumpForever() - { - this.doesJump = true; - this.jumpInterval = 1; - this.jumpCooldown = 1; return this; } + public EntityPlayerActionPack setSneaking(boolean doSneak) { sneaking = doSneak; @@ -151,98 +97,67 @@ public class EntityPlayerActionPack strafing = value; return this; } - public boolean look(String where) + public EntityPlayerActionPack look(Direction direction) { - switch (where) + switch (direction) { - case "north": - look(180.0f,0.0F); return true; - case "south": - look (0.0F, 0.0F); return true; - case "east": - look(-90.0F, 0.0F); return true; - case "west": - look(90.0F, 0.0F); return true; - case "up": - look(player.yaw, -90.0F); return true; - case "down": - look(player.yaw, 90.0F); return true; - case "left": - case "right": - return turn(where); + case NORTH: return look(180, 0); + case SOUTH: return look(0, 0); + case EAST: return look(-90, 0); + case WEST: return look(90, 0); + case UP: return look(player.yaw, -90); + case DOWN: return look(player.yaw, 90); } - return false; - } - public EntityPlayerActionPack look(float yaw, float pitch) - { - player.setPositionAndAngles(player.x, player.y, player.z, yaw, MathHelper.clamp(pitch,-90.0F, 90.0F)); return this; } - public boolean turn(String where) + public EntityPlayerActionPack look(Vec2f rotation) { - switch (where) - { - case "left": - turn(-90.0F,0.0F); return true; - case "right": - turn (90.0F, 0.0F); return true; - case "back": - turn (180.0F, 0.0F); return true; - case "up": - turn(0.0F, -5.0F); return true; - case "down": - turn(0.0F, 5.0F); return true; - } - return false; - } - public EntityPlayerActionPack turn(float yaw, float pitch) - { - player.setPositionAndAngles(player.x, player.y, player.z, player.yaw+yaw,MathHelper.clamp(player.pitch+pitch,-90.0F, 90.0F)); - return this; + return look(rotation.x, rotation.y); } + public EntityPlayerActionPack look(float yaw, float pitch) + { + player.yaw = yaw % 360; + player.pitch = MathHelper.clamp(pitch, -90, 90); + // maybe player.setPositionAndAngles(player.x, player.y, player.z, yaw, MathHelper.clamp(pitch,-90.0F, 90.0F)); + return this; + } + + public EntityPlayerActionPack turn(float yaw, float pitch) + { + return look(player.yaw + yaw, player.pitch + pitch); + } + + public EntityPlayerActionPack turn(Vec2f rotation) + { + return turn(rotation.x, rotation.y); + } public EntityPlayerActionPack stop() { - this.doesUse = false; - this.doesAttack = false; - this.doesJump = false; - //resetBlockRemoving(false); + for (ActionType type : actions.keySet()) type.stop(player, actions.get(type)); + actions.clear(); setSneaking(false); setSprinting(false); forward = 0.0F; strafing = 0.0F; - player.setJumping(false); - - return this; } - public void swapHands() - { - PlayerActionC2SPacket packet = new PlayerActionC2SPacket(); - ((PlayerActionC2SPacketMixin)packet).setAction(PlayerActionC2SPacket.Action.SWAP_HELD_ITEMS); - player.networkHandler.onPlayerAction(packet); - } - - public void dropItem() - { - PlayerActionC2SPacket packet = new PlayerActionC2SPacket(); - ((PlayerActionC2SPacketMixin)packet).setAction(PlayerActionC2SPacket.Action.DROP_ITEM); - player.networkHandler.onPlayerAction(packet); - } - public void mount() + public EntityPlayerActionPack mount() { + //test what happens List entities = player.world.getEntities(player,player.getBoundingBox().expand(3.0D, 1.0D, 3.0D)); if (entities.size()==0) - { - return; - } - Entity closest = entities.get(0); - double distance = player.squaredDistanceTo(closest); + return this; + Entity closest = null; + double distance = Double.POSITIVE_INFINITY; + Entity currentVehicle = player.getVehicle(); for (Entity e: entities) { + if (e == player || (currentVehicle == e)) + continue; double dd = player.squaredDistanceTo(e); if (dd e : actions.entrySet()) { - useCooldown = useInterval; - used = useOnce(); - } - if (doesAttack) - { - if ((--attackCooldown) == 0) + Action action = e.getValue(); + if (action.done) { - attackCooldown = attackInterval; - if (!(used)) attackOnce(); + actions.remove(e.getKey()); + continue; } + if (used && e.getKey() == ActionType.ATTACK) + continue; + if (action.tick(this, e.getKey())) + used = true; } if (forward != 0.0F) { @@ -298,561 +200,283 @@ public class EntityPlayerActionPack } } - public void jumpOnce() + static HitResult getTarget(ServerPlayerEntity player) { - if (player.onGround) - { - player.jump(); - } + double reach = player.interactionManager.isCreative() ? 5 : 4.5f; + return Tracer.rayTrace(player, 1, reach, false); } - - - public void attackOnce() + public enum ActionType { - /* needs rework due to 1.14 changes - HitResult raytraceresult = mouseOver(); - if(raytraceresult == null) return; - - switch (raytraceresult.getType()) + USE(true) { - case ENTITY: - player.attackTargetEntityWithCurrentItem(raytraceresult.entity); - this.player.swingArm(EnumHand.MAIN_HAND); - this.player.resetCooldown(); - break; - case MISS: - break; - case BLOCK: - BlockPos blockpos = raytraceresult.getBlockPos(); - if (player.getEntityWorld().getBlockState(blockpos).getMaterial() != Material.AIR) + @Override + boolean execute(ServerPlayerEntity player, Action action) + { + HitResult hit = getTarget(player); + for (Hand hand : Hand.values()) { - onPlayerDamageBlock(blockpos,raytraceresult.sideHit.getOpposite()); - this.player.swingArm(EnumHand.MAIN_HAND); - if (attackInterval > 1) + switch (hit.getType()) { - resetBlockRemoving(true); - } - break; - } - } - */ - } - - public boolean useOnce() - { - /*needs rework due to 1.14 changes - BlockHitResult raytraceresult = mouseOver(); - for (EnumHand enumhand : EnumHand.values()) - { - ItemStack itemstack = this.player.getHeldItem(enumhand); - if (raytraceresult != null) - { - switch (raytraceresult.type) - { - case ENTITY: - Entity target = raytraceresult.entity; - Vec3d vec3d = new Vec3d(raytraceresult.hitVec.x - target.posX, raytraceresult.hitVec.y - target.posY, raytraceresult.hitVec.z - target.posZ); - - boolean flag = player.canEntityBeSeen(target); - double d0 = 36.0D; - - if (!flag) + case BLOCK: { - d0 = 9.0D; - } - - if (player.getDistanceSq(target) < d0) - { - EnumActionResult res = player.interactOn(target,enumhand); - if (res == EnumActionResult.SUCCESS) + player.updateLastActionTime(); + ServerWorld world = player.getServerWorld(); + BlockHitResult blockHit = (BlockHitResult) hit; + BlockPos pos = blockHit.getBlockPos(); + Direction side = blockHit.getSide(); + if (pos.getY() < player.server.getWorldHeight() - (side == Direction.UP ? 1 : 0) && world.canPlayerModifyAt(player, pos)) { - return true; - } - res = target.applyPlayerInteraction(player, vec3d, enumhand); - if (res == EnumActionResult.SUCCESS) - { - return true; + ActionResult result = player.interactionManager.interactBlock(player, world, player.getStackInHand(hand), hand, blockHit); + if (result == ActionResult.SUCCESS) + { + player.swingHand(hand); + return true; + } } + break; } - break; - case MISS: - break; - case BLOCK: - BlockPos blockpos = raytraceresult.getBlockPos(); - - if (player.getEntityWorld().getBlockState(blockpos).getMaterial() != Material.AIR) + case ENTITY: { - float x = (float) raytraceresult.hitVec.x; - float y = (float) raytraceresult.hitVec.y; - float z = (float) raytraceresult.hitVec.z; - - EnumActionResult res = player.interactionManager.processRightClickBlock(player, player.getEntityWorld(), itemstack, enumhand, blockpos, raytraceresult.sideHit, x, y, z); - if (res == EnumActionResult.SUCCESS) - { - this.player.swingArm(enumhand); - return true; - } - } - } - } - EnumActionResult res = player.interactionManager.processRightClick(player,player.getEntityWorld(),itemstack,enumhand); - if (res == EnumActionResult.SUCCESS) - { - return true; - } - } - */ - return false; - } - - /*needs rework due to 1.14 changes - private BlockHitResult rayTraceBlocks(double blockReachDistance) - { - Vec3d eyeVec = player.getEyePosition(1.0F); - Vec3d lookVec = player.getLook(1.0F); - Vec3d pointVec = eyeVec.add(lookVec.x * blockReachDistance, lookVec.y * blockReachDistance, lookVec.z * blockReachDistance); - return player.getEntityWorld().rayTraceBlocks(eyeVec, pointVec, RayTraceFluidMode.NEVER, false, true); - } - - private BlockHitResult mouseOver() - { - World world = player.getEntityWorld(); - BlockHitResult result = null; - - Entity pointedEntity = null; - double reach = player.isCreative() ? 5.0D : 4.5D; - result = rayTraceBlocks(reach); - Vec3d eyeVec = player.getEyePosition(1.0F); - boolean flag = !player.isCreative(); - if (player.isCreative()) reach = 6.0D; - double extendedReach = reach; - - if (result != null) - { - extendedReach = result.hitVec.distanceTo(eyeVec); - if (world.getBlockState(result.getBlockPos()).getMaterial() == Material.AIR) - result = null; - } - - Vec3d lookVec = player.getLook(1.0F); - Vec3d pointVec = eyeVec.add(lookVec.x * reach, lookVec.y * reach, lookVec.z * reach); - Vec3d hitVec = null; - List list = world.getEntitiesInAABBexcluding( - player, - player.getBoundingBox().expand(lookVec.x * reach, lookVec.y * reach, lookVec.z * reach).grow(1.0D, 1.0D, 1.0D), - EntitySelectors.NOT_SPECTATING.and((Predicate) e -> e != null && e.canBeCollidedWith()) - ); - double d2 = extendedReach; - - for (int j = 0; j < list.size(); ++j) - { - Entity entity1 = list.get(j); - BoundingBox axisalignedbb = entity1.getBoundingBox().grow((double) entity1.getCollisionBorderSize()); - BlockHitResult raytraceresult = axisalignedbb.calculateIntercept(eyeVec, pointVec); - - if (axisalignedbb.contains(eyeVec)) - { - if (d2 >= 0.0D) - { - pointedEntity = entity1; - hitVec = raytraceresult == null ? eyeVec : raytraceresult.hitVec; - d2 = 0.0D; - } - } - else if (raytraceresult != null) - { - double d3 = eyeVec.distanceTo(raytraceresult.hitVec); - - if (d3 < d2 || d2 == 0.0D) - { - if (entity1.getLowestRidingEntity() == player.getLowestRidingEntity()) - { - if (d2 == 0.0D) - { - pointedEntity = entity1; - hitVec = raytraceresult.hitVec; + player.updateLastActionTime(); + EntityHitResult entityHit = (EntityHitResult) hit; + Entity entity = entityHit.getEntity(); + Vec3d relativeHitPos = entityHit.getPos().subtract(entity.x, entity.y, entity.z); + if (entity.interactAt(player, relativeHitPos, hand) == ActionResult.SUCCESS) return true; + if (player.interact(entity, hand) == ActionResult.SUCCESS) return true; + break; } } - else - { - pointedEntity = entity1; - hitVec = raytraceresult.hitVec; - d2 = d3; - } } - } - } - - if (pointedEntity != null && flag && eyeVec.distanceTo(hitVec) > 3.0D) - { - pointedEntity = null; - result = new BlockHitResult(BlockHitResult.Type.MISS, hitVec, (Direction) null, new BlockPos(hitVec)); - } - - if (pointedEntity != null && (d2 < extendedReach || result == null)) - { - result = new BlockHitResult(pointedEntity, hitVec); - } - - return result; - } - - public boolean clickBlock(BlockPos loc, Direction face) // don't call this one - { - World world = player.getEntityWorld(); - if (player.interactionManager.getGameType()!=GameMode.ADVENTURE) - { - if (player.interactionManager.getGameType() == GameMode.SPECTATOR) - { return false; } - if (!player.abilities.allowEdit) + @Override + void inactiveTick(ServerPlayerEntity player, Action action) { - ItemStack itemstack = player.getHeldItemMainhand(); - - if (itemstack.isEmpty()) - { - return false; - } - - BlockWorldState blockworldstate = new BlockWorldState(world, loc, false); - - if (!itemstack.canDestroy(world.getTags(), blockworldstate)) - { - return false; - } + player.stopUsingItem(); } - } + }, + ATTACK(true) { + @Override + boolean execute(ServerPlayerEntity player, Action action) { + HitResult hit = getTarget(player); + switch (hit.getType()) { + case ENTITY: { + EntityHitResult entityHit = (EntityHitResult) hit; + player.attack(entityHit.getEntity()); + player.resetLastAttackedTicks(); + player.updateLastActionTime(); + player.swingHand(Hand.MAIN_HAND); + break; + } + case BLOCK: { + EntityPlayerActionPack ap = ((ServerPlayerEntityInterface) player).getActionPack(); + if (ap.blockHitDelay > 0) + { + ap.blockHitDelay--; + return false; + } + BlockHitResult blockHit = (BlockHitResult) hit; + BlockPos pos = blockHit.getBlockPos(); + Direction side = blockHit.getSide(); + if (player.method_21701(player.world, pos, player.interactionManager.getGameMode())) return false; + if (ap.currentBlock != null && player.world.isAir(ap.currentBlock)) + { + ap.currentBlock = null; + return false; + } + BlockState state = player.world.getBlockState(pos); + if (player.interactionManager.getGameMode().isCreative()) + { + player.interactionManager.method_14263(pos, PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, side, player.server.getWorldHeight()); + ap.blockHitDelay = 5; + } + else if (ap.currentBlock == null || !ap.currentBlock.equals(pos)) + { + if (ap.currentBlock != null) + { + player.interactionManager.method_14263(ap.currentBlock, PlayerActionC2SPacket.Action.ABORT_DESTROY_BLOCK, side, player.server.getWorldHeight()); + } + player.interactionManager.method_14263(pos, PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, side, player.server.getWorldHeight()); + boolean notAir = !state.isAir(); + if (notAir && ap.curBlockDamageMP == 0) + { + state.onBlockBreakStart(player.world, pos, player); + } + if (notAir && state.calcBlockBreakingDelta(player, player.world, pos) >= 1) + { + ap.currentBlock = null; + } + else + { + ap.currentBlock = pos; + ap.curBlockDamageMP = 0; + } + } + else + { + ap.curBlockDamageMP += state.calcBlockBreakingDelta(player, player.world, pos); + if (ap.curBlockDamageMP >= 1) + { + player.interactionManager.method_14263(pos, PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, side, player.server.getWorldHeight()); + ap.currentBlock = null; + } + player.world.setBlockBreakingProgress(-1, pos, (int) (ap.curBlockDamageMP * 10)); - if (!world.getWorldBorder().contains(loc)) - { - return false; - } - else - { - if (player.interactionManager.getGameType()==GameMode.CREATIVE) - { - player.connection.processPlayerDigging(new CPacketPlayerDigging(loc, face, CPacketPlayerDigging.Action.START_DESTROY_BLOCK)); - clickBlockCreative(world, loc, face); - this.blockHitDelay = 5; + } + player.updateLastActionTime(); + player.swingHand(Hand.MAIN_HAND); + break; + } + } + return false; } - else if (!this.isHittingBlock || !(currentBlock.equals(loc))) + + @Override + void inactiveTick(ServerPlayerEntity player, Action action) { - if (this.isHittingBlock) + EntityPlayerActionPack ap = ((ServerPlayerEntityInterface) player).getActionPack(); + if (ap.currentBlock == null) return; + player.world.setBlockBreakingProgress(-1, ap.currentBlock, -1); + player.interactionManager.method_14263(ap.currentBlock, PlayerActionC2SPacket.Action.ABORT_DESTROY_BLOCK, Direction.DOWN, player.server.getWorldHeight()); + } + }, + JUMP(true) + { + @Override + boolean execute(ServerPlayerEntity player, Action action) + { + if (action.limit == 1) { - player.connection.processPlayerDigging(new CPacketPlayerDigging(this.currentBlock, face, CPacketPlayerDigging.Action.ABORT_DESTROY_BLOCK)); - } - - BlockState iblockstate = world.getBlockState(loc); - player.connection.processPlayerDigging(new CPacketPlayerDigging(loc, face, CPacketPlayerDigging.Action.START_DESTROY_BLOCK)); - boolean flag = iblockstate.getMaterial() != Material.AIR; - - if (flag && this.curBlockDamageMP == 0.0F) - { - iblockstate.getBlock().onBlockClicked(iblockstate, world, loc, player); - } - - if (flag && iblockstate.getPlayerRelativeBlockHardness(player, world, loc) >= 1.0F) - { - this.onPlayerDestroyBlock(loc); + if (player.onGround) player.jump(); } else { - this.isHittingBlock = true; - this.currentBlock = loc; - this.curBlockDamageMP = 0.0F; - world.sendBlockBreakProgress(player.getEntityId(), this.currentBlock, (int)(this.curBlockDamageMP * 10.0F) - 1); + player.setJumping(true); } - } - - return true; - } - } - - private void clickBlockCreative(World world, BlockPos pos, Direction facing) - { - if (!world.extinguishFire(player, pos, facing)) - { - onPlayerDestroyBlock(pos); - } - } - - public boolean onPlayerDamageBlock(BlockPos posBlock, Direction directionFacing) //continue clicking - one to call - { - if (this.blockHitDelay > 0) - { - --this.blockHitDelay; - return true; - } - World world = player.getEntityWorld(); - if (player.interactionManager.getGameType()==GameMode.CREATIVE && world.getWorldBorder().contains(posBlock)) - { - this.blockHitDelay = 5; - player.connection.processPlayerDigging(new CPacketPlayerDigging(posBlock, directionFacing, CPacketPlayerDigging.Action.START_DESTROY_BLOCK)); - clickBlockCreative(world, posBlock, directionFacing); - return true; - } - else if (posBlock.equals(currentBlock)) - { - BlockState iblockstate = world.getBlockState(posBlock); - - if (iblockstate.getMaterial() == Material.AIR) - { - this.isHittingBlock = false; - return false; - } - else - { - this.curBlockDamageMP += iblockstate.getPlayerRelativeBlockHardness(player, world, posBlock); - - if (this.curBlockDamageMP >= 1.0F) - { - this.isHittingBlock = false; - player.connection.processPlayerDigging(new CPacketPlayerDigging(posBlock, directionFacing, CPacketPlayerDigging.Action.STOP_DESTROY_BLOCK)); - this.onPlayerDestroyBlock(posBlock); - this.curBlockDamageMP = 0.0F; - this.blockHitDelay = 5; - } - //player.getEntityId() - //send to all, even the breaker - world.sendBlockBreakProgress(-1, this.currentBlock, (int)(this.curBlockDamageMP * 10.0F) - 1); - return true; - } - } - else - { - return this.clickBlock(posBlock, directionFacing); - } - } - - private boolean onPlayerDestroyBlock(BlockPos pos) - { - World world = player.getEntityWorld(); - if (player.interactionManager.getGameType()!=GameMode.ADVENTURE) - { - if (player.interactionManager.getGameType() == GameMode.SPECTATOR) - { return false; } - if (player.abilities.allowEdit) + @Override + void inactiveTick(ServerPlayerEntity player, Action action) { - ItemStack itemstack = player.getHeldItemMainhand(); - - if (itemstack.isEmpty()) - { - return false; - } - - BlockWorldState blockworldstate = new BlockWorldState(world, pos, false); - - if (!itemstack.canDestroy(world.getTags(), blockworldstate)) - { - return false; - } + player.setJumping(false); } - } - - if (player.interactionManager.getGameType()==GameMode.CREATIVE && !player.getHeldItemMainhand().isEmpty() && player.getHeldItemMainhand().getItem() instanceof ItemSword) + }, + DROP_ITEM(true) { - return false; - } - else - { - BlockState iblockstate = world.getBlockState(pos); - Block block = iblockstate.getBlock(); - - if ((block instanceof BlockCommandBlock || block instanceof BlockStructure) && !player.canUseCommandBlock()) + @Override + boolean execute(ServerPlayerEntity player, Action action) { + player.updateLastActionTime(); + player.dropSelectedItem(false); return false; } - else if (iblockstate.getMaterial() == Material.AIR) + }, + DROP_STACK(true) + { + @Override + boolean execute(ServerPlayerEntity player, Action action) { + player.updateLastActionTime(); + player.dropSelectedItem(true); return false; } - else + }, + SWAP_HANDS(true) + { + @Override + boolean execute(ServerPlayerEntity player, Action action) { - world.playEvent(2001, pos, Block.getStateId(iblockstate)); - block.onBlockHarvested(world, pos, iblockstate, player); - FluidState ifluidstate = world.getFluidState(pos); - boolean flag = world.setBlockState(pos, ifluidstate.getBlockState(), 11); - - if (flag) - { - block.onPlayerDestroy(world, pos, iblockstate); - } - - this.currentBlock = new BlockPos(this.currentBlock.getX(), -1, this.currentBlock.getZ()); - - if (!(player.interactionManager.getGameType()==GameMode.CREATIVE)) - { - ItemStack itemstack1 = player.getHeldItemMainhand(); - - if (!itemstack1.isEmpty()) - { - itemstack1.onBlockDestroyed(world, iblockstate, pos, player); - - if (itemstack1.isEmpty()) - { - player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY); - } - } - } - - return flag; + player.updateLastActionTime(); + ItemStack itemStack_1 = player.getStackInHand(Hand.OFF_HAND); + player.setStackInHand(Hand.OFF_HAND, player.getStackInHand(Hand.MAIN_HAND)); + player.setStackInHand(Hand.MAIN_HAND, itemStack_1); + return false; } + }; + + public final boolean preventSpectator; + + ActionType(boolean preventSpectator) + { + this.preventSpectator = preventSpectator; + } + + void start(ServerPlayerEntity player, Action action) {} + abstract boolean execute(ServerPlayerEntity player, Action action); + void inactiveTick(ServerPlayerEntity player, Action action) {} + void stop(ServerPlayerEntity player, Action action) + { + inactiveTick(player, action); } } - public void resetBlockRemoving(boolean force) + public static class Action { - if (this.isHittingBlock || force) + public boolean done = false; + public final int limit; + public final int interval; + public final int offset; + private int count; + private int next; + + private Action(int limit, int interval, int offset) { - player.connection.processPlayerDigging(new CPacketPlayerDigging(this.currentBlock, Direction.DOWN, CPacketPlayerDigging.Action.ABORT_DESTROY_BLOCK)); - this.isHittingBlock = false; - this.curBlockDamageMP = 0.0F; - player.getEntityWorld().sendBlockBreakProgress(player.getEntityId(), this.currentBlock, -1); - player.resetCooldown(); - blockHitDelay = 0; - this.currentBlock = new BlockPos(-1,-1,-1); + this.limit = limit; + this.interval = interval; + this.offset = offset; + next = interval + offset; } - } - - /* - public EnumActionResult processRightClickBlock(EntityPlayerSP player, WorldClient worldIn, BlockPos stack, Direction pos, Vec3d facing, EnumHand vec) - { - this.syncCurrentPlayItem(); - ItemStack itemstack = player.getHeldItem(vec); - float f = (float)(facing.xCoord - (double)stack.getX()); - float f1 = (float)(facing.yCoord - (double)stack.getY()); - float f2 = (float)(facing.zCoord - (double)stack.getZ()); - boolean flag = false; - - if (!this.mc.world.getWorldBorder().contains(stack)) + public static Action once() { - return EnumActionResult.FAIL; + return new Action(1, 1, 0); } - else + + public static Action continuous() { - if (this.currentGameType != GameMode.SPECTATOR) - { - BlockState iblockstate = worldIn.getBlockState(stack); + return new Action(-1, 1, 0); + } - if ((!player.isSneaking() || player.getHeldItemMainhand().func_190926_b() && player.getHeldItemOffhand().func_190926_b()) && iblockstate.getBlock().onBlockActivated(worldIn, stack, iblockstate, player, vec, pos, f, f1, f2)) + public static Action interval(int interval) + { + return new Action(-1, interval, 0); + } + + public static Action interval(int interval, int offset) + { + return new Action(-1, interval, offset); + } + + boolean tick(EntityPlayerActionPack actionPack, ActionType type) + { + next--; + boolean cancel = false; + if (next <= 0) { + + if (!type.preventSpectator || !actionPack.player.isSpectator()) { - flag = true; + cancel = type.execute(actionPack.player, this); } - - if (!flag && itemstack.getItem() instanceof ItemBlock) + count++; + if (count == limit) { - ItemBlock itemblock = (ItemBlock)itemstack.getItem(); - - if (!itemblock.canPlaceBlockOnSide(worldIn, stack, pos, player, itemstack)) - { - return EnumActionResult.FAIL; - } - } - } - - this.connection.sendPacket(new CPacketPlayerTryUseItemOnBlock(stack, pos, vec, f, f1, f2)); - - if (!flag && this.currentGameType != GameMode.SPECTATOR) - { - if (itemstack.func_190926_b()) - { - return EnumActionResult.PASS; - } - else if (player.getCooldownTracker().hasCooldown(itemstack.getItem())) - { - return EnumActionResult.PASS; - } - else - { - if (itemstack.getItem() instanceof ItemBlock && !player.canUseCommandBlock()) - { - Block block = ((ItemBlock)itemstack.getItem()).getBlock(); - - if (block instanceof BlockCommandBlock || block instanceof BlockStructure) - { - return EnumActionResult.FAIL; - } - } - - if (this.currentGameType.isCreative()) - { - int i = itemstack.getMetadata(); - int j = itemstack.func_190916_E(); - EnumActionResult enumactionresult = itemstack.onItemUse(player, worldIn, stack, vec, pos, f, f1, f2); - itemstack.setItemDamage(i); - itemstack.func_190920_e(j); - return enumactionresult; - } - else - { - return itemstack.onItemUse(player, worldIn, stack, vec, pos, f, f1, f2); - } + type.stop(actionPack.player, null); + done = true; + return cancel; } + next = interval; } else { - return EnumActionResult.SUCCESS; - } - } - } - - public EnumActionResult processRightClick(EntityPlayer player, World worldIn, EnumHand stack) - { - if (this.currentGameType == GameMode.SPECTATOR) - { - return EnumActionResult.PASS; - } - else - { - this.syncCurrentPlayItem(); - this.connection.sendPacket(new CPacketPlayerTryUseItem(stack)); - ItemStack itemstack = player.getHeldItem(stack); - - if (player.getCooldownTracker().hasCooldown(itemstack.getItem())) - { - return EnumActionResult.PASS; - } - else - { - int i = itemstack.func_190916_E(); - ActionResult actionresult = itemstack.useItemRightClick(worldIn, player, stack); - ItemStack itemstack1 = actionresult.getResult(); - - if (itemstack1 != itemstack || itemstack1.func_190916_E() != i) + if (!type.preventSpectator || !actionPack.player.isSpectator()) { - player.setHeldItem(stack, itemstack1); + type.inactiveTick(actionPack.player, this); } - - return actionresult.getType(); } + return cancel; } } - - public EnumActionResult interactWithEntity(EntityPlayer player, Entity target, EnumHand heldItem) - { - this.syncCurrentPlayItem(); - this.connection.sendPacket(new CPacketUseEntity(target, heldItem)); - return this.currentGameType == GameMode.SPECTATOR ? EnumActionResult.PASS : player.func_190775_a(target, heldItem); - } - */ - - /* - * Handles right clicking an entity from the entities side, sends a packet to the server. - * - public EnumActionResult interactWithEntity(EntityPlayer player, Entity target, BlockHitResult raytrace, EnumHand heldItem) - { - this.syncCurrentPlayItem(); - Vec3d vec3d = new Vec3d(raytrace.hitVec.xCoord - target.posX, raytrace.hitVec.yCoord - target.posY, raytrace.hitVec.zCoord - target.posZ); - this.connection.sendPacket(new CPacketUseEntity(target, heldItem, vec3d)); - return this.currentGameType == GameMode.SPECTATOR ? EnumActionResult.PASS : target.applyPlayerInteraction(player, vec3d, heldItem); - } -*/ - } diff --git a/src/main/java/carpet/helpers/Tracer.java b/src/main/java/carpet/helpers/Tracer.java index c49cfc19..b415012e 100644 --- a/src/main/java/carpet/helpers/Tracer.java +++ b/src/main/java/carpet/helpers/Tracer.java @@ -1,16 +1,90 @@ package carpet.helpers; import net.minecraft.entity.Entity; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; import net.minecraft.world.RayTraceContext; +import net.minecraft.world.World; + +import java.util.Optional; +import java.util.function.Predicate; public class Tracer { - public static HitResult traceEntityLook(Entity entity, double reach) { - Vec3d vec3d_1 = entity.getCameraPosVec(1.0F); - Vec3d vec3d_2 = entity.getRotationVec(1.0F); - Vec3d vec3d_3 = vec3d_1.add(vec3d_2.x * reach, vec3d_2.y * reach, vec3d_2.z * reach); - return entity.world.rayTrace(new RayTraceContext(vec3d_1, vec3d_3, RayTraceContext.ShapeType.OUTLINE, RayTraceContext.FluidHandling.ANY, entity)); + public static HitResult rayTrace(Entity source, float partialTicks, double reach, boolean fluids) + { + BlockHitResult blockHit = rayTraceBlocks(source, partialTicks, reach, fluids); + double maxSqDist = reach * reach; + if (blockHit != null) + { + maxSqDist = blockHit.getPos().squaredDistanceTo(source.getCameraPosVec(partialTicks)); + } + EntityHitResult entityHit = rayTraceEntities(source, partialTicks, reach, maxSqDist); + return entityHit == null ? blockHit : entityHit; + } + + public static BlockHitResult rayTraceBlocks(Entity source, float partialTicks, double reach, boolean fluids) + { + Vec3d pos = source.getCameraPosVec(partialTicks); + Vec3d rotation = source.getRotationVec(partialTicks); + Vec3d reachEnd = pos.add(rotation.x * reach, rotation.y * reach, rotation.z * reach); + return source.world.rayTrace(new RayTraceContext(pos, reachEnd, RayTraceContext.ShapeType.OUTLINE, fluids ? RayTraceContext.FluidHandling.ANY : RayTraceContext.FluidHandling.NONE, source)); + } + + public static EntityHitResult rayTraceEntities(Entity source, float partialTicks, double reach, double maxSqDist) + { + Vec3d pos = source.getCameraPosVec(partialTicks); + Vec3d reachVec = source.getRotationVec(partialTicks).multiply(reach); + Box box = source.getBoundingBox().stretch(reachVec).expand(1); + return rayTraceEntities(source, pos, pos.add(reachVec), box, e -> !e.isSpectator() && e.collides(), maxSqDist); + } + + public static EntityHitResult rayTraceEntities(Entity source, Vec3d start, Vec3d end, Box box, Predicate predicate, double maxSqDistance) + { + World world = source.world; + double targetDistance = maxSqDistance; + Entity target = null; + Vec3d targetHitPos = null; + for (Entity current : world.getEntities(source, box, predicate)) + { + Box currentBox = current.getBoundingBox().expand(current.getTargetingMargin()); + Optional currentHit = currentBox.rayTrace(start, end); + if (currentBox.contains(start)) + { + if (targetDistance >= 0) + { + target = current; + targetHitPos = currentHit.orElse(start); + targetDistance = 0; + } + } + else if (currentHit.isPresent()) + { + Vec3d currentHitPos = currentHit.get(); + double currentDistance = start.squaredDistanceTo(currentHitPos); + if (currentDistance < targetDistance || targetDistance == 0) + { + if (current.getRootVehicle() == source.getRootVehicle()) + { + if (targetDistance == 0) + { + target = current; + targetHitPos = currentHitPos; + } + } + else + { + target = current; + targetHitPos = currentHitPos; + targetDistance = currentDistance; + } + } + } + } + if (target == null) return null; + return new EntityHitResult(target, targetHitPos); } } diff --git a/src/main/java/carpet/mixins/Entity_horseFixMixin.java b/src/main/java/carpet/mixins/PlayerEntity_horseFixMixin.java similarity index 56% rename from src/main/java/carpet/mixins/Entity_horseFixMixin.java rename to src/main/java/carpet/mixins/PlayerEntity_horseFixMixin.java index 685c21a4..7d570a98 100644 --- a/src/main/java/carpet/mixins/Entity_horseFixMixin.java +++ b/src/main/java/carpet/mixins/PlayerEntity_horseFixMixin.java @@ -3,8 +3,12 @@ package carpet.mixins; import carpet.settings.CarpetSettings; import net.minecraft.client.network.packet.EntityPositionS2CPacket; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -12,22 +16,27 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(Entity.class) -public abstract class Entity_horseFixMixin +@Mixin(PlayerEntity.class) +public abstract class PlayerEntity_horseFixMixin extends Entity { - @Shadow private Entity vehicle; - @Shadow public abstract World getEntityWorld(); + @Shadow public abstract ActionResult interact(Entity entity_1, Hand hand_1); + + public PlayerEntity_horseFixMixin(EntityType entityType_1, World world_1) + { + super(entityType_1, world_1); + } @Inject(method = "stopRiding", at = @At("HEAD")) private void resetNavigation(CallbackInfo ci) { - if (vehicle != null && vehicle instanceof MobEntity && CarpetSettings.horseWanderingFix) + if (this.getVehicle() != null && CarpetSettings.horseWanderingFix) { - ((MobEntity) vehicle).getNavigation().stop(); + if (getVehicle() instanceof MobEntity) + ((MobEntity) getVehicle()).getNavigation().stop(); if (!getEntityWorld().isClient) { - ((ServerWorld) getEntityWorld()).method_14178().sendToNearbyPlayers((Entity)(Object)this, new EntityPositionS2CPacket(vehicle)); + ((ServerWorld) getEntityWorld()).method_14178().sendToNearbyPlayers((Entity)(Object)this, new EntityPositionS2CPacket(getVehicle())); } } } diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java new file mode 100644 index 00000000..3ca3c1a2 --- /dev/null +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java @@ -0,0 +1,30 @@ +package carpet.mixins; + +import carpet.CarpetServer; +import net.minecraft.network.ClientConnection; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.packet.CustomPayloadC2SPacket; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayNetworkHandler.class) +public class ServerPlayNetworkHandler_coreMixin { + @Shadow + public ServerPlayerEntity player; + + @Inject(method = "", at = @At("RETURN")) + private void onPlayerConnect(MinecraftServer server, ClientConnection client, ServerPlayerEntity player, CallbackInfo ci) { + CarpetServer.onPlayerLoggedIn(player); + } + + @Inject(method = "onDisconnected", at = @At("HEAD")) + private void onPlayerDisconnect(Text reason, CallbackInfo ci) { + CarpetServer.onPlayerLoggedOut(this.player); + } +} diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandlerMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_tickMixin.java similarity index 96% rename from src/main/java/carpet/mixins/ServerPlayNetworkHandlerMixin.java rename to src/main/java/carpet/mixins/ServerPlayNetworkHandler_tickMixin.java index ea11e749..afe068cb 100644 --- a/src/main/java/carpet/mixins/ServerPlayNetworkHandlerMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_tickMixin.java @@ -12,7 +12,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin +public class ServerPlayNetworkHandler_tickMixin { @Shadow public ServerPlayerEntity player; diff --git a/src/main/java/carpet/patches/EntityPlayerMPFake.java b/src/main/java/carpet/patches/EntityPlayerMPFake.java index 09419095..68df9885 100644 --- a/src/main/java/carpet/patches/EntityPlayerMPFake.java +++ b/src/main/java/carpet/patches/EntityPlayerMPFake.java @@ -78,6 +78,8 @@ public class EntityPlayerMPFake extends ServerPlayerEntity interactionManagerIn.setGameMode(player.interactionManager.getGameMode()); ((ServerPlayerEntityInterface) playerShadow).getActionPack().copyFrom(((ServerPlayerEntityInterface) player).getActionPack()); playerShadow.stepHeight = 0.6F; + playerShadow.dataTracker.set(PLAYER_MODEL_BIT_MASK, player.getDataTracker().get(PLAYER_MODEL_BIT_MASK)); + server.getPlayerManager().sendToDimension(new EntitySetHeadYawS2CPacket(playerShadow, (byte) (player.headYaw * 256 / 360)), playerShadow.dimension); server.getPlayerManager().sendToAll(new PlayerListS2CPacket(PlayerListS2CPacket.Action.ADD_PLAYER, playerShadow)); diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 3fb50f52..2b96c42e 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -29,7 +29,9 @@ "ServerWorld_fakePlayersMixin", - "ServerPlayNetworkHandlerMixin", + "ServerPlayNetworkHandler_coreMixin", + + "ServerPlayNetworkHandler_tickMixin", "MinecraftServer_scarpetMixin", "PlayerListHeaderS2CPacketMixin", "WeightedPickerEntryMixin", @@ -81,7 +83,7 @@ "Entity_portalSuffocationMixin", "PortalForcer_portalSuffocationMixin", - "Entity_horseFixMixin", + "PlayerEntity_horseFixMixin", "HopperBlockEntityMixin", "ContainerMixin",