diff --git a/fakeplayer-dist/pom.xml b/fakeplayer-dist/pom.xml index 93071f7..db9b93e 100644 --- a/fakeplayer-dist/pom.xml +++ b/fakeplayer-dist/pom.xml @@ -90,6 +90,12 @@ ${revision} + + io.github.hello09x.fakeplayer + fakeplayer-v1_21_5 + ${revision} + + @@ -164,6 +170,11 @@ + + + + + diff --git a/fakeplayer-dist/src/main/resources/META-INF/services/io.github.hello09x.fakeplayer.api.spi.NMSBridge b/fakeplayer-dist/src/main/resources/META-INF/services/io.github.hello09x.fakeplayer.api.spi.NMSBridge index fb262f9..59f89e4 100644 --- a/fakeplayer-dist/src/main/resources/META-INF/services/io.github.hello09x.fakeplayer.api.spi.NMSBridge +++ b/fakeplayer-dist/src/main/resources/META-INF/services/io.github.hello09x.fakeplayer.api.spi.NMSBridge @@ -8,3 +8,4 @@ io.github.hello09x.fakeplayer.v1_21.spi.NMSBridgeImpl io.github.hello09x.fakeplayer.v1_21_1.spi.NMSBridgeImpl io.github.hello09x.fakeplayer.v1_21_3.spi.NMSBridgeImpl io.github.hello09x.fakeplayer.v1_21_4.spi.NMSBridgeImpl +io.github.hello09x.fakeplayer.v1_21_5.spi.NMSBridgeImpl diff --git a/fakeplayer-v1_21_5/pom.xml b/fakeplayer-v1_21_5/pom.xml new file mode 100644 index 0000000..2d8cf9f --- /dev/null +++ b/fakeplayer-v1_21_5/pom.xml @@ -0,0 +1,100 @@ + + + 4.0.0 + + io.github.hello09x.fakeplayer + fakeplayer-parent + ${revision} + + + fakeplayer-v1_21_5 + + + 21 + 21 + UTF-8 + 1.21.5-R0.1-SNAPSHOT + + + + + + io.papermc.paper + paper-api + provided + + + + io.github.hello09x.fakeplayer + fakeplayer-core + provided + + + + io.github.hello09x.fakeplayer + fakeplayer-api + provided + + + + org.spigotmc + spigot + ${nms.version} + remapped-mojang + provided + + + + org.projectlombok + lombok + provided + + + + + + + + net.md-5 + specialsource-maven-plugin + 2.0.3 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:${nms.version}:txt:maps-mojang + true + + org.spigotmc:spigot:${nms.version}:jar:remapped-mojang + + true + remapped-obf + + + + package + + remap + + remap-spigot + + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + + org.spigotmc:minecraft-server:${nms.version}:csrg:maps-spigot + org.spigotmc:spigot:${nms.version}:jar:remapped-obf + + + + + + + + + \ No newline at end of file diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/AttackAction.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/AttackAction.java new file mode 100644 index 0000000..f210555 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/AttackAction.java @@ -0,0 +1,49 @@ +package io.github.hello09x.fakeplayer.v1_21_5.action; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; + + +public class AttackAction extends TraceAction { + + private final ServerPlayer player; + + public AttackAction(ServerPlayer player) { + super(player); + this.player = player; + } + + + @Override + public boolean tick() { + var hit = this.getTarget(); + if (hit == null) { + return false; + } + + if (hit.getType() != HitResult.Type.ENTITY) { + return false; + } + + var entityHit = (EntityHitResult) hit; + player.attack(entityHit.getEntity()); + player.swing(InteractionHand.MAIN_HAND); + player.resetAttackStrengthTicker(); + player.resetLastActionTime(); + return true; + } + + @Override + public void inactiveTick() { + + } + + @Override + public void stop() { + + } + + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/MineAction.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/MineAction.java new file mode 100644 index 0000000..21851f8 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/MineAction.java @@ -0,0 +1,160 @@ +package io.github.hello09x.fakeplayer.v1_21_5.action; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.Nullable; + +import static net.minecraft.network.protocol.game.ServerboundPlayerActionPacket.Action.*; + +public class MineAction extends TraceAction { + + private final Current current = new Current(); + + public MineAction(ServerPlayer player) { + super(player); + } + + @Override + @SuppressWarnings("resource") + public boolean tick() { + var hit = this.getTarget(); + if (hit == null) { + return false; + } + + if (hit.getType() != HitResult.Type.BLOCK) { + return false; + } + + if (current.freeze > 0) { + current.freeze--; + return false; + } + + var blockHit = (BlockHitResult) hit; + var pos = blockHit.getBlockPos(); + var side = blockHit.getDirection(); + + if (player.blockActionRestricted(player.level(), pos, player.gameMode.getGameModeForPlayer())) { + return false; + } + + if (current.pos != null && player.level().getBlockState(current.pos).isAir()) { + current.pos = null; + return false; + } + + var state = player.level().getBlockState(pos); + var broken = false; + if (player.gameMode.getGameModeForPlayer().isCreative()) { + player.gameMode.handleBlockBreakAction( + pos, + START_DESTROY_BLOCK, + side, + player.level().getMaxY(), + -1 + ); + current.freeze = 5; + broken = true; + } else if (current.pos == null || !current.pos.equals(pos)) { + if (current.pos != null) { + player.gameMode.handleBlockBreakAction( + current.pos, + ABORT_DESTROY_BLOCK, + side, + player.level().getMaxY(), + -1 + ); + } + + player.gameMode.handleBlockBreakAction( + pos, + START_DESTROY_BLOCK, + side, + player.level().getMaxY(), + -1 + ); + + if (!state.isAir() && current.progress == 0) { + state.attack(player.level(), pos, player); + } + + if (!state.isAir() && state.getDestroyProgress(player, player.level(), pos) >= 1) { + current.pos = null; + broken = true; + } else { + current.pos = pos; + current.progress = 0; + } + } else { + current.progress += state.getDestroyProgress(player, player.level(), pos); + if (current.progress >= 1) { + player.gameMode.handleBlockBreakAction( + pos, + STOP_DESTROY_BLOCK, + side, + player.level().getMaxY(), + -1 + ); + current.pos = null; + current.freeze = 5; + broken = true; + } + player.level().destroyBlockProgress(-1, pos, (int) (current.progress * 10)); + } + + player.resetLastActionTime(); + player.swing(InteractionHand.MAIN_HAND); + return broken; + } + + @Override + public void inactiveTick() { + stop(); + } + + @Override + @SuppressWarnings("resource") + public void stop() { + if (current.pos == null) { + return; + } + + player.level().destroyBlockProgress(-1, current.pos, -1); + player.gameMode.handleBlockBreakAction( + current.pos, + ABORT_DESTROY_BLOCK, + Direction.DOWN, + player.level().getMaxY(), + -1 + ); + current.pos = null; + current.freeze = 0; + current.progress = 0; + } + + private static class Current { + + /** + * 当前左键的目标位置 + */ + @Nullable + public BlockPos pos; + + /** + * 破坏方块的进度 + */ + public float progress; + + /** + * 冷却, 单位: tick + */ + public int freeze; + + } + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/TraceAction.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/TraceAction.java new file mode 100644 index 0000000..fb84a46 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/TraceAction.java @@ -0,0 +1,24 @@ +package io.github.hello09x.fakeplayer.v1_21_5.action; + +import io.github.hello09x.fakeplayer.api.spi.Action; +import io.github.hello09x.fakeplayer.v1_21_5.action.util.Tracer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class TraceAction implements Action { + + protected final ServerPlayer player; + + protected TraceAction(@NotNull ServerPlayer player) { + this.player = player; + } + + protected @Nullable HitResult getTarget() { + double reach = player.gameMode.isCreative() ? 5 : 4.5f; + return Tracer.rayTrace(player, 1, reach, false); + } + + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/UseAction.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/UseAction.java new file mode 100644 index 0000000..106582e --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/UseAction.java @@ -0,0 +1,97 @@ +package io.github.hello09x.fakeplayer.v1_21_5.action; + +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import org.jetbrains.annotations.NotNull; + +public class UseAction extends TraceAction { + + private final Current current = new Current(); + + public UseAction(@NotNull ServerPlayer player) { + super(player); + } + + @Override + @SuppressWarnings("resource") + public boolean tick() { + if (current.freeze > 0) { + current.freeze--; + return false; + } + + if (player.isUsingItem()) { + return true; + } + + var hit = this.getTarget(); + if (hit == null) { + return false; + } + + for (var hand : InteractionHand.values()) { + switch (hit.getType()) { + case BLOCK -> { + player.resetLastActionTime(); + var world = player.serverLevel(); + var blockHit = (BlockHitResult) hit; + var pos = blockHit.getBlockPos(); + var side = blockHit.getDirection(); + if (pos.getY() < player.level().getMaxY() - (side == Direction.UP ? 1 : 0) && world.mayInteract(player, pos)) { + var result = player.gameMode.useItemOn(player, world, player.getItemInHand(hand), hand, blockHit); + if (result.consumesAction()) { + player.swing(hand); + current.freeze = 3; + return true; + } + } + } + case ENTITY -> { + player.resetLastActionTime(); + var entityHit = (EntityHitResult) hit; + var entity = entityHit.getEntity(); + boolean handWasEmpty = player.getItemInHand(hand).isEmpty(); + boolean itemFrameEmpty = (entity instanceof ItemFrame) && ((ItemFrame) entity).getItem().isEmpty(); + var pos = entityHit.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + if (entity.interactAt(player, pos, hand).consumesAction()) { + current.freeze = 3; + return true; + } + if (player.interactOn(entity, hand).consumesAction() && !(handWasEmpty && itemFrameEmpty)) { + current.freeze = 3; + return true; + } + } + } + var handItem = player.getItemInHand(hand); + if (player.gameMode.useItem(player, player.level(), handItem, hand).consumesAction()) { + player.resetLastActionTime(); + current.freeze = 3; + return true; + } + } + return false; + } + + @Override + public void inactiveTick() { + } + + @Override + public void stop() { + current.freeze = 0; + player.releaseUsingItem(); + } + + private final static class Current { + + /** + * 冷却, 单位: tick + */ + public int freeze; + } +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/util/Tracer.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/util/Tracer.java new file mode 100644 index 0000000..6b86f27 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/action/util/Tracer.java @@ -0,0 +1,105 @@ +package io.github.hello09x.fakeplayer.v1_21_5.action.util; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Predicate; + +/** + * copy from fabric carpet mod + */ +public class Tracer { + + public static @Nullable HitResult rayTrace( + @NotNull Entity source, + float partialTicks, + double reach, + boolean fluids + ) { + var blockHit = rayTraceBlocks(source, partialTicks, reach, fluids); + double maxSqDist = reach * reach; + if (blockHit != null) { + maxSqDist = blockHit.getLocation().distanceToSqr(source.getEyePosition(partialTicks)); + } + EntityHitResult entityHit = rayTraceEntities(source, partialTicks, reach, maxSqDist); + return entityHit == null ? blockHit : entityHit; + } + + @SuppressWarnings("resource") + public static @Nullable BlockHitResult rayTraceBlocks( + @NotNull Entity source, + float partialTicks, + double reach, + boolean fluids + ) { + var pos = source.getEyePosition(partialTicks); + var rotation = source.getViewVector(partialTicks); + var reachEnd = pos.add(rotation.x * reach, rotation.y * reach, rotation.z * reach); + return source.level().clip(new ClipContext(pos, reachEnd, ClipContext.Block.OUTLINE, fluids ? + ClipContext.Fluid.ANY : ClipContext.Fluid.NONE, source)); + } + + public static @Nullable EntityHitResult rayTraceEntities( + @NotNull Entity source, + float partialTicks, + double reach, + double maxSqDist + ) { + var pos = source.getEyePosition(partialTicks); + var reachVec = source.getViewVector(partialTicks).scale(reach); + var box = source.getBoundingBox().expandTowards(reachVec).inflate(1); + return rayTraceEntities(source, + pos, + pos.add(reachVec), + box, + e -> !e.isSpectator() && e.isPickable(), + maxSqDist); + } + + public static @Nullable EntityHitResult rayTraceEntities( + @NotNull Entity source, + @NotNull Vec3 start, + @NotNull Vec3 end, + @NotNull AABB box, + @NotNull Predicate predicate, + double maxSqDistance + ) { + @SuppressWarnings("resource") + var world = source.level(); + double targetDistance = maxSqDistance; + Entity target = null; + Vec3 targetHitPos = null; + for (Entity current : world.getEntities(source, box, predicate)) { + var currentBox = current.getBoundingBox().inflate(current.getPickRadius()); + var currentHit = currentBox.clip(start, end); + if (currentBox.contains(start)) { + if (targetDistance >= 0) { + target = current; + targetHitPos = currentHit.orElse(start); + targetDistance = 0; + } + } else if (currentHit.isPresent()) { + var currentHitPos = currentHit.get(); + var currentDistance = start.distanceToSqr(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; + } + } + } + } + return target == null ? null : new EntityHitResult(target, targetHitPos); + } +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakeConnection.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakeConnection.java new file mode 100644 index 0000000..5a731e1 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakeConnection.java @@ -0,0 +1,43 @@ +package io.github.hello09x.fakeplayer.v1_21_5.network; + +import io.github.hello09x.fakeplayer.core.Main; +import io.github.hello09x.fakeplayer.core.manager.FakeplayerManager; +import io.github.hello09x.fakeplayer.core.network.FakeChannel; +import net.minecraft.network.Connection; +import net.minecraft.network.PacketSendListener; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.InetAddress; +import java.util.logging.Logger; + +public class FakeConnection extends Connection { + + private final static Logger log = Main.getInstance().getLogger(); + private final FakeplayerManager manager = Main.getInjector().getInstance(FakeplayerManager.class); + + public FakeConnection(@NotNull InetAddress address) { + super(PacketFlow.SERVERBOUND); + this.channel = new FakeChannel(null, address); + this.address = this.channel.remoteAddress(); + Connection.configureSerialization(this.channel.pipeline(), PacketFlow.SERVERBOUND, false, null); + } + + @Override + public boolean isConnected() { + return true; + } + + @Override + public void send(Packet packet, @Nullable PacketSendListener listener) { + + } + + @Override + public void send(Packet packet) { + + } + +} \ No newline at end of file diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakePlayerAdvancements.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakePlayerAdvancements.java new file mode 100644 index 0000000..070dc29 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakePlayerAdvancements.java @@ -0,0 +1,64 @@ +package io.github.hello09x.fakeplayer.v1_21_5.network; + +import com.mojang.datafixers.DataFixer; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.advancements.AdvancementProgress; +import net.minecraft.server.PlayerAdvancements; +import net.minecraft.server.ServerAdvancementManager; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.PlayerList; + +import java.nio.file.Path; + +public class FakePlayerAdvancements extends PlayerAdvancements { + + public FakePlayerAdvancements( + DataFixer datafixer, + PlayerList playerlist, + ServerAdvancementManager manager, + Path path, + ServerPlayer player + ) { + super(datafixer, playerlist, manager, path, player); + this.save(); + } + + @Override + public boolean award(AdvancementHolder advancementholder, String s) { + return false; + } + + @Override + public void flushDirty(ServerPlayer entityplayer, boolean flag) { + + } + + @Override + public AdvancementProgress getOrStartProgress(AdvancementHolder advancement) { + return new AdvancementProgress(); + } + + @Override + public boolean revoke(AdvancementHolder advancement, String s) { + return false; + } + + @Override + public void save() { + } + + @Override + public void setPlayer(ServerPlayer player) { + } + + @Override + public void setSelectedTab(AdvancementHolder advancement) { + } + + @Override + public void stopListening() { + + } + + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakeServerGamePacketListenerImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakeServerGamePacketListenerImpl.java new file mode 100644 index 0000000..d16a6d3 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/network/FakeServerGamePacketListenerImpl.java @@ -0,0 +1,89 @@ +package io.github.hello09x.fakeplayer.v1_21_5.network; + +import io.github.hello09x.fakeplayer.api.spi.NMSServerGamePacketListener; +import io.github.hello09x.fakeplayer.core.Main; +import io.github.hello09x.fakeplayer.core.manager.FakeplayerManager; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.custom.DiscardedPayload; +import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_21_R4.entity.CraftPlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.logging.Logger; + +public class FakeServerGamePacketListenerImpl extends ServerGamePacketListenerImpl implements NMSServerGamePacketListener { + + private final FakeplayerManager manager = Main.getInjector().getInstance(FakeplayerManager.class); + private final static Logger log = Main.getInstance().getLogger(); + + public FakeServerGamePacketListenerImpl( + @NotNull MinecraftServer server, + @NotNull Connection connection, + @NotNull ServerPlayer player, + @NotNull CommonListenerCookie cookie + ) { + super(server, connection, player, cookie); + Optional.ofNullable(Bukkit.getPlayer(player.getUUID())) + .map(CraftPlayer.class::cast) + .ifPresent(p -> p.addChannel(BUNGEE_CORD_CORRECTED_CHANNEL)); + } + + @Override + public void send(Packet packet) { + if (packet instanceof ClientboundCustomPayloadPacket p) { + this.handleCustomPayloadPacket(p); + } else if (packet instanceof ClientboundSetEntityMotionPacket p) { + this.handleClientboundSetEntityMotionPacket(p); + } + } + + /** + * 玩家被击退的动作由客户端完成, 假人没有客户端因此手动完成这个动作 + */ + public void handleClientboundSetEntityMotionPacket(@NotNull ClientboundSetEntityMotionPacket packet) { + if (packet.getId() == this.player.getId() && this.player.hurtMarked) { + Bukkit.getScheduler().runTask(Main.getInstance(), () -> { + this.player.hurtMarked = true; + this.player.lerpMotion(packet.getXa(), packet.getYa(), packet.getZa()); + }); + } + } + + private void handleCustomPayloadPacket(@NotNull ClientboundCustomPayloadPacket packet) { + var payload = packet.payload(); + var resourceLocation = payload.type().id(); + var channel = resourceLocation.getNamespace() + ":" + resourceLocation.getPath(); + + if (!channel.equals(BUNGEE_CORD_CORRECTED_CHANNEL)) { + return; + } + + if (!(payload instanceof DiscardedPayload p)) { + return; + } + + var recipient = Bukkit + .getOnlinePlayers() + .stream() + .filter(manager::isNotFake) + .findAny() + .orElse(null); + + if (recipient == null) { + log.warning("Failed to forward a plugin message cause non real players in the server"); + return; + } + + var message = p.data().array(); + recipient.sendPluginMessage(Main.getInstance(), BUNGEE_CORD_CHANNEL, message); + } + +} \ No newline at end of file diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/ActionTickerImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/ActionTickerImpl.java new file mode 100644 index 0000000..9d4de25 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/ActionTickerImpl.java @@ -0,0 +1,31 @@ +package io.github.hello09x.fakeplayer.v1_21_5.spi; + + +import io.github.hello09x.fakeplayer.api.spi.ActionSetting; +import io.github.hello09x.fakeplayer.api.spi.ActionTicker; +import io.github.hello09x.fakeplayer.api.spi.ActionType; +import io.github.hello09x.fakeplayer.api.spi.NMSBridge; +import io.github.hello09x.fakeplayer.core.entity.action.BaseActionTicker; +import io.github.hello09x.fakeplayer.v1_21_5.action.AttackAction; +import io.github.hello09x.fakeplayer.v1_21_5.action.MineAction; +import io.github.hello09x.fakeplayer.v1_21_5.action.UseAction; +import org.bukkit.craftbukkit.v1_21_R4.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class ActionTickerImpl extends BaseActionTicker implements ActionTicker { + + public ActionTickerImpl(@NotNull NMSBridge nms, @NotNull Player player, @NotNull ActionType action, @NotNull ActionSetting setting) { + super(nms, player, action, setting); + if (this.action == null) { + this.action = switch (action) { + case ATTACK -> new AttackAction(((CraftPlayer) player).getHandle()); + case MINE -> new MineAction(((CraftPlayer) player).getHandle()); + case USE -> new UseAction(((CraftPlayer) player).getHandle()); + case JUMP, LOOK_AT_NEAREST_ENTITY, DROP_INVENTORY, DROP_STACK, DROP_ITEM -> + throw new UnsupportedOperationException(); + }; + } + } + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSBridgeImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSBridgeImpl.java new file mode 100644 index 0000000..c648126 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSBridgeImpl.java @@ -0,0 +1,54 @@ +package io.github.hello09x.fakeplayer.v1_21_5.spi; + +import io.github.hello09x.fakeplayer.api.spi.*; +import io.github.hello09x.fakeplayer.core.Main; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.net.InetAddress; +import java.util.Set; + +public class NMSBridgeImpl implements NMSBridge { + + private final static Set SUPPORTS = Set.of("1.21.5"); + + @Override + public @NotNull NMSEntity fromEntity(@NotNull Entity entity) { + return new NMSEntityImpl(entity); + } + + @Override + public @NotNull NMSServer fromServer(@NotNull Server server) { + return new NMSServerImpl(server); + } + + @Override + public @NotNull NMSServerLevel fromWorld(@NotNull World world) { + return new NMSServerLevelImpl(world); + } + + @Override + public @NotNull NMSServerPlayer fromPlayer(@NotNull Player player) { + return new NMSServerPlayerImpl(player); + } + + @Override + public @NotNull NMSNetwork createNetwork(@NotNull InetAddress address) { + return new NMSNetworkImpl(address); + } + + @Override + public boolean isSupported() { + return SUPPORTS.contains(Bukkit.getMinecraftVersion()); + } + + @Override + public @NotNull ActionTicker createAction(@NotNull Player player, @NotNull ActionType action, @NotNull ActionSetting setting) { + return new ActionTickerImpl(Main.getInjector().getInstance(NMSBridge.class), player, action, setting); + } + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSEntityImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSEntityImpl.java new file mode 100644 index 0000000..32c350c --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSEntityImpl.java @@ -0,0 +1,19 @@ +package io.github.hello09x.fakeplayer.v1_21_5.spi; + +import io.github.hello09x.fakeplayer.api.spi.NMSEntity; +import lombok.Getter; +import net.minecraft.world.entity.Entity; +import org.bukkit.craftbukkit.v1_21_R4.entity.CraftEntity; +import org.jetbrains.annotations.NotNull; + +public class NMSEntityImpl implements NMSEntity { + + @Getter + private final Entity handle; + + public NMSEntityImpl(@NotNull org.bukkit.entity.@NotNull Entity entity) { + this.handle = ((CraftEntity) entity).getHandle(); + } + + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSNetworkImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSNetworkImpl.java new file mode 100644 index 0000000..c3b8d4c --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSNetworkImpl.java @@ -0,0 +1,64 @@ +package io.github.hello09x.fakeplayer.v1_21_5.spi; + +import io.github.hello09x.fakeplayer.api.spi.NMSNetwork; +import io.github.hello09x.fakeplayer.api.spi.NMSServerGamePacketListener; +import io.github.hello09x.fakeplayer.v1_21_5.network.FakeConnection; +import io.github.hello09x.fakeplayer.v1_21_5.network.FakeServerGamePacketListenerImpl; +import net.minecraft.server.network.CommonListenerCookie; +import org.bukkit.Server; +import org.bukkit.craftbukkit.v1_21_R4.CraftServer; +import org.bukkit.craftbukkit.v1_21_R4.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.net.InetAddress; + +public class NMSNetworkImpl implements NMSNetwork { + + @NotNull + private final FakeConnection connection; + + private NMSServerGamePacketListener serverGamePacketListener; + + public NMSNetworkImpl( + @NotNull InetAddress address + ) { + this.connection = new FakeConnection(address); + } + + @NotNull + @Override + public NMSServerGamePacketListener placeNewPlayer( + @NotNull Server server, + @NotNull Player player + ) { + var handle = ((CraftPlayer) player).getHandle(); + var cookie = CommonListenerCookie.createInitial(((CraftPlayer) player).getProfile(), false); + + ((CraftServer) server).getHandle().placeNewPlayer( + this.connection, + handle, + cookie + ); + + var listener = new FakeServerGamePacketListenerImpl( + ((CraftServer) server).getServer(), + this.connection, + handle, + cookie + ); + this.serverGamePacketListener = listener; + handle.connection = listener; + return listener; + } + + @NotNull + @Override + public NMSServerGamePacketListener getServerGamePacketListener() throws IllegalStateException { + if (this.serverGamePacketListener == null) { + throw new IllegalStateException("not initialized"); + } + return this.serverGamePacketListener; + } + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerImpl.java new file mode 100644 index 0000000..c1ddbf3 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerImpl.java @@ -0,0 +1,38 @@ +package io.github.hello09x.fakeplayer.v1_21_5.spi; + +import com.mojang.authlib.GameProfile; +import io.github.hello09x.devtools.core.utils.WorldUtils; +import io.github.hello09x.fakeplayer.api.spi.NMSServer; +import io.github.hello09x.fakeplayer.api.spi.NMSServerPlayer; +import lombok.Getter; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.craftbukkit.v1_21_R4.CraftServer; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class NMSServerImpl implements NMSServer { + + + @Getter + private final MinecraftServer handle; + + public NMSServerImpl(@NotNull Server server) { + this.handle = ((CraftServer) server).getServer(); + } + + @Override + public @NotNull NMSServerPlayer newPlayer(@NotNull UUID uuid, @NotNull String name) { + var handle = new ServerPlayer( + new NMSServerImpl(Bukkit.getServer()).getHandle(), + new NMSServerLevelImpl(WorldUtils.getMainWorld()).getHandle(), + new GameProfile(uuid, name), + ClientInformation.createDefault() + ); + return new NMSServerPlayerImpl(handle.getBukkitEntity()); + } +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerLevelImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerLevelImpl.java new file mode 100644 index 0000000..77247f7 --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerLevelImpl.java @@ -0,0 +1,19 @@ +package io.github.hello09x.fakeplayer.v1_21_5.spi; + +import io.github.hello09x.fakeplayer.api.spi.NMSServerLevel; +import lombok.Getter; +import net.minecraft.server.level.ServerLevel; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R4.CraftWorld; +import org.jetbrains.annotations.NotNull; + +public class NMSServerLevelImpl implements NMSServerLevel { + + @Getter + private final ServerLevel handle; + + public NMSServerLevelImpl(@NotNull World world) { + this.handle = ((CraftWorld) world).getHandle(); + } + +} diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerPlayerImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerPlayerImpl.java new file mode 100644 index 0000000..007352e --- /dev/null +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerPlayerImpl.java @@ -0,0 +1,254 @@ +package io.github.hello09x.fakeplayer.v1_21_5.spi; + +import io.github.hello09x.fakeplayer.api.spi.NMSServerPlayer; +import io.github.hello09x.fakeplayer.core.constant.ConstantPool; +import io.github.hello09x.fakeplayer.core.util.Reflections; +import io.github.hello09x.fakeplayer.v1_21_5.network.FakePlayerAdvancements; +import lombok.Getter; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.game.ServerboundClientCommandPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.server.PlayerAdvancements; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ParticleStatus; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_21_R4.CraftServer; +import org.bukkit.craftbukkit.v1_21_R4.entity.CraftPlayer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; + +public class NMSServerPlayerImpl implements NMSServerPlayer { + + private final static Field ServerPlayer$advancements = Reflections.getFirstFieldByType( + ServerPlayer.class, + PlayerAdvancements.class, + false + ); + + @Getter + private final ServerPlayer handle; + + @Getter + private final CraftPlayer player; + + public NMSServerPlayerImpl(@NotNull Player player) { + this.player = ((CraftPlayer) player); + this.handle = ((CraftPlayer) player).getHandle(); + } + + @Override + public double getX() { + return handle.getX(); + } + + @Override + public double getY() { + return handle.getY(); + } + + @Override + public double getZ() { + return handle.getZ(); + } + + @Override + public void setXo(double xo) { + handle.xo = xo; + } + + @Override + public void setYo(double yo) { + handle.yo = yo; + } + + @Override + public void setZo(double zo) { + handle.zo = zo; + } + + @Override + public void doTick() { + handle.doTick(); + } + + @Override + public void absMoveTo(double x, double y, double z, float yRot, float xRot) { + handle.absSnapTo(x, y, z, yRot, xRot); + } + + @Override + public float getYRot() { + return handle.getYRot(); + } + + @Override + public void setYRot(float yRot) { + handle.setYRot(yRot); + } + + @Override + public float getXRot() { + return handle.getXRot(); + } + + @Override + public void setXRot(float xRot) { + handle.setXRot(xRot); + } + + @Override + public float getZza() { + return handle.zza; + } + + @Override + public void setZza(float zza) { + handle.zza = zza; + } + + @Override + public float getXxa() { + return handle.xxa; + } + + @Override + public void setXxa(float xxa) { + handle.xxa = xxa; + } + + @Override + public void setDeltaMovement(@NotNull Vector vector) { + handle.setDeltaMovement(new Vec3( + vector.getX(), + vector.getY(), + vector.getZ() + )); + } + + @Override + public boolean startRiding(@NotNull Entity entity, boolean force) { + return handle.startRiding(new NMSEntityImpl(entity).getHandle(), force); + } + + @Override + public void stopRiding() { + handle.stopRiding(); + } + + + @Override + public int getTickCount() { + return handle.tickCount; + } + + @Override + public void drop(boolean allStack) { + handle.drop(allStack); + } + + @Override + public void resetLastActionTime() { + handle.resetLastActionTime(); + } + + @Override + public boolean onGround() { + return handle.onGround(); + } + + @Override + public void jumpFromGround() { + handle.jumpFromGround(); + } + + @Override + public void setJumping(boolean jumping) { + handle.setJumping(jumping); + } + + @Override + public boolean isUsingItem() { + return handle.isUsingItem(); + } + + @Override + public void disableAdvancements(@NotNull Plugin plugin) { + if (ServerPlayer$advancements == null) { + return; + } + + var server = ((CraftServer) Bukkit.getServer()).getServer(); + try { + ServerPlayer$advancements.set( + handle, + new FakePlayerAdvancements( + server.getFixerUpper(), + server.getPlayerList(), + server.getAdvancements(), + plugin.getDataFolder().getParentFile().toPath(), + handle + ) + ); + } catch (IllegalAccessException ignored) { + } + } + + @Override + public void drop(int slot, boolean flag, boolean flag1) { + var inventory = handle.getInventory(); + handle.drop(inventory.removeItem(slot, inventory.getItem(slot).getCount()), flag, flag1); + } + + @Override + public void setPlayBefore() { + player.readExtraData(new CompoundTag()); + } + + @Override + public void setupClientOptions() { + var option = new ClientInformation( + "en_us", + Bukkit.getViewDistance(), + ChatVisiblity.SYSTEM, + false, + ConstantPool.MODEL_CUSTOMISATION, + HumanoidArm.RIGHT, + false, + true, + ParticleStatus.MINIMAL + ); + + handle.updateOptions(option); + } + + @Override + public void respawn() { + if (!this.player.isDead()) { + return; + } + + var packet = new ServerboundClientCommandPacket(ServerboundClientCommandPacket.Action.PERFORM_RESPAWN); + handle.connection.handleClientCommand(packet); + } + + @Override + public void swapItemWithOffhand() { + handle.connection.handlePlayerAction(new ServerboundPlayerActionPacket( + ServerboundPlayerActionPacket.Action.SWAP_ITEM_WITH_OFFHAND, + new BlockPos(0, 0, 0), + Direction.DOWN + )); + } + +} diff --git a/pom.xml b/pom.xml index 8a2dc02..5106343 100644 --- a/pom.xml +++ b/pom.xml @@ -24,14 +24,15 @@ fakeplayer-v1_21_1 fakeplayer-v1_21_3 fakeplayer-v1_21_4 + fakeplayer-v1_21_5 21 UTF-8 - 0.3.13 + 0.3.14 - 0.1.4-SNAPSHOT + 0.1.5-SNAPSHOT @@ -101,7 +102,7 @@ dev.jorel commandapi-bukkit-core - 9.2.0 + 10.0.0 provided