feat: add bot command
This commit is contained in:
1 parent
ea91716272
commit
01944bd5b4
12 files changed
+460
-76
No files matched your search
@@ -1,5 +1,9 @@
|
||||
package com.github.zly2006.carpetslsaddition;
|
||||
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public interface PlayerAccess {
|
||||
boolean holdingObsidianPickaxe();
|
||||
|
||||
void setDisplayName(Text name);
|
||||
}
|
||||
@@ -2,8 +2,10 @@ package com.github.zly2006.carpetslsaddition;
|
||||
|
||||
import carpet.CarpetExtension;
|
||||
import carpet.CarpetServer;
|
||||
import com.github.zly2006.carpetslsaddition.command.BotCommand;
|
||||
import com.github.zly2006.carpetslsaddition.command.HatCommand;
|
||||
import com.github.zly2006.carpetslsaddition.command.SitCommand;
|
||||
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
|
||||
import com.github.zly2006.carpetslsaddition.util.SitEntity;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@@ -13,28 +15,13 @@ import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.Version;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.decoration.ArmorStandEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.ShapedRecipe;
|
||||
import net.minecraft.recipe.book.CraftingRecipeCategory;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.world.World;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ServerMain implements ModInitializer, CarpetExtension {
|
||||
@@ -58,6 +45,7 @@ public class ServerMain implements ModInitializer, CarpetExtension {
|
||||
public void onInitialize() {
|
||||
INSTANCE = this;
|
||||
CarpetServer.manageExtension(this);
|
||||
PcaSyncProtocol.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,24 +53,12 @@ public class ServerMain implements ModInitializer, CarpetExtension {
|
||||
ServerMain.server = server;
|
||||
CarpetServer.settingsManager.parseSettingsClass(SLSCarpetSettings.class);
|
||||
((SettingsManagerAccessor) CarpetServer.settingsManager).loadSettings();
|
||||
if (false) {
|
||||
ItemStack stack = new ItemStack(Items.STONE_PICKAXE);
|
||||
stack.setCustomName(Text.empty().formatted(Formatting.LIGHT_PURPLE).append("黑曜石镐"));
|
||||
stack.getOrCreateSubNbt(MOD_ID).putString(ITEM_NAME, OBSIDIAN_PICKAXE);
|
||||
DefaultedList<Ingredient> ingredients = DefaultedList.ofSize(9, Ingredient.EMPTY);
|
||||
ingredients.set(0, Ingredient.ofItems(Items.OBSIDIAN));
|
||||
ingredients.set(1, Ingredient.ofItems(Items.OBSIDIAN));
|
||||
ingredients.set(2, Ingredient.ofItems(Items.OBSIDIAN));
|
||||
ingredients.set(4, Ingredient.ofItems(Items.STICK));
|
||||
ingredients.set(7, Ingredient.ofItems(Items.STICK));
|
||||
server.getRecipeManager().setRecipes(List.of(new ShapedRecipe(new Identifier(MOD_ID, "recipe.obsidian_pickaxe"), MOD_ID, CraftingRecipeCategory.EQUIPMENT, 3, 3, ingredients, stack)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> canHasTranslations(String lang) {
|
||||
Map<String, String> translation = Maps.newHashMap();
|
||||
PcaSyncProtocol.init();
|
||||
|
||||
String jsonFile;
|
||||
try {
|
||||
try (InputStream stream = ServerMain.class.getResourceAsStream("/assets/slsaddition/lang/%s.json".formatted(lang))) {
|
||||
@@ -109,42 +85,8 @@ public class ServerMain implements ModInitializer, CarpetExtension {
|
||||
|
||||
@Override
|
||||
public void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher, CommandRegistryAccess commandBuildContext) {
|
||||
dispatcher.register(CommandManager.literal("hat")
|
||||
.requires(ServerCommandSource::isExecutedByPlayer)
|
||||
.requires((commandSource) -> SLSCarpetSettings.canUseHatCommand)
|
||||
.executes(context -> {
|
||||
ServerPlayerEntity player = context.getSource().getPlayer();
|
||||
assert player != null;
|
||||
ItemStack stack = player.getMainHandStack();
|
||||
ItemStack head = player.getEquippedStack(EquipmentSlot.HEAD);
|
||||
player.equipStack(EquipmentSlot.HEAD, stack);
|
||||
player.getInventory().setStack(player.getInventory().selectedSlot, head);
|
||||
player.currentScreenHandler.syncState();
|
||||
|
||||
return 1;
|
||||
}));
|
||||
|
||||
dispatcher.register(CommandManager.literal("sit")
|
||||
.requires(ServerCommandSource::isExecutedByPlayer)
|
||||
.requires((commandSource) -> SLSCarpetSettings.canUseSitCommand)
|
||||
.executes(context -> {
|
||||
ServerPlayerEntity player = context.getSource().getPlayer();
|
||||
assert player != null;
|
||||
|
||||
if (player.getVehicle() != null || !player.isOnGround()) { // 防止错误的坐下行为
|
||||
return 1;
|
||||
}
|
||||
|
||||
World world = player.getWorld();
|
||||
|
||||
ArmorStandEntity armorStandEntity = new ArmorStandEntity(world, player.getX(), player.getY(), player.getZ());
|
||||
((SitEntity) armorStandEntity).setSitEntity(true);
|
||||
world.spawnEntity(armorStandEntity);
|
||||
player.setSneaking(false);
|
||||
player.startRiding(armorStandEntity);
|
||||
|
||||
return 1;
|
||||
})
|
||||
);
|
||||
HatCommand.register(dispatcher);
|
||||
SitCommand.register(dispatcher);
|
||||
BotCommand.register(dispatcher);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
package com.github.zly2006.carpetslsaddition.command;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.fakes.ServerPlayerInterface;
|
||||
import carpet.helpers.EntityPlayerActionPack;
|
||||
import carpet.patches.EntityPlayerMPFake;
|
||||
import carpet.utils.Messenger;
|
||||
import com.github.zly2006.carpetslsaddition.PlayerAccess;
|
||||
import com.github.zly2006.carpetslsaddition.ServerMain;
|
||||
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 me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
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.player.PlayerEntity;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.PlayerManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Style;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Uuids;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec2f;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.GameMode;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static net.minecraft.command.CommandSource.suggestMatching;
|
||||
import static net.minecraft.server.command.CommandManager.argument;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
|
||||
public class BotCommand {
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher)
|
||||
{
|
||||
LiteralArgumentBuilder<ServerCommandSource> command = literal("bot")
|
||||
.requires(source -> source.hasPermissionLevel(4) || Permissions.check(source, "slsaddition.command.bot"))
|
||||
.then(argument("player", StringArgumentType.word())
|
||||
.suggests((c, b) -> suggestMatching(getPlayerSuggestions(c.getSource()), b))
|
||||
.then(literal("stop").executes(manipulation(EntityPlayerActionPack::stopAll)))
|
||||
.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(makeDropCommand("drop", false))
|
||||
.then(makeActionCommand("dropStack", EntityPlayerActionPack.ActionType.DROP_STACK))
|
||||
.then(makeDropCommand("dropStack", true))
|
||||
.then(makeActionCommand("swapHands", EntityPlayerActionPack.ActionType.SWAP_HANDS))
|
||||
.then(literal("hotbar")
|
||||
.then(argument("slot", IntegerArgumentType.integer(1, 9))
|
||||
.executes(c -> manipulate(c, ap -> ap.setSlot(IntegerArgumentType.getInteger(c, "slot"))))))
|
||||
.then(literal("kill").executes(BotCommand::kill))
|
||||
.then(literal("mount").executes(manipulation(ap -> ap.mount(true)))
|
||||
.then(literal("anything").executes(manipulation(ap -> ap.mount(false)))))
|
||||
.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(literal("at").then(argument("position", Vec3ArgumentType.vec3())
|
||||
.executes(c -> manipulate(c, ap -> ap.lookAt(Vec3ArgumentType.getVec3(c, "position"))))))
|
||||
.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(manipulation(ap -> ap.turn(-90, 0))))
|
||||
.then(literal("right").executes(manipulation(ap -> ap.turn(90, 0))))
|
||||
.then(literal("back").executes(manipulation(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").executes(manipulation(EntityPlayerActionPack::stopMovement))
|
||||
.then(literal("forward").executes(manipulation(ap -> ap.setForward(1))))
|
||||
.then(literal("backward").executes(manipulation(ap -> ap.setForward(-1))))
|
||||
.then(literal("left").executes(manipulation(ap -> ap.setStrafing(1))))
|
||||
.then(literal("right").executes(manipulation(ap -> ap.setStrafing(-1))))
|
||||
).then(literal("spawn").executes(BotCommand::spawn)
|
||||
.then(literal("in").requires((player) -> player.hasPermissionLevel(2))
|
||||
.then(argument("gamemode", GameModeArgumentType.gameMode())
|
||||
.executes(BotCommand::spawn)))
|
||||
.then(literal("at").then(argument("position", Vec3ArgumentType.vec3()).executes(BotCommand::spawn)
|
||||
.then(literal("facing").then(argument("direction", RotationArgumentType.rotation()).executes(BotCommand::spawn)
|
||||
.then(literal("in").then(argument("dimension", DimensionArgumentType.dimension()).executes(BotCommand::spawn)
|
||||
.then(literal("in").requires((player) -> player.hasPermissionLevel(2))
|
||||
.then(argument("gamemode", GameModeArgumentType.gameMode())
|
||||
.executes(BotCommand::spawn)
|
||||
)))
|
||||
)))
|
||||
))
|
||||
)
|
||||
);
|
||||
dispatcher.register(command);
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<ServerCommandSource> makeActionCommand(String actionName, EntityPlayerActionPack.ActionType type)
|
||||
{
|
||||
return literal(actionName)
|
||||
.executes(manipulation(ap -> ap.start(type, EntityPlayerActionPack.Action.once())))
|
||||
.then(literal("once").executes(manipulation(ap -> ap.start(type, EntityPlayerActionPack.Action.once()))))
|
||||
.then(literal("continuous").executes(manipulation(ap -> ap.start(type, EntityPlayerActionPack.Action.continuous()))))
|
||||
.then(literal("interval").then(argument("ticks", IntegerArgumentType.integer(1))
|
||||
.executes(c -> manipulate(c, ap -> ap.start(type, EntityPlayerActionPack.Action.interval(IntegerArgumentType.getInteger(c, "ticks")))))));
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<ServerCommandSource> makeDropCommand(String actionName, boolean dropAll)
|
||||
{
|
||||
return literal(actionName)
|
||||
.then(literal("all").executes(manipulation(ap -> ap.drop(-2, dropAll))))
|
||||
.then(literal("mainhand").executes(manipulation(ap -> ap.drop(-1, dropAll))))
|
||||
.then(literal("offhand").executes(manipulation(ap -> ap.drop(40, dropAll))))
|
||||
.then(argument("slot", IntegerArgumentType.integer(0, 40)).
|
||||
executes(c -> manipulate(c, ap -> ap.drop(IntegerArgumentType.getInteger(c, "slot"), dropAll))));
|
||||
}
|
||||
|
||||
private static Collection<String> getPlayerSuggestions(ServerCommandSource source)
|
||||
{
|
||||
Set<String> players = new LinkedHashSet<>(List.of("Steve", "Alex"));
|
||||
players.addAll(source.getPlayerNames());
|
||||
return players;
|
||||
}
|
||||
|
||||
private static ServerPlayerEntity getPlayer(CommandContext<ServerCommandSource> context)
|
||||
{
|
||||
String playerName = StringArgumentType.getString(context, "player");
|
||||
MinecraftServer server = context.getSource().getServer();
|
||||
return server.getPlayerManager().getPlayer(playerName);
|
||||
}
|
||||
|
||||
private static boolean cantManipulate(CommandContext<ServerCommandSource> context)
|
||||
{
|
||||
PlayerEntity player = getPlayer(context);
|
||||
ServerCommandSource source = context.getSource();
|
||||
if (player == null)
|
||||
{
|
||||
Messenger.m(source, "r Can only manipulate existing players");
|
||||
return true;
|
||||
}
|
||||
PlayerEntity sender = source.getPlayer();
|
||||
if (sender == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!source.getServer().getPlayerManager().isOperator(sender.getGameProfile()))
|
||||
{
|
||||
if (sender != player && !(player instanceof EntityPlayerMPFake))
|
||||
{
|
||||
Messenger.m(source, "r Non OP players can't control other real players");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean cantReMove(CommandContext<ServerCommandSource> context)
|
||||
{
|
||||
if (cantManipulate(context)) return true;
|
||||
PlayerEntity player = getPlayer(context);
|
||||
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<ServerCommandSource> context)
|
||||
{
|
||||
String playerName = StringArgumentType.getString(context, "player");
|
||||
MinecraftServer server = context.getSource().getServer();
|
||||
PlayerManager manager = server.getPlayerManager();
|
||||
|
||||
if (manager.getPlayer(playerName) != null)
|
||||
{
|
||||
Messenger.m(context.getSource(), "r Player ", "rb " + playerName, "r is already logged on");
|
||||
return true;
|
||||
}
|
||||
GameProfile profile = server.getUserCache().findByName(playerName).orElse(null);
|
||||
if (profile == null)
|
||||
{
|
||||
if (!CarpetSettings.allowSpawningOfflinePlayers)
|
||||
{
|
||||
Messenger.m(context.getSource(), "r Player "+playerName+" is either banned by Mojang, or auth servers are down. " +
|
||||
"Banned players can only be summoned in Singleplayer and in servers in off-line mode.");
|
||||
return true;
|
||||
} else {
|
||||
profile = new GameProfile(Uuids.getOfflinePlayerUuid(playerName), playerName);
|
||||
}
|
||||
}
|
||||
if (manager.getUserBanList().contains(profile))
|
||||
{
|
||||
Messenger.m(context.getSource(), "r Player ", "rb " + playerName, "r is banned on this server");
|
||||
return true;
|
||||
}
|
||||
if (manager.isWhitelistEnabled() && 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 kill(CommandContext<ServerCommandSource> context)
|
||||
{
|
||||
if (cantReMove(context)) return 0;
|
||||
getPlayer(context).kill();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface SupplierWithCSE<T>
|
||||
{
|
||||
T get() throws CommandSyntaxException;
|
||||
}
|
||||
|
||||
private static <T> T getArgOrDefault(BotCommand.SupplierWithCSE<T> getter, T defaultValue) throws CommandSyntaxException
|
||||
{
|
||||
try
|
||||
{
|
||||
return getter.get();
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static int spawn(CommandContext<ServerCommandSource> context) throws CommandSyntaxException
|
||||
{
|
||||
if (cantSpawn(context)) return 0;
|
||||
|
||||
ServerCommandSource source = context.getSource();
|
||||
Vec3d pos = getArgOrDefault(
|
||||
() -> Vec3ArgumentType.getVec3(context, "position"),
|
||||
source.getPosition()
|
||||
);
|
||||
Vec2f facing = getArgOrDefault(
|
||||
() -> RotationArgumentType.getRotation(context, "direction").toAbsoluteRotation(source),
|
||||
source.getRotation()
|
||||
);
|
||||
RegistryKey<World> dimType = getArgOrDefault(
|
||||
() -> DimensionArgumentType.getDimensionArgument(context, "dimension").getRegistryKey(),
|
||||
source.getWorld().getRegistryKey()
|
||||
);
|
||||
|
||||
String playerName = "bot_" + StringArgumentType.getString(context, "player");
|
||||
if (playerName.length() > maxNameLength(source.getServer()))
|
||||
{
|
||||
Messenger.m(source, "rb Player name: " + playerName + " is too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!World.isValid(BlockPos.ofFloored(pos)))
|
||||
{
|
||||
Messenger.m(source, "rb Player " + playerName + " cannot be placed outside of the world");
|
||||
return 0;
|
||||
}
|
||||
ServerPlayerEntity player = EntityPlayerMPFake.createFake(playerName, source.getServer(), pos, facing.y, facing.x, dimType, GameMode.SURVIVAL, false);
|
||||
if (player == 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 {
|
||||
((PlayerAccess) player).setDisplayName(Text.empty().append(Text.literal("[%s] ".formatted(source.getName())).setStyle(Style.EMPTY.withColor(Formatting.GRAY))).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().sendToAll(new PlayerListS2CPacket(
|
||||
PlayerListS2CPacket.Action.UPDATE_DISPLAY_NAME,
|
||||
player
|
||||
));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int maxNameLength(MinecraftServer server)
|
||||
{
|
||||
return server.getServerPort() >= 0 ? PlayerEntity.field_30643 : 40;
|
||||
}
|
||||
|
||||
private static int manipulate(CommandContext<ServerCommandSource> context, Consumer<EntityPlayerActionPack> action)
|
||||
{
|
||||
if (cantManipulate(context)) return 0;
|
||||
ServerPlayerEntity player = getPlayer(context);
|
||||
action.accept(((ServerPlayerInterface) player).getActionPack());
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static Command<ServerCommandSource> manipulation(Consumer<EntityPlayerActionPack> action)
|
||||
{
|
||||
return c -> manipulate(c, action);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.github.zly2006.carpetslsaddition.command;
|
||||
|
||||
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
public class HatCommand {
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
|
||||
dispatcher.register(CommandManager.literal("hat")
|
||||
.requires(ServerCommandSource::isExecutedByPlayer)
|
||||
.requires((commandSource) -> SLSCarpetSettings.canUseHatCommand)
|
||||
.executes(context -> {
|
||||
ServerPlayerEntity player = context.getSource().getPlayer();
|
||||
assert player != null;
|
||||
ItemStack stack = player.getMainHandStack();
|
||||
ItemStack head = player.getEquippedStack(EquipmentSlot.HEAD);
|
||||
player.equipStack(EquipmentSlot.HEAD, stack);
|
||||
player.getInventory().setStack(player.getInventory().selectedSlot, head);
|
||||
player.currentScreenHandler.syncState();
|
||||
|
||||
return 1;
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.github.zly2006.carpetslsaddition.command;
|
||||
|
||||
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
|
||||
import com.github.zly2006.carpetslsaddition.util.SitEntity;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.entity.decoration.ArmorStandEntity;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class SitCommand {
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
|
||||
dispatcher.register(CommandManager.literal("sit")
|
||||
.requires(ServerCommandSource::isExecutedByPlayer)
|
||||
.requires((commandSource) -> SLSCarpetSettings.canUseSitCommand)
|
||||
.executes(context -> {
|
||||
ServerPlayerEntity player = context.getSource().getPlayer();
|
||||
assert player != null;
|
||||
|
||||
if (player.getVehicle() != null || !player.isOnGround()) { // 防止错误的坐下行为
|
||||
return 1;
|
||||
}
|
||||
|
||||
World world = player.getWorld();
|
||||
|
||||
ArmorStandEntity armorStandEntity = new ArmorStandEntity(world, player.getX(), player.getY(), player.getZ());
|
||||
((SitEntity) armorStandEntity).setSitEntity(true);
|
||||
world.spawnEntity(armorStandEntity);
|
||||
player.setSneaking(false);
|
||||
player.startRiding(armorStandEntity);
|
||||
|
||||
return 1;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
-2
@@ -6,10 +6,8 @@ import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.FallingBlockEntity;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.predicate.entity.EntityPredicates;
|
||||
import net.minecraft.world.World;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
+17
@@ -8,6 +8,7 @@ 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;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -22,6 +23,10 @@ public abstract class MixinPlayerEntity implements PlayerAccess {
|
||||
|
||||
@Shadow public abstract void resetStat(Stat<?> stat);
|
||||
|
||||
@Shadow public abstract Text getName();
|
||||
|
||||
private Text displayName = null;
|
||||
|
||||
@Override
|
||||
public boolean holdingObsidianPickaxe() {
|
||||
ItemStack itemStack = getEquippedStack(EquipmentSlot.MAINHAND);
|
||||
@@ -29,6 +34,18 @@ public abstract class MixinPlayerEntity implements PlayerAccess {
|
||||
return compound != null && compound.contains(ITEM_NAME) && compound.getString(ITEM_NAME).equals(OBSIDIAN_PICKAXE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayName(Text name) {
|
||||
this.displayName = name;
|
||||
}
|
||||
|
||||
@Inject(method = "getDisplayName", at = @At("HEAD"), cancellable = true)
|
||||
public void injectGetDisplayName(CallbackInfoReturnable<Text> cir) {
|
||||
if (this.displayName != null) {
|
||||
cir.setReturnValue(displayName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Inject(method = "getBlockBreakingSpeed", at = @At("HEAD"), cancellable = true)
|
||||
private void onGetBlockBreakingSpeed(BlockState block, CallbackInfoReturnable<Float> cir) {
|
||||
|
||||
+20
-4
@@ -1,6 +1,7 @@
|
||||
package com.github.zly2006.carpetslsaddition.mixin.world;
|
||||
|
||||
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.block.ChainRestrictedNeighborUpdater;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -8,8 +9,10 @@ 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;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(ChainRestrictedNeighborUpdater.class)
|
||||
public class MixinChainRestrictedNeighborUpdater {
|
||||
@@ -18,12 +21,25 @@ public class MixinChainRestrictedNeighborUpdater {
|
||||
@Final
|
||||
private ArrayDeque<?> queue;
|
||||
|
||||
@Inject(method = "runQueuedUpdates", at = @At(value = "INVOKE", target = "Ljava/util/List;clear()V", ordinal = 0, shift = At.Shift.BEFORE))
|
||||
public void injectRunQueuedUpdates(CallbackInfo ci) {
|
||||
@Shadow
|
||||
@Final
|
||||
private List<?> pending;
|
||||
|
||||
@Shadow
|
||||
private int depth;
|
||||
|
||||
@Inject(method = "enqueue", at = @At(value = "INVOKE", target = "Ljava/util/ArrayDeque;push(Ljava/lang/Object;)V"), cancellable = true, locals = LocalCapture.CAPTURE_FAILSOFT)
|
||||
public void injectEnqueue(BlockPos pos, ChainRestrictedNeighborUpdater.Entry entry, CallbackInfo ci, boolean bl) {
|
||||
int maxSize = SLSCarpetSettings.maxUpdateQueueSize;
|
||||
if (maxSize > 0) {
|
||||
if (this.queue.size() > maxSize) {
|
||||
throw new OutOfMemoryError("Create by Carpet-SLS-Addition: The update queue exceeded the maximum allowed allocation of heap space set by SLS Addition!");
|
||||
if (this.depth + 1 > maxSize) {
|
||||
this.queue.clear();
|
||||
this.pending.clear();
|
||||
this.depth = 0;
|
||||
bl = true;
|
||||
Throwable e = new OutOfMemoryError("Create by Carpet-SLS-Addition: The update queue exceeded the maximum allowed allocation of heap space set by SLS Addition!");
|
||||
e.printStackTrace();
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user