feat: 调整了bot的实现方式
This commit is contained in:
1 parent
07596c15c7
commit
2063933634
10 files changed
+90
-86
No files matched your search
+2
-2
@@ -41,14 +41,14 @@ dependencies {
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
// luck perm
|
||||
modRuntimeOnly "maven.modrinth:luckperms:v5.4.83-fabric"
|
||||
modRuntimeOnly "maven.modrinth:luckperms:v5.4.133-fabric"
|
||||
|
||||
// carpet
|
||||
modImplementation "carpet:fabric-carpet:${project.carpet_core_version}"
|
||||
// modImplementation(files("./lib/fabric-carpet-1.20-1.4.112+v230608.jar"))
|
||||
|
||||
// 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'))
|
||||
|
||||
// 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})
|
||||
public static boolean noBatSpawning = false;
|
||||
|
||||
@Rule(categories = {CARPET_ID, RuleCategory.FEATURE})
|
||||
public static boolean offlineFakePlayers = false;
|
||||
|
||||
@Rule(categories = {CARPET_ID, RuleCategory.FEATURE})
|
||||
public static boolean canUseHatCommand = false;
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ import carpet.CarpetSettings;
|
||||
import carpet.fakes.ServerPlayerInterface;
|
||||
import carpet.helpers.EntityPlayerActionPack;
|
||||
import carpet.patches.EntityPlayerMPFake;
|
||||
import carpet.patches.FakeClientConnection;
|
||||
import carpet.utils.Messenger;
|
||||
import com.github.zly2006.carpetslsaddition.util.access.PlayerAccess;
|
||||
import com.github.zly2006.carpetslsaddition.ServerMain;
|
||||
import com.github.zly2006.carpetslsaddition.util.access.PlayerAccess;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.brigadier.Command;
|
||||
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.RotationArgumentType;
|
||||
import net.minecraft.command.argument.Vec3ArgumentType;
|
||||
import net.minecraft.entity.attribute.EntityAttributes;
|
||||
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.registry.RegistryKey;
|
||||
import net.minecraft.server.Main;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.PlayerManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ConnectedClientData;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Style;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.UserCache;
|
||||
import net.minecraft.util.Uuids;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
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.World;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
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;
|
||||
|
||||
public class BotCommand {
|
||||
public static final ArrayBlockingQueue<ServerPlayerEntity> playerQueue = new ArrayBlockingQueue<>(128);
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher)
|
||||
{
|
||||
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");
|
||||
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. " +
|
||||
"Turn the server offline to spawn non-existing players");
|
||||
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()
|
||||
.append(Text.literal("假人").setStyle(Style.EMPTY.withColor(Formatting.GREEN)))
|
||||
.append(Text.literal(playerName).setStyle(Style.EMPTY.withColor(Formatting.GOLD).withBold(true)))
|
||||
.append(Text.literal("由玩家").setStyle(Style.EMPTY.withColor(Formatting.GREEN)))
|
||||
.append(source.getDisplayName())
|
||||
.append(Text.literal("召唤!").setStyle(Style.EMPTY.withColor(Formatting.GREEN))), false);
|
||||
ServerMain.server.getPlayerManager().broadcast(Text.empty()
|
||||
.append(Text.literal("假人").setStyle(Style.EMPTY.withColor(Formatting.GREEN)))
|
||||
.append(Text.literal(playerName).setStyle(Style.EMPTY.withColor(Formatting.GOLD).withBold(true)))
|
||||
.append(Text.literal("由玩家").setStyle(Style.EMPTY.withColor(Formatting.GREEN)))
|
||||
.append(source.getDisplayName())
|
||||
.append(Text.literal("召唤!").setStyle(Style.EMPTY.withColor(Formatting.GREEN))), false);
|
||||
|
||||
ServerMain.server.getPlayerManager().sendToAll(new PlayerListS2CPacket(
|
||||
PlayerListS2CPacket.Action.UPDATE_DISPLAY_NAME,
|
||||
player
|
||||
));
|
||||
}
|
||||
ServerMain.server.getPlayerManager().sendToAll(new PlayerListS2CPacket(
|
||||
PlayerListS2CPacket.Action.UPDATE_DISPLAY_NAME,
|
||||
bot
|
||||
));
|
||||
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)
|
||||
{
|
||||
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
-6
@@ -1,12 +1,9 @@
|
||||
package com.github.zly2006.carpetslsaddition.mixin.entity;
|
||||
|
||||
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.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.stat.Stat;
|
||||
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.callback.CallbackInfoReturnable;
|
||||
|
||||
import static com.github.zly2006.carpetslsaddition.ServerMain.*;
|
||||
|
||||
@Mixin(PlayerEntity.class)
|
||||
public abstract class MixinPlayerEntity implements PlayerAccess {
|
||||
@Shadow public abstract ItemStack getEquippedStack(EquipmentSlot slot);
|
||||
@@ -31,7 +26,7 @@ public abstract class MixinPlayerEntity implements PlayerAccess {
|
||||
private Text displayName = null;
|
||||
|
||||
@Override
|
||||
public void setDisplayName(Text name) {
|
||||
public void carpet_SLS_Addition$setDisplayName(Text name) {
|
||||
this.displayName = name;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,5 @@ package com.github.zly2006.carpetslsaddition.util.access;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public interface PlayerAccess {
|
||||
boolean holdingObsidianPickaxe();
|
||||
|
||||
void setDisplayName(Text name);
|
||||
void carpet_SLS_Addition$setDisplayName(Text name);
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
"carpet.rule.skipTicksForJoblessVillager.name": "Skip ticks for jobless villager",
|
||||
"carpet.rule.creativeNoInfinitePickup.name": "Creative mode cannot infinite pickup",
|
||||
"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.pcaSyncPlayerEntity.name": "Set PCA Sync Protocol's entity scope",
|
||||
"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.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.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.pcaSyncPlayerEntity.desc": "Which player entity can be sync",
|
||||
"carpet.rule.emptyShulkerBoxStack.desc": "Empty shulker boxes stack",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"carpet.rule.skipTicksForJoblessVillager.name": "无业村民跳刻",
|
||||
"carpet.rule.creativeNoInfinitePickup.name": "创造模式满背包无法拾取",
|
||||
"carpet.rule.noBatSpawning.name": "禁止蝙蝠生成",
|
||||
"carpet.rule.offlineFakePlayers.name": "假人离线模式",
|
||||
"carpet.rule.pcaSyncProtocol.name": "启动兼容PCA的同步协议",
|
||||
"carpet.rule.pcaSyncPlayerEntity.name": "PCA同步协议作用范围",
|
||||
"carpet.rule.emptyShulkerBoxStack.name": "空潜影盒背包可堆叠",
|
||||
@@ -28,7 +27,6 @@
|
||||
"carpet.rule.skipTicksForJoblessVillager.desc": "对于无业/傻子村民,执行设定数量的tick运算后,跳过1tick的运算",
|
||||
"carpet.rule.creativeNoInfinitePickup.desc": "创造模式下,玩家不能无限制地拾取物品",
|
||||
"carpet.rule.noBatSpawning.desc": "禁止任何区域蝙蝠生成",
|
||||
"carpet.rule.offlineFakePlayers.desc": "由Carpet生成的假玩家,将使用离线皮肤和UUID",
|
||||
"carpet.rule.pcaSyncProtocol.desc": "借助PCA同步协议,支持同步 BlockEntity 和 Entity 到客户端",
|
||||
"carpet.rule.pcaSyncPlayerEntity.desc": "决定哪些玩家的数据将会被同步",
|
||||
"carpet.rule.emptyShulkerBoxStack.desc": "空潜影盒可堆叠,但是不会改变容器中潜影盒的堆叠行为",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
accessWidener v1 named
|
||||
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": [
|
||||
"block.BlockPatternTestTransformInvoker",
|
||||
"block.MixinRedstoneWireBlock",
|
||||
"carpet.MixinFakePlayer",
|
||||
"carpet.MixinSettingsManager",
|
||||
"entity.MixinArmorStandEntity",
|
||||
"entity.MixinEnderDragonFight",
|
||||
|
||||
Reference in new issue
Block a user