feat: 调整了bot的实现方式

This commit is contained in:
Disy authored and zly2006 committed 2024-07-11 12:14:02 +08:00
1 parent 07596c15c7
commit 2063933634
10 files changed
+89 -85

No files matched your search

+2 -2
View File
@@ -41,14 +41,14 @@ dependencies {
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// luck perm // luck perm
modRuntimeOnly "maven.modrinth:luckperms:v5.4.83-fabric" modRuntimeOnly "maven.modrinth:luckperms:v5.4.133-fabric"
// carpet // carpet
modImplementation "carpet:fabric-carpet:${project.carpet_core_version}" modImplementation "carpet:fabric-carpet:${project.carpet_core_version}"
// modImplementation(files("./lib/fabric-carpet-1.20-1.4.112+v230608.jar")) // modImplementation(files("./lib/fabric-carpet-1.20-1.4.112+v230608.jar"))
// Fabric Permission API // Fabric Permission API
include(modImplementation('me.lucko:fabric-permissions-api:0.2-SNAPSHOT')) include(modImplementation('me.lucko:fabric-permissions-api:0.3.1'))
include(modImplementation('com.github.Fallen-Breath:conditional-mixin:v0.4.0')) include(modImplementation('com.github.Fallen-Breath:conditional-mixin:v0.4.0'))
// Fabric API. This is technically optional, but you probably want it anyway. // Fabric API. This is technically optional, but you probably want it anyway.
@@ -23,9 +23,6 @@ public class SLSCarpetSettings {
@Rule(categories = {CARPET_ID, RuleCategory.OPTIMIZATION}) @Rule(categories = {CARPET_ID, RuleCategory.OPTIMIZATION})
public static boolean noBatSpawning = false; public static boolean noBatSpawning = false;
@Rule(categories = {CARPET_ID, RuleCategory.FEATURE})
public static boolean offlineFakePlayers = false;
@Rule(categories = {CARPET_ID, RuleCategory.FEATURE}) @Rule(categories = {CARPET_ID, RuleCategory.FEATURE})
public static boolean canUseHatCommand = false; public static boolean canUseHatCommand = false;
@@ -4,9 +4,10 @@ import carpet.CarpetSettings;
import carpet.fakes.ServerPlayerInterface; import carpet.fakes.ServerPlayerInterface;
import carpet.helpers.EntityPlayerActionPack; import carpet.helpers.EntityPlayerActionPack;
import carpet.patches.EntityPlayerMPFake; import carpet.patches.EntityPlayerMPFake;
import carpet.patches.FakeClientConnection;
import carpet.utils.Messenger; import carpet.utils.Messenger;
import com.github.zly2006.carpetslsaddition.util.access.PlayerAccess;
import com.github.zly2006.carpetslsaddition.ServerMain; import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.util.access.PlayerAccess;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.brigadier.Command; import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
@@ -20,17 +21,24 @@ import net.minecraft.command.argument.DimensionArgumentType;
import net.minecraft.command.argument.GameModeArgumentType; import net.minecraft.command.argument.GameModeArgumentType;
import net.minecraft.command.argument.RotationArgumentType; import net.minecraft.command.argument.RotationArgumentType;
import net.minecraft.command.argument.Vec3ArgumentType; import net.minecraft.command.argument.Vec3ArgumentType;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.NetworkSide;
import net.minecraft.network.packet.c2s.common.SyncedClientOptions;
import net.minecraft.network.packet.s2c.play.EntityPositionS2CPacket;
import net.minecraft.network.packet.s2c.play.EntitySetHeadYawS2CPacket;
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKey;
import net.minecraft.server.Main;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerManager; import net.minecraft.server.PlayerManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ConnectedClientData;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Style; import net.minecraft.text.Style;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.UserCache;
import net.minecraft.util.Uuids; import net.minecraft.util.Uuids;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
@@ -39,12 +47,12 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameMode; import net.minecraft.world.GameMode;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import static net.minecraft.command.CommandSource.suggestMatching; import static net.minecraft.command.CommandSource.suggestMatching;
@@ -52,7 +60,6 @@ import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal; import static net.minecraft.server.command.CommandManager.literal;
public class BotCommand { public class BotCommand {
public static final ArrayBlockingQueue<ServerPlayerEntity> playerQueue = new ArrayBlockingQueue<>(128);
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) public static void register(CommandDispatcher<ServerCommandSource> dispatcher)
{ {
LiteralArgumentBuilder<ServerCommandSource> command = literal("bot") LiteralArgumentBuilder<ServerCommandSource> command = literal("bot")
@@ -279,41 +286,89 @@ public class BotCommand {
Messenger.m(source, "rb Player " + playerName + " cannot be placed outside of the world"); Messenger.m(source, "rb Player " + playerName + " cannot be placed outside of the world");
return 0; return 0;
} }
boolean success = EntityPlayerMPFake.createFake(playerName, source.getServer(), pos, facing.y, facing.x, dimType, GameMode.SURVIVAL, false);
if (!success) EntityPlayerMPFake bot = createBot(playerName, source.getServer(), pos, facing.y, facing.x, dimType);
if (bot == null)
{ {
Messenger.m(source, "rb Player " + playerName + " doesn't exist and cannot spawn in online mode. " + Messenger.m(source, "rb Player " + playerName + " doesn't exist and cannot spawn in online mode. " +
"Turn the server offline to spawn non-existing players"); "Turn the server offline to spawn non-existing players");
return 0; return 0;
} }
else {
ServerPlayerEntity player;
try {
player = playerQueue.poll(500, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e) {
return 1;
}
if (player == null) return 1; ((PlayerAccess) bot).carpet_SLS_Addition$setDisplayName(Text.empty().append(Text.literal("[%s] ".formatted(source.getName())).setStyle(Style.EMPTY.withColor(Formatting.AQUA))).append(Text.literal(playerName).setStyle(Style.EMPTY)));
((PlayerAccess) player).setDisplayName(Text.empty().append(Text.literal("[%s] ".formatted(source.getName())).setStyle(Style.EMPTY.withColor(Formatting.AQUA))).append(Text.literal(playerName).setStyle(Style.EMPTY))); ServerMain.server.getPlayerManager().broadcast(Text.empty()
ServerMain.server.getPlayerManager().broadcast(Text.empty() .append(Text.literal("假人").setStyle(Style.EMPTY.withColor(Formatting.GREEN)))
.append(Text.literal("假人").setStyle(Style.EMPTY.withColor(Formatting.GREEN))) .append(Text.literal(playerName).setStyle(Style.EMPTY.withColor(Formatting.GOLD).withBold(true)))
.append(Text.literal(playerName).setStyle(Style.EMPTY.withColor(Formatting.GOLD).withBold(true))) .append(Text.literal("由玩家").setStyle(Style.EMPTY.withColor(Formatting.GREEN)))
.append(Text.literal("由玩家").setStyle(Style.EMPTY.withColor(Formatting.GREEN))) .append(source.getDisplayName())
.append(source.getDisplayName()) .append(Text.literal("召唤!").setStyle(Style.EMPTY.withColor(Formatting.GREEN))), false);
.append(Text.literal("召唤!").setStyle(Style.EMPTY.withColor(Formatting.GREEN))), false);
ServerMain.server.getPlayerManager().sendToAll(new PlayerListS2CPacket( ServerMain.server.getPlayerManager().sendToAll(new PlayerListS2CPacket(
PlayerListS2CPacket.Action.UPDATE_DISPLAY_NAME, PlayerListS2CPacket.Action.UPDATE_DISPLAY_NAME,
player bot
)); ));
}
return 1; return 1;
} }
@SuppressWarnings("unchecked")
private static EntityPlayerMPFake createBot(String username, MinecraftServer server, Vec3d pos, double yaw, double pitch, RegistryKey<World> dimensionId) {
ServerWorld worldIn = server.getWorld(dimensionId);
UserCache.setUseRemote(false);
GameProfile gameprofile;
try {
gameprofile = server.getUserCache().findByName(username).orElse(null); //findByName .orElse(null)
}
finally {
UserCache.setUseRemote(server.isDedicated() && server.isOnlineMode());
}
if (gameprofile == null)
{
if (!CarpetSettings.allowSpawningOfflinePlayers)
{
return null;
} else {
gameprofile = new GameProfile(Uuids.getOfflinePlayerUuid(username), username);
}
}
// 孩子不懂,用反射写着玩的,报错了记得随Carpet一起升级一下
try {
Class<EntityPlayerMPFake> fakePlayerClass = (Class<EntityPlayerMPFake>)Class.forName("carpet.patches.EntityPlayerMPFake");
Constructor<EntityPlayerMPFake> constructor = fakePlayerClass.getDeclaredConstructor(
MinecraftServer.class,
ServerWorld.class,
GameProfile.class,
SyncedClientOptions.class,
boolean.class
);
constructor.setAccessible(true);
EntityPlayerMPFake bot = constructor.newInstance(server, worldIn, gameprofile, SyncedClientOptions.createDefault(), false);
bot.fixStartingPosition = () -> bot.refreshPositionAndAngles(pos.x, pos.y, pos.z, (float) yaw, (float) pitch);
server.getPlayerManager().onPlayerConnect(new FakeClientConnection(NetworkSide.SERVERBOUND), bot, new ConnectedClientData(gameprofile, 0, bot.getClientOptions(), false));
bot.teleport(worldIn, pos.x, pos.y, pos.z, (float) yaw, (float) pitch);
bot.setHealth(20.0F);
bot.unsetRemoved();
bot.getAttributeInstance(EntityAttributes.GENERIC_STEP_HEIGHT).setBaseValue(0.6F);
bot.interactionManager.changeGameMode(GameMode.SURVIVAL);
server.getPlayerManager().sendToDimension(new EntitySetHeadYawS2CPacket(bot, (byte) (bot.headYaw * 256 / 360)), dimensionId);//bot.dimension);
server.getPlayerManager().sendToDimension(new EntityPositionS2CPacket(bot), dimensionId);
bot.getDataTracker().set(PlayerEntity.PLAYER_MODEL_PARTS, (byte) 0x7f); // show all model layers (incl. capes)
bot.getAbilities().flying = false;
return bot;
}
catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("An error has occurred when trying spawn a new bot with reflection", e);
}
}
private static int maxNameLength(MinecraftServer server) private static int maxNameLength(MinecraftServer server)
{ {
return 40; return 40;
@@ -1,38 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.carpet;
import carpet.patches.EntityPlayerMPFake;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.command.BotCommand;
import com.mojang.authlib.GameProfile;
import net.minecraft.util.UserCache;
import net.minecraft.util.Uuids;
import net.minecraft.util.math.Vec3d;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Mixin(value = EntityPlayerMPFake.class)
public class MixinFakePlayer {
@Redirect(method = "createFake", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/UserCache;findByName(Ljava/lang/String;)Ljava/util/Optional;"))
private static Optional<GameProfile> onCreate(UserCache instance, String name) {
if (SLSCarpetSettings.offlineFakePlayers) {
UUID uuid = Uuids.getOfflinePlayerUuid(name);
return Optional.of(new GameProfile(uuid, name));
}
return instance.findByName(name);
}
@Inject(method = "lambda$createFake$1", at = @At("TAIL"))
private static void onAcceptFakePlayer(EntityPlayerMPFake instance, Vec3d pos, double yaw, double pitch, CallbackInfo ci) {
try {
BotCommand.playerQueue.offer(instance, 500, TimeUnit.MILLISECONDS);
}
catch (InterruptedException ignored) {}
}
}
@@ -1,12 +1,9 @@
package com.github.zly2006.carpetslsaddition.mixin.entity; package com.github.zly2006.carpetslsaddition.mixin.entity;
import com.github.zly2006.carpetslsaddition.util.access.PlayerAccess; import com.github.zly2006.carpetslsaddition.util.access.PlayerAccess;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.stat.Stat; import net.minecraft.stat.Stat;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -17,8 +14,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import static com.github.zly2006.carpetslsaddition.ServerMain.*;
@Mixin(PlayerEntity.class) @Mixin(PlayerEntity.class)
public abstract class MixinPlayerEntity implements PlayerAccess { public abstract class MixinPlayerEntity implements PlayerAccess {
@Shadow public abstract ItemStack getEquippedStack(EquipmentSlot slot); @Shadow public abstract ItemStack getEquippedStack(EquipmentSlot slot);
@@ -31,7 +26,7 @@ public abstract class MixinPlayerEntity implements PlayerAccess {
private Text displayName = null; private Text displayName = null;
@Override @Override
public void setDisplayName(Text name) { public void carpet_SLS_Addition$setDisplayName(Text name) {
this.displayName = name; this.displayName = name;
} }
@@ -3,7 +3,5 @@ package com.github.zly2006.carpetslsaddition.util.access;
import net.minecraft.text.Text; import net.minecraft.text.Text;
public interface PlayerAccess { public interface PlayerAccess {
boolean holdingObsidianPickaxe(); void carpet_SLS_Addition$setDisplayName(Text name);
void setDisplayName(Text name);
} }
@@ -8,7 +8,6 @@
"carpet.rule.skipTicksForJoblessVillager.name": "Skip ticks for jobless villager", "carpet.rule.skipTicksForJoblessVillager.name": "Skip ticks for jobless villager",
"carpet.rule.creativeNoInfinitePickup.name": "Creative mode cannot infinite pickup", "carpet.rule.creativeNoInfinitePickup.name": "Creative mode cannot infinite pickup",
"carpet.rule.noBatSpawning.name": "No bat spawning", "carpet.rule.noBatSpawning.name": "No bat spawning",
"carpet.rule.offlineFakePlayers.name": "Use offline mode for fake players",
"carpet.rule.pcaSyncProtocol.name": "Enable PCA Sync Protocol", "carpet.rule.pcaSyncProtocol.name": "Enable PCA Sync Protocol",
"carpet.rule.pcaSyncPlayerEntity.name": "Set PCA Sync Protocol's entity scope", "carpet.rule.pcaSyncPlayerEntity.name": "Set PCA Sync Protocol's entity scope",
"carpet.rule.emptyShulkerBoxStack.name": "Empty shulker boxes can be stacked", "carpet.rule.emptyShulkerBoxStack.name": "Empty shulker boxes can be stacked",
@@ -28,7 +27,6 @@
"carpet.rule.skipTicksForJoblessVillager.desc": "For jobless/nitwit villagers, after performing a set number of tick operations, skip the 1 tick operation.", "carpet.rule.skipTicksForJoblessVillager.desc": "For jobless/nitwit villagers, after performing a set number of tick operations, skip the 1 tick operation.",
"carpet.rule.creativeNoInfinitePickup.desc": "If my inventory is full, don't pick up items in creative mode.", "carpet.rule.creativeNoInfinitePickup.desc": "If my inventory is full, don't pick up items in creative mode.",
"carpet.rule.noBatSpawning.desc": "Prevents bats from spawning.", "carpet.rule.noBatSpawning.desc": "Prevents bats from spawning.",
"carpet.rule.offlineFakePlayers.desc": "Using offline uuid and skin so that fake players wont cause extra network traffic.",
"carpet.rule.pcaSyncProtocol.desc": "Using PCA protocol to support sync entity and blockEntity from server", "carpet.rule.pcaSyncProtocol.desc": "Using PCA protocol to support sync entity and blockEntity from server",
"carpet.rule.pcaSyncPlayerEntity.desc": "Which player entity can be sync", "carpet.rule.pcaSyncPlayerEntity.desc": "Which player entity can be sync",
"carpet.rule.emptyShulkerBoxStack.desc": "Empty shulker boxes stack", "carpet.rule.emptyShulkerBoxStack.desc": "Empty shulker boxes stack",
@@ -8,7 +8,6 @@
"carpet.rule.skipTicksForJoblessVillager.name": "无业村民跳刻", "carpet.rule.skipTicksForJoblessVillager.name": "无业村民跳刻",
"carpet.rule.creativeNoInfinitePickup.name": "创造模式满背包无法拾取", "carpet.rule.creativeNoInfinitePickup.name": "创造模式满背包无法拾取",
"carpet.rule.noBatSpawning.name": "禁止蝙蝠生成", "carpet.rule.noBatSpawning.name": "禁止蝙蝠生成",
"carpet.rule.offlineFakePlayers.name": "假人离线模式",
"carpet.rule.pcaSyncProtocol.name": "启动兼容PCA的同步协议", "carpet.rule.pcaSyncProtocol.name": "启动兼容PCA的同步协议",
"carpet.rule.pcaSyncPlayerEntity.name": "PCA同步协议作用范围", "carpet.rule.pcaSyncPlayerEntity.name": "PCA同步协议作用范围",
"carpet.rule.emptyShulkerBoxStack.name": "空潜影盒背包可堆叠", "carpet.rule.emptyShulkerBoxStack.name": "空潜影盒背包可堆叠",
@@ -28,7 +27,6 @@
"carpet.rule.skipTicksForJoblessVillager.desc": "对于无业/傻子村民,执行设定数量的tick运算后,跳过1tick的运算", "carpet.rule.skipTicksForJoblessVillager.desc": "对于无业/傻子村民,执行设定数量的tick运算后,跳过1tick的运算",
"carpet.rule.creativeNoInfinitePickup.desc": "创造模式下,玩家不能无限制地拾取物品", "carpet.rule.creativeNoInfinitePickup.desc": "创造模式下,玩家不能无限制地拾取物品",
"carpet.rule.noBatSpawning.desc": "禁止任何区域蝙蝠生成", "carpet.rule.noBatSpawning.desc": "禁止任何区域蝙蝠生成",
"carpet.rule.offlineFakePlayers.desc": "由Carpet生成的假玩家,将使用离线皮肤和UUID",
"carpet.rule.pcaSyncProtocol.desc": "借助PCA同步协议,支持同步 BlockEntity 和 Entity 到客户端", "carpet.rule.pcaSyncProtocol.desc": "借助PCA同步协议,支持同步 BlockEntity 和 Entity 到客户端",
"carpet.rule.pcaSyncPlayerEntity.desc": "决定哪些玩家的数据将会被同步", "carpet.rule.pcaSyncPlayerEntity.desc": "决定哪些玩家的数据将会被同步",
"carpet.rule.emptyShulkerBoxStack.desc": "空潜影盒可堆叠,但是不会改变容器中潜影盒的堆叠行为", "carpet.rule.emptyShulkerBoxStack.desc": "空潜影盒可堆叠,但是不会改变容器中潜影盒的堆叠行为",
+2
View File
@@ -1,3 +1,5 @@
accessWidener v1 named accessWidener v1 named
accessible class net/minecraft/world/block/ChainRestrictedNeighborUpdater$Entry accessible class net/minecraft/world/block/ChainRestrictedNeighborUpdater$Entry
accessible class net/minecraft/entity/mob/EndermanEntity$PickUpBlockGoal accessible class net/minecraft/entity/mob/EndermanEntity$PickUpBlockGoal
accessible method net/minecraft/entity/Entity unsetRemoved ()V
accessible field net/minecraft/entity/player/PlayerEntity PLAYER_MODEL_PARTS Lnet/minecraft/entity/data/TrackedData;
@@ -12,7 +12,6 @@
"mixins": [ "mixins": [
"block.BlockPatternTestTransformInvoker", "block.BlockPatternTestTransformInvoker",
"block.MixinRedstoneWireBlock", "block.MixinRedstoneWireBlock",
"carpet.MixinFakePlayer",
"carpet.MixinSettingsManager", "carpet.MixinSettingsManager",
"entity.MixinArmorStandEntity", "entity.MixinArmorStandEntity",
"entity.MixinEnderDragonFight", "entity.MixinEnderDragonFight",