(1.21.8) migrate to moj mapping

This commit is contained in:
iceBear67 committed 2026-07-17 15:09:15 +08:00
1 parent 5a51b350ad
commit a8643f7ddf
72 files changed
+862 -977

No files matched your search

+3 -3
View File
@@ -1,8 +1,8 @@
plugins {
id 'maven-publish'
id("io.freefair.lombok") version "8.6"
id("io.freefair.lombok") version "9.5.0"
id("com.gradleup.shadow") version "9.3.1"
id 'fabric-loom' version '1.10.1'
id 'fabric-loom' version '1.17-SNAPSHOT'
}
version = project.mod_version
@@ -23,7 +23,7 @@ repositories {
dependencies {
// To change the versions see the gradle.properties file1
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
mappings loom.officialMojangMappings()
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation 'me.lucko:fabric-permissions-api:0.3.1'
// Fabric API. This is technically optional, but you probably want it anyway.
+1 -1
View File
@@ -1 +1 @@
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
@@ -2,14 +2,14 @@ package io.ib67.sfcraft;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
import net.minecraft.item.Item;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.util.Identifier;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
public class SFRegistries {
public static final Registry<Item> ITEMS = FabricRegistryBuilder
.<Item>createSimple(RegistryKey.ofRegistry(Identifier.of(SFCraft.MOD_ID, "item")))
.<Item>createSimple(ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(SFCraft.MOD_ID, "item")))
.attribute(RegistryAttribute.MODDED)
.buildAndRegister();
}
@@ -3,16 +3,15 @@ package io.ib67.sfcraft.callback;
import com.mojang.datafixers.util.Either;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.ClientConnection;
import net.minecraft.core.BlockPos;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.status.ServerStatus;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerMetadata;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Player;
import java.util.function.Consumer;
import static io.ib67.sfcraft.callback.Utility.*;
@@ -39,35 +38,35 @@ public interface SFCallbacks {
l -> (p, s) -> forEach(l, i -> i.onAFKStatus(p, s)));
interface PlayerAFKCallback {
void onAFKStatus(ServerPlayerEntity player, boolean inAFK);
void onAFKStatus(ServerPlayer player, boolean inAFK);
}
interface PlayerFlyingCallback {
void onFlyingTick(PlayerEntity player, long flyingTick, boolean flying);
void onFlyingTick(Player player, long flyingTick, boolean flying);
}
interface PlayerSneakingCallback {
void onSneaking(PlayerEntity player, boolean sneak);
void onSneaking(Player player, boolean sneak);
}
interface PlayerIdlingCallback {
void onSwitchIdle(ServerPlayerEntity player, boolean afk);
void onSwitchIdle(ServerPlayer player, boolean afk);
}
interface ServerMotdCallback {
ServerMetadata onMotd(MinecraftServer server, ClientConnection connection);
ServerStatus onMotd(MinecraftServer server, Connection connection);
}
interface PlayerDeathCallback {
void onPlayerDeath(PlayerEntity player, DamageSource damageSource);
void onPlayerDeath(Player player, DamageSource damageSource);
}
interface PlayerPreLoginCallback {
void onPlayerPreLogin(String currentPlayer, ClientConnection connection, Consumer<Text> disconnect, boolean offline);
void onPlayerPreLogin(String currentPlayer, Connection connection, Consumer<Component> disconnect, boolean offline);
}
interface PlayerSleepCallback {
Either<PlayerEntity.SleepFailureReason, Unit> onPlayerSleep(PlayerEntity player, BlockPos pos);
Either<Player.BedSleepingProblem, Unit> onPlayerSleep(Player player, BlockPos pos);
}
}
@@ -1,29 +1,29 @@
package io.ib67.sfcraft.entity;
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.passive.AllayEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.world.World;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.animal.allay.Allay;
import net.minecraft.world.level.Level;
public class SFGuiderEntity extends AllayEntity {
public SFGuiderEntity(EntityType<SFGuiderEntity> entityEntityType, World world) {
public class SFGuiderEntity extends Allay {
public SFGuiderEntity(EntityType<SFGuiderEntity> entityEntityType, Level world) {
super(entityEntityType, world);
}
@Override
public Text getName() {
return Text.of("guider");
public Component getName() {
return Component.nullToEmpty("guider");
}
@Override
public void tick() {
super.tick();
var nearbyPlayer = PlayerLookup.around((ServerWorld) getWorld(), getPos(), 20D);
for (ServerPlayerEntity serverPlayerEntity : nearbyPlayer) {
this.navigation.startMovingTo(serverPlayerEntity, 2f);
var nearbyPlayer = PlayerLookup.around((ServerLevel) level(), position(), 20D);
for (ServerPlayer serverPlayerEntity : nearbyPlayer) {
this.navigation.moveTo(serverPlayerEntity, 2f);
break;
}
}
@@ -2,19 +2,18 @@ package io.ib67.sfcraft.init;
import lombok.RequiredArgsConstructor;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.text.Text;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import java.util.concurrent.atomic.AtomicBoolean;
@RequiredArgsConstructor
public class PreInitHandler {
private final AtomicBoolean initialized;
void defend(ServerPlayNetworkHandler handler, PacketSender sender, MinecraftServer server) {
void defend(ServerGamePacketListenerImpl handler, PacketSender sender, MinecraftServer server) {
if (!initialized.get()) {
handler.disconnect(Text.of("Server is initializing, please wait."));
handler.disconnect(Component.nullToEmpty("Server is initializing, please wait."));
}
}
}
@@ -4,9 +4,6 @@ import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.module.RoomModule;
import io.ib67.sfcraft.registry.RoomRegistry;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.TeleportTarget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@@ -16,31 +13,34 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.UUID;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.portal.TeleportTransition;
@Mixin(Entity.class)
public abstract class EntityMixin {
@Inject(method = "setSneaking", at = @At("HEAD"))
@Inject(method = "setShiftKeyDown", at = @At("HEAD"))
public void onSneaking(boolean sneaking, CallbackInfo ci) {
if ($this() instanceof PlayerEntity pe) {
if ($this() instanceof Player pe) {
SFCallbacks.PLAYER_SNEAKING.invoker().onSneaking(pe, sneaking);
}
}
@Shadow
public abstract UUID getUuid();
public abstract UUID getUUID();
@Inject(at = @At("HEAD"), method = "teleportTo", cancellable = true)
private void sf$redirectTeleport(TeleportTarget teleportTarget, CallbackInfoReturnable<Entity> cir) {
if (RoomModule.isVirtual(this.getUuid())) {
@Inject(at = @At("HEAD"), method = "teleport", cancellable = true)
private void sf$redirectTeleport(TeleportTransition teleportTarget, CallbackInfoReturnable<Entity> cir) {
if (RoomModule.isVirtual(this.getUUID())) {
cir.setReturnValue((Entity) (Object) this);
}
}
@Inject(at = @At("HEAD"), method = "canUsePortals", cancellable = true)
@Inject(at = @At("HEAD"), method = "canUsePortal", cancellable = true)
private void sf$disablePortal(boolean allowVehicles, CallbackInfoReturnable<Boolean> cir) {
var registry = SFCraft.getInjector().getInstance(RoomRegistry.class);
var $this = (Entity) (Object) this;
if (registry.isRoomWorld($this.getWorld().getRegistryKey())) {
if (registry.isRoomWorld($this.level().dimension())) {
cir.setReturnValue(false);
}
}
@@ -1,13 +1,13 @@
package io.ib67.sfcraft.mixin.common;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.world.entity.Mob;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(MobEntity.class)
@Mixin(Mob.class)
public abstract class MobEntityMixin {
@Shadow
public boolean cannotDespawn() {
public boolean requiresCustomPersistence() {
throw new AssertionError();
}
}
@@ -2,19 +2,19 @@ package io.ib67.sfcraft.mixin.common;
import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.mixin.common.bridge.EntityBridge;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerEntity.class)
@Mixin(Player.class)
public abstract class PlayerEntityMixin {
@Unique
private long flyTime;
@Inject(method = "tickMovement", at = @At("TAIL"))
@Inject(method = "aiStep", at = @At("TAIL"))
public void tickMovement(CallbackInfo ci) {
var eb = ((EntityBridge) $this());
if (eb.sfcraft$getFlag(EntityBridge.sfcraft$getFlyingFlagIndex())) {
@@ -28,8 +28,8 @@ public abstract class PlayerEntityMixin {
}
@Unique
public PlayerEntity $this() {
return (PlayerEntity) (Object) this;
public Player $this() {
return (Player) (Object) this;
}
}
@@ -1,17 +1,17 @@
package io.ib67.sfcraft.mixin.common.bridge;
import net.minecraft.entity.Entity;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(Entity.class)
public interface EntityBridge {
@Accessor("GLIDING_FLAG_INDEX")
@Accessor("FLAG_FALL_FLYING")
static int sfcraft$getFlyingFlagIndex() {
throw new AssertionError();
}
@Invoker("getFlag")
@Invoker("getSharedFlag")
boolean sfcraft$getFlag(int index);
}
@@ -1,12 +1,12 @@
package io.ib67.sfcraft.mixin.common.bridge;
import net.minecraft.item.Item;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.core.Holder;
import net.minecraft.world.item.Item;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Item.class)
public interface ItemBridge {
@Accessor
void setRegistryEntry(RegistryEntry.Reference<Item> value);
void setBuiltInRegistryHolder(Holder.Reference<Item> value);
}
@@ -1,12 +1,12 @@
package io.ib67.sfcraft.mixin.common.bridge;
import net.minecraft.server.world.ChunkLevelManager;
import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.server.level.DistanceManager;
import net.minecraft.server.level.ServerChunkCache;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerChunkManager.class)
@Mixin(ServerChunkCache.class)
public interface ServerChunkManagerBridge {
@Accessor("levelManager")
ChunkLevelManager getLevelManager();
@Accessor("distanceManager")
DistanceManager getLevelManager();
}
@@ -1,10 +1,10 @@
package io.ib67.sfcraft.mixin.common.bridge;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.level.ServerPlayer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerPlayerEntity.class)
@Mixin(ServerPlayer.class)
public interface ServerPlayerBridge {
@Accessor
void setLastActionTime(long time);
@@ -1,12 +1,12 @@
package io.ib67.sfcraft.mixin.common.bridge;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.server.world.SleepManager;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.players.SleepStatus;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerWorld.class)
@Mixin(ServerLevel.class)
public interface ServerWorldBridge {
@Accessor
SleepManager getSleepManager();
SleepStatus getDEEPSLATE_BRICKS();
}
@@ -1,17 +1,17 @@
package io.ib67.sfcraft.mixin.common.fixes;
import io.ib67.sfcraft.mixin.common.MobEntityMixin;
import net.minecraft.entity.mob.EndermanEntity;
import net.minecraft.world.entity.monster.EnderMan;
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.callback.CallbackInfoReturnable;
@Mixin(EndermanEntity.class)
@Mixin(EnderMan.class)
public abstract class EndermanEntityMixin extends MobEntityMixin {
@Inject(at = @At("HEAD"), method = "cannotDespawn", cancellable = true)
@Inject(at = @At("HEAD"), method = "requiresCustomPersistence", cancellable = true)
private void sf$cannotDespawn(CallbackInfoReturnable<Boolean> cir) {
cir.setReturnValue(super.cannotDespawn());
cir.setReturnValue(super.requiresCustomPersistence());
}
}
@@ -1,7 +1,7 @@
package io.ib67.sfcraft.mixin.common.fixes;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.passive.BeeEntity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.animal.Bee;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -10,9 +10,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin {
@Inject(method = "tickCramming", at=@At("HEAD"), cancellable = true)
@Inject(method = "pushEntities", at=@At("HEAD"), cancellable = true)
private void sf$disableBeeCramming(CallbackInfo ci) {
if($this() instanceof BeeEntity) {
if($this() instanceof Bee) {
ci.cancel();
}
}
@@ -1,63 +0,0 @@
package io.ib67.sfcraft.mixin.common.fixes;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LazyEntityReference;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.server.world.ServerWorld;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.UUID;
@Mixin(ProjectileEntity.class)
public class ProjectileEntityMixin {
@Shadow
@Nullable
protected LazyEntityReference<Entity> owner;
@Unique
private boolean isPlayer;
@Inject(at = @At("HEAD"), method = "setOwner(Lnet/minecraft/entity/Entity;)V")
private void setOwner(@Nullable Entity owner, CallbackInfo ci) {
isPlayer = owner instanceof PlayerEntity;
}
@Inject(at=@At("HEAD"), method = "setOwner(Lnet/minecraft/entity/LazyEntityReference;)V")
private void setOwner(@Nullable LazyEntityReference<Entity> owner, CallbackInfo ci) {
isPlayer = LazyEntityReference.resolve(owner, $().getWorld(), Entity.class) instanceof PlayerEntity;
}
/**
* @reason Implement the logic correctly.
* @author icybear
*/
@Overwrite
public @Nullable Entity getOwner() {
if (this.owner != null) {
var ownerUuid = this.owner.getUuid();
var server = $().getWorld().getServer();
if (server == null) {
return null;
}
if (isPlayer) {
return server.getPlayerManager().getPlayer(ownerUuid);
} else {
return LazyEntityReference.resolve(this.owner, $().getWorld(), Entity.class);
}
}
return null;
}
@Unique
private ProjectileEntity $() {
return (ProjectileEntity) (Object) this;
}
}
@@ -1,25 +1,25 @@
package io.ib67.sfcraft.mixin.server;
import io.ib67.sfcraft.mixin.common.bridge.ServerWorldBridge;
import net.minecraft.block.AbstractFurnaceBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.entity.AbstractFurnaceBlockEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.AbstractFurnaceBlock;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Unique;
@Mixin(AbstractFurnaceBlock.class)
public abstract class AbstractFurnaceBlockMixin extends BlockWithEntity {
protected AbstractFurnaceBlockMixin(Settings settings) {
public abstract class AbstractFurnaceBlockMixin extends BaseEntityBlock {
protected AbstractFurnaceBlockMixin(Properties settings) {
super(settings);
}
@@ -29,20 +29,20 @@ public abstract class AbstractFurnaceBlockMixin extends BlockWithEntity {
*/
@Nullable
@Overwrite
public static <T extends BlockEntity> BlockEntityTicker<T> validateTicker(
World world, BlockEntityType<T> givenType, BlockEntityType<? extends AbstractFurnaceBlockEntity> expectedType
public static <T extends BlockEntity> BlockEntityTicker<T> createFurnaceTicker(
Level world, BlockEntityType<T> givenType, BlockEntityType<? extends AbstractFurnaceBlockEntity> expectedType
) {
return world instanceof ServerWorld sw ? BlockWithEntity.validateTicker(givenType, expectedType, AbstractFurnaceBlockMixin::tickMultiple) : null;
return world instanceof ServerLevel sw ? BaseEntityBlock.createTickerHelper(givenType, expectedType, AbstractFurnaceBlockMixin::tickMultiple) : null;
}
@Unique
private static <E extends AbstractFurnaceBlockEntity> void tickMultiple(World _world, BlockPos pos, BlockState state, E blockEntity) {
var world = (ServerWorld) _world;
AbstractFurnaceBlockEntity.tick(world, pos, state, blockEntity);
int i = world.getGameRules().getInt(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
if (((ServerWorldBridge) world).getSleepManager().canSkipNight(i)) {
AbstractFurnaceBlockEntity.tick(world, pos, state, blockEntity); //todo: config support?
AbstractFurnaceBlockEntity.tick(world, pos, state, blockEntity);
private static <E extends AbstractFurnaceBlockEntity> void tickMultiple(Level _world, BlockPos pos, BlockState state, E blockEntity) {
var world = (ServerLevel) _world;
AbstractFurnaceBlockEntity.serverTick(world, pos, state, blockEntity);
int i = world.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
if (((ServerWorldBridge) world).getDEEPSLATE_BRICKS().areEnoughSleeping(i)) {
AbstractFurnaceBlockEntity.serverTick(world, pos, state, blockEntity); //todo: config support?
AbstractFurnaceBlockEntity.serverTick(world, pos, state, blockEntity);
}
}
}
@@ -2,8 +2,6 @@ package io.ib67.sfcraft.mixin.server;
import io.ib67.sfcraft.util.Helper;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.network.QueryableServer;
import net.minecraft.network.handler.LegacyQueryHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -14,6 +12,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Locale;
import net.minecraft.server.ServerInfo;
import net.minecraft.server.network.LegacyQueryHandler;
@Mixin(LegacyQueryHandler.class)
public class LegacyQueryHandlerMixin {
@@ -25,17 +25,17 @@ public class LegacyQueryHandlerMixin {
address = ctx.channel().remoteAddress();
}
@Redirect(method = "channelRead", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/handler/LegacyQueryHandler;getResponse(Lnet/minecraft/network/QueryableServer;)Ljava/lang/String;"))
private String getResponse(QueryableServer server) {
var version = server.getVersion();
@Redirect(method = "channelRead", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/LegacyQueryHandler;createVersion1Response(Lnet/minecraft/server/ServerInfo;)Ljava/lang/String;"))
private String getResponse(ServerInfo server) {
var version = server.getServerVersion();
return String.format(
Locale.ROOT,
"§1\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d",
127,
version,
server.getServerMotd(),
server.getCurrentPlayerCount(),
server.getMaxPlayerCount()
server.getMotd(),
server.getPlayerCount(),
server.getMaxPlayers()
);
}
}
@@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(MinecraftServer.class)
public abstract class MinecraftServerMixin {
@ModifyConstant(method = "tickWorlds", constant = @Constant(intValue = 20))
@ModifyConstant(method = "tickChildren", constant = @Constant(intValue = 20))
private int speedUpAtNight(int constant) {
if (MixinHelper.spedUp) {
return 2;
@@ -2,10 +2,10 @@ package io.ib67.sfcraft.mixin.server;
import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.callback.SFCallbacks;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.status.ServerStatus;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerMetadata;
import net.minecraft.server.network.ServerHandshakeNetworkHandler;
import net.minecraft.server.network.ServerHandshakePacketListenerImpl;
import org.spongepowered.asm.mixin.Debug;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -13,17 +13,17 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ServerHandshakeNetworkHandler.class)
@Mixin(ServerHandshakePacketListenerImpl.class)
public abstract class ServerHandshakeNetworkHandlerMixin {
@Shadow
@Final
private ClientConnection connection;
private Connection connection;
@Redirect(method = "onHandshake", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getServerMetadata()Lnet/minecraft/server/ServerMetadata;"))
public ServerMetadata getMetadata(MinecraftServer instance) {
@Redirect(method = "handleIntention", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getStatus()Lnet/minecraft/network/protocol/status/ServerStatus;"))
public ServerStatus getMetadata(MinecraftServer instance) {
var result = SFCallbacks.MOTD.invoker().onMotd(instance,connection);
if(result == null) {
return instance.getServerMetadata();
return instance.getStatus();
}else{
return result;
}
@@ -3,13 +3,12 @@ package io.ib67.sfcraft.mixin.server;
import io.ib67.sfcraft.callback.SFCallbacks;
import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalServerChannel;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.c2s.login.LoginHelloC2SPacket;
import net.minecraft.core.UUIDUtil;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.login.ServerboundHelloPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerLoginNetworkHandler;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Uuids;
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -21,10 +20,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.net.InetSocketAddress;
@Mixin(ServerLoginNetworkHandler.class)
@Mixin(ServerLoginPacketListenerImpl.class)
public abstract class ServerLoginNetworkHandlerMixin {
@Shadow
public abstract void disconnect(Text reason);
public abstract void disconnect(Component reason);
@Shadow
@Final
@@ -32,23 +31,23 @@ public abstract class ServerLoginNetworkHandlerMixin {
@Unique
private String currentPlayer;
@Inject(method = "onHello", at = @At("HEAD"))
public void onHello(LoginHelloC2SPacket packet, CallbackInfo ci) {
@Inject(method = "handleHello", at = @At("HEAD"))
public void onHello(ServerboundHelloPacket packet, CallbackInfo ci) {
currentPlayer = packet.name();
}
@Redirect(method = "onHello", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;isLocal()Z"))
public boolean isLocal(ClientConnection connection) {
if (!(connection.getAddress() instanceof InetSocketAddress)) {
return connection.isLocal(); // 碰上真 isLocal 了
@Redirect(method = "handleHello", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/Connection;isMemoryConnection()Z"))
public boolean isLocal(Connection connection) {
if (!(connection.getRemoteAddress() instanceof InetSocketAddress)) {
return connection.isMemoryConnection(); // 碰上真 isLocal 了
}
var offlineProfile = Uuids.getOfflinePlayerProfile(currentPlayer);
var offlineProfile = UUIDUtil.createOfflineProfile(currentPlayer);
boolean _r;
if (server.getUserCache() != null) {
_r = server.getUserCache().getByUuid(offlineProfile.getId()).isPresent();
if (server.getProfileCache() != null) {
_r = server.getProfileCache().get(offlineProfile.getId()).isPresent();
}else{
var wl = server.getPlayerManager().getWhitelist();
_r = wl.isAllowed(offlineProfile);
var wl = server.getPlayerList().getWhiteList();
_r = wl.isWhiteListed(offlineProfile);
}
SFCallbacks.PRE_LOGIN.invoker().onPlayerPreLogin(currentPlayer, connection, this::disconnect, _r);
return _r;
@@ -4,39 +4,39 @@ import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.mixin.common.bridge.ServerPlayerBridge;
import io.ib67.sfcraft.registry.chat.SimpleMessageDecorator;
import net.minecraft.network.DisconnectionInfo;
import net.minecraft.network.message.MessageDecorator;
import net.minecraft.network.DisconnectionDetails;
import net.minecraft.network.chat.ChatDecorator;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ServerPlayNetworkHandler.class)
@Mixin(ServerGamePacketListenerImpl.class)
public abstract class ServerPlayNetworkHandlerMixin {
@Shadow
public ServerPlayerEntity player;
public ServerPlayer player;
/**
* @author icybear
* @reason small method, overwrite to reduce overhead
*/
@Redirect(method = "method_44900", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getMessageDecorator()Lnet/minecraft/network/message/MessageDecorator;"))
public MessageDecorator getMessageDecorator(MinecraftServer instance) {
@Redirect(method = "method_44900", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getChatDecorator()Lnet/minecraft/network/chat/ChatDecorator;"))
public ChatDecorator getMessageDecorator(MinecraftServer instance) {
return SFCraft.getInjector().getInstance(SimpleMessageDecorator.class);
}
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;disconnect(Lnet/minecraft/text/Text;)V", ordinal = 2))
public void onPlayerIdling(ServerPlayNetworkHandler instance, Text text) {
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;disconnect(Lnet/minecraft/network/chat/Component;)V", ordinal = 2))
public void onPlayerIdling(ServerGamePacketListenerImpl instance, Component text) {
((ServerPlayerBridge) instance.player).setLastActionTime(Long.MAX_VALUE);
SFCallbacks.PLAYER_IDLE.invoker().onSwitchIdle(instance.player, true);
}
@Inject(method = "onDisconnected", at = @At("HEAD"))
public void onDisconnected(DisconnectionInfo instance, CallbackInfo ci) {
player.updateLastActionTime();
@Inject(method = "onDisconnect", at = @At("HEAD"))
public void onDisconnected(DisconnectionDetails instance, CallbackInfo ci) {
player.resetLastActionTime();
}
}
@@ -2,11 +2,11 @@ package io.ib67.sfcraft.mixin.server;
import com.mojang.datafixers.util.Either;
import io.ib67.sfcraft.callback.SFCallbacks;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -14,28 +14,28 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ServerPlayerEntity.class)
@Mixin(ServerPlayer.class)
public class ServerPlayerEntityMixin {
@Shadow
private long lastActionTime;
@Inject(method = "onDeath", at = @At("TAIL"))
@Inject(method = "die", at = @At("TAIL"))
public void onDeath(DamageSource damageSource, CallbackInfo ci) {
SFCallbacks.PLAYER_DEATH.invoker().onPlayerDeath((ServerPlayerEntity) (Object) this, damageSource);
SFCallbacks.PLAYER_DEATH.invoker().onPlayerDeath((ServerPlayer) (Object) this, damageSource);
}
@Inject(method = "trySleep", at = @At("HEAD"), cancellable = true)
public void onSleep(BlockPos pos, CallbackInfoReturnable<Either<PlayerEntity.SleepFailureReason, Unit>> cir) {
var result = SFCallbacks.PLAYER_SLEEP.invoker().onPlayerSleep((ServerPlayerEntity) (Object) this, pos);
@Inject(method = "startSleepInBed", at = @At("HEAD"), cancellable = true)
public void onSleep(BlockPos pos, CallbackInfoReturnable<Either<Player.BedSleepingProblem, Unit>> cir) {
var result = SFCallbacks.PLAYER_SLEEP.invoker().onPlayerSleep((ServerPlayer) (Object) this, pos);
if (result.left().isPresent()) {
cir.setReturnValue(result);
}
}
@Inject(method = "updateLastActionTime", at = @At("HEAD"))
@Inject(method = "resetLastActionTime", at = @At("HEAD"))
public void leaveAFK(CallbackInfo ci) {
if (lastActionTime == Long.MAX_VALUE) {
SFCallbacks.PLAYER_IDLE.invoker().onSwitchIdle((ServerPlayerEntity) (Object) this, false);
SFCallbacks.PLAYER_IDLE.invoker().onSwitchIdle((ServerPlayer) (Object) this, false);
}
}
}
@@ -4,10 +4,8 @@ import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.mixin.common.bridge.ServerWorldBridge;
import io.ib67.sfcraft.module.RoomModule;
import io.ib67.sfcraft.util.MixinHelper;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.GameRules;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -15,12 +13,12 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ServerWorld.class)
@Mixin(ServerLevel.class)
public abstract class ServerWorldMixin {
@ModifyArg(method = "tickTime", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;setTimeOfDay(J)V"))
@ModifyArg(method = "tickTime", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;setDayTime(J)V"))
public long setTimeOfDay(long timeOfDay) {
int i = ((ServerWorld) (Object) this).getGameRules().getInt(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
if (((ServerWorldBridge) this).getSleepManager().canSkipNight(i)) {
int i = ((ServerLevel) (Object) this).getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
if (((ServerWorldBridge) this).getDEEPSLATE_BRICKS().areEnoughSleeping(i)) {
MixinHelper.spedUp = true;
return timeOfDay + 10;
}
@@ -1,24 +1,24 @@
package io.ib67.sfcraft.mixin.server;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.SleepManager;
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.callback.CallbackInfoReturnable;
import java.util.List;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.SleepStatus;
@Mixin(SleepManager.class)
@Mixin(SleepStatus.class)
public abstract class SleepManagerMixin {
@Inject(method = "canResetTime", at = @At("HEAD"), cancellable = true)
public void canResetTime(int percentage, List<ServerPlayerEntity> players, CallbackInfoReturnable<Boolean> cir) {
@Inject(method = "areEnoughDeepSleeping", at = @At("HEAD"), cancellable = true)
public void canResetTime(int percentage, List<ServerPlayer> players, CallbackInfoReturnable<Boolean> cir) {
if (players.isEmpty()) {
cir.setReturnValue(false);
return;
}
var world = players.getFirst().getWorld();
if (world.getTimeOfDay() % 24000 >= 12544) {
var world = players.getFirst().level();
if (world.getDayTime() % 24000 >= 12544) {
if(!world.isRaining()){
cir.setReturnValue(false);
}
@@ -3,16 +3,16 @@ package io.ib67.sfcraft.mixin.server.subserver;
import com.mojang.authlib.GameProfile;
import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.module.RoomModule;
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.UUID;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.server.level.ServerPlayer;
@Mixin(PlayerListS2CPacket.Entry.class)
@Mixin(ClientboundPlayerInfoUpdatePacket.Entry.class)
public class PlayerListS2CPacket$EntryMixin {
@Unique
private static final byte[] lock = new byte[0];
@@ -31,11 +31,11 @@ public class PlayerListS2CPacket$EntryMixin {
return module;
}
@Redirect(method = "<init>(Lnet/minecraft/server/network/ServerPlayerEntity;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;getGameProfile()Lcom/mojang/authlib/GameProfile;"))
private static GameProfile sf$redirectGameProfileForRoom(ServerPlayerEntity instance) {
if (!RoomModule.isVirtual(instance.getUuid())) {
@Redirect(method = "<init>(Lnet/minecraft/server/level/ServerPlayer;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;getGameProfile()Lcom/mojang/authlib/GameProfile;"))
private static GameProfile sf$redirectGameProfileForRoom(ServerPlayer instance) {
if (!RoomModule.isVirtual(instance.getUUID())) {
return instance.getGameProfile();
}
return getModule().devirtualize(instance.getUuid());
return getModule().devirtualize(instance.getUUID());
}
}
@@ -5,13 +5,6 @@ import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.mixin.common.bridge.ServerChunkManagerBridge;
import io.ib67.sfcraft.module.RoomModule;
import io.ib67.sfcraft.registry.RoomRegistry;
import net.minecraft.entity.Entity;
import net.minecraft.network.ClientConnection;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ConnectedClientData;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.GlobalPos;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -24,56 +17,63 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.net.SocketAddress;
import java.util.Set;
import net.minecraft.core.GlobalPos;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.CommonListenerCookie;
import net.minecraft.server.players.PlayerList;
import net.minecraft.world.entity.Entity;
@Mixin(PlayerManager.class)
@Mixin(PlayerList.class)
public abstract class PlayerManagerMixin {
@Shadow
@Final
private static Logger LOGGER;
@Inject(method = "onPlayerConnect", at = @At("TAIL"))
public void sf$updateSession(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) {
@Inject(method = "placeNewPlayer", at = @At("TAIL"))
public void sf$updateSession(Connection connection, ServerPlayer player, CommonListenerCookie clientData, CallbackInfo ci) {
var registry = SFCraft.getInjector().getInstance(RoomRegistry.class);
var room = registry.getRoomBy(player.getUuid());
var room = registry.getRoomBy(player.getUUID());
if (room != null) {
var spawn = room.getSpawnPosition();
if(player.getWorld().getRegistryKey() != spawn.dimension()){
if(player.level().dimension() != spawn.dimension()){
teleportToRoom(player, spawn);
}
LOGGER.info("Room player joined as " + player.getName().getLiteralString() + "/" + player.getUuid());
LOGGER.info("Room player joined as " + player.getName().tryCollapseToString() + "/" + player.getUUID());
room.onPlayerJoin(player);
}
}
@Inject(method = "respawnPlayer", at = @At("TAIL"))
public void sf$updateSession(ServerPlayerEntity player, boolean alive, Entity.RemovalReason removalReason, CallbackInfoReturnable<ServerPlayerEntity> cir) {
@Inject(method = "respawn", at = @At("TAIL"))
public void sf$updateSession(ServerPlayer player, boolean alive, Entity.RemovalReason removalReason, CallbackInfoReturnable<ServerPlayer> cir) {
var registry = SFCraft.getInjector().getInstance(RoomRegistry.class);
var room = registry.getRoomBy(player.getUuid());
var room = registry.getRoomBy(player.getUUID());
if (!alive && room != null) {
var spawn = room.getSpawnPosition();
teleportToRoom(cir.getReturnValue(), spawn);
}
}
@Inject(method = "checkCanJoin", cancellable = true, at = @At("HEAD"))
private void sf$bypassJoinLimit(SocketAddress address, GameProfile profile, CallbackInfoReturnable<Text> cir) {
@Inject(method = "canPlayerLogin", cancellable = true, at = @At("HEAD"))
private void sf$bypassJoinLimit(SocketAddress address, GameProfile profile, CallbackInfoReturnable<Component> cir) {
if (RoomModule.isVirtual(profile.getId())) cir.setReturnValue(null);
}
@Unique
private void teleportToRoom(ServerPlayerEntity player, GlobalPos spawn) {
var world = player.getServer().getWorld(spawn.dimension());
private void teleportToRoom(ServerPlayer player, GlobalPos spawn) {
var world = player.getServer().getLevel(spawn.dimension());
var pos = spawn.pos();
((ServerChunkManagerBridge)world.getChunkManager()).getLevelManager().handleChunkEnter(player.getWatchedSection(), player);
player.teleport(world, pos.getX(), pos.getY(), pos.getZ(), Set.of(), 0, 0, true);
((ServerChunkManagerBridge)world.getChunkSource()).getLevelManager().addPlayer(player.getLastSectionPos(), player);
player.teleportTo(world, pos.getX(), pos.getY(), pos.getZ(), Set.of(), 0, 0, true);
}
@Inject(method = "remove", at = @At("HEAD"))
public void sf$removePlayers(ServerPlayerEntity instance, CallbackInfo ci) {
public void sf$removePlayers(ServerPlayer instance, CallbackInfo ci) {
var registry = SFCraft.getInjector().getInstance(RoomRegistry.class);
var room = registry.getRoomBy(instance.getUuid());
var room = registry.getRoomBy(instance.getUUID());
if (room != null) {
room.onPlayerQuit(instance);
}
@@ -3,10 +3,6 @@ package io.ib67.sfcraft.mixin.server.subserver;
import com.mojang.datafixers.DataFixer;
import io.ib67.sfcraft.module.RoomModule;
import io.ib67.sfcraft.util.Helper;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.WorldSavePath;
import net.minecraft.world.PlayerSaveHandler;
import net.minecraft.world.level.storage.LevelStorage;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -17,36 +13,40 @@ import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.io.File;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.storage.LevelResource;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PlayerDataStorage;
@Mixin(PlayerSaveHandler.class)
@Mixin(PlayerDataStorage.class)
public class PlayerSaveHandlerMixin {
@Shadow
@Final
private File playerDataDir;
private File playerDir;
@Unique
private File virtualPlayerFolder;
@Inject(at = @At("TAIL"), method = "<init>")
private void sf$createVirtualPlayerDataFolder(LevelStorage.Session session, DataFixer dataFixer, CallbackInfo ci) {
this.virtualPlayerFolder = session.getDirectory(WorldSavePath.PLAYERDATA).resolve("in_rooms").toFile();
private void sf$createVirtualPlayerDataFolder(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, CallbackInfo ci) {
this.virtualPlayerFolder = session.getLevelPath(LevelResource.PLAYER_DATA_DIR).resolve("in_rooms").toFile();
this.virtualPlayerFolder.mkdirs();
}
@Redirect(at = @At(value = "FIELD", target = "Lnet/minecraft/world/PlayerSaveHandler;playerDataDir:Ljava/io/File;"), method = "savePlayerData")
private File sf$getPlayerDataFolder(PlayerSaveHandler instance, PlayerEntity entity) {
if (RoomModule.isVirtual(entity.getUuid())) {
@Redirect(at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/storage/PlayerDataStorage;playerDir:Ljava/io/File;"), method = "save")
private File sf$getPlayerDataFolder(PlayerDataStorage instance, Player entity) {
if (RoomModule.isVirtual(entity.getUUID())) {
return virtualPlayerFolder;
} else {
return this.playerDataDir;
return this.playerDir;
}
}
@Redirect(at = @At(value = "FIELD", target = "Lnet/minecraft/world/PlayerSaveHandler;playerDataDir:Ljava/io/File;"), method = "loadPlayerData(Lnet/minecraft/entity/player/PlayerEntity;Ljava/lang/String;)Ljava/util/Optional;")
private File sf$saveGetPlayerFolder(PlayerSaveHandler instance, PlayerEntity player) {
if (RoomModule.isVirtual(player.getUuid())) {
@Redirect(at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/storage/PlayerDataStorage;playerDir:Ljava/io/File;"), method = "load(Lnet/minecraft/world/entity/player/Player;Ljava/lang/String;)Ljava/util/Optional;")
private File sf$saveGetPlayerFolder(PlayerDataStorage instance, Player player) {
if (RoomModule.isVirtual(player.getUUID())) {
return virtualPlayerFolder;
} else {
return this.playerDataDir;
return this.playerDir;
}
}
}
@@ -8,12 +8,6 @@ import io.ib67.sfcraft.registry.RoomRegistry;
import io.ib67.sfcraft.room.CookieState;
import io.ib67.sfcraft.room.RequestedRoom;
import io.netty.buffer.Unpooled;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.c2s.common.CookieResponseC2SPacket;
import net.minecraft.network.packet.s2c.common.CookieRequestS2CPacket;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerLoginNetworkHandler;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
@@ -26,26 +20,32 @@ import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.net.SocketAddress;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.cookie.ClientboundCookieRequestPacket;
import net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket;
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
import net.minecraft.server.players.PlayerList;
import static io.ib67.sfcraft.room.CookieState.*;
import static io.ib67.sfcraft.room.RoomTeleporter.ROOM_COOKIE;
@Mixin(ServerLoginNetworkHandler.class)
@Mixin(ServerLoginPacketListenerImpl.class)
public abstract class ServerLoginNetworkHandlerMixin {
@Shadow
abstract void startVerify(GameProfile profile);
abstract void startClientVerification(GameProfile profile);
@Shadow
private @Nullable GameProfile profile;
private @Nullable GameProfile authenticatedProfile;
@Shadow
@Final
private boolean transferred;
@Shadow
@Final
private ClientConnection connection;
private Connection connection;
@Shadow
public abstract void disconnect(Text reason);
public abstract void disconnect(Component reason);
@Shadow
@Final
@@ -61,12 +61,12 @@ public abstract class ServerLoginNetworkHandlerMixin {
void restoreVerify(CallbackInfo ci) {
if ((sf$cookieState == SENT && sf$room != null) || (clean && sf$cookieState != DONE)) {
sf$cookieState = CookieState.RECV;
startVerify(this.profile);
startClientVerification(this.authenticatedProfile);
}
}
@Inject(method = "onCookieResponse", at = @At("HEAD"), cancellable = true)
private void sf$onRoomId(CookieResponseC2SPacket packet, CallbackInfo ci) {
@Inject(method = "handleCookieResponse", at = @At("HEAD"), cancellable = true)
private void sf$onRoomId(ServerboundCookieResponsePacket packet, CallbackInfo ci) {
if (packet.key().equals(ROOM_COOKIE)) {
if (sf$cookieState != SENT) throw new IllegalStateException("Protocol error");
var roomSvc = SFCraft.getInjector().getInstance(RoomModule.class);
@@ -74,7 +74,7 @@ public abstract class ServerLoginNetworkHandlerMixin {
try {
if (packet.payload().length == 0) {
// clean reconnect.
LOGGER.info("Player " + profile.getName() + " requested a clean reconnection");
LOGGER.info("Player " + authenticatedProfile.getName() + " requested a clean reconnection");
clean = true;
ci.cancel();
return;
@@ -83,7 +83,7 @@ public abstract class ServerLoginNetworkHandlerMixin {
this.sf$room = RequestedRoom.PACKET_CODEC.decode(Unpooled.wrappedBuffer(sign.data()));
} catch (Exception t) {
LOGGER.error("Failed to read cookie: {0}", t);
this.disconnect(Text.of("Protocol error."));
this.disconnect(Component.nullToEmpty("Protocol error."));
ci.cancel();
return;
}
@@ -91,29 +91,29 @@ public abstract class ServerLoginNetworkHandlerMixin {
ci.cancel();
}
@Inject(method = "startVerify", at = @At("HEAD"), cancellable = true)
@Inject(method = "startClientVerification", at = @At("HEAD"), cancellable = true)
void sf$makeTransferPlayerProfile(GameProfile profile, CallbackInfo ci) {
if (transferred && !clean) {
switch (this.sf$cookieState) {
case NOT_SENT -> {
this.profile = profile;
this.connection.send(new CookieRequestS2CPacket(ROOM_COOKIE));
this.authenticatedProfile = profile;
this.connection.send(new ClientboundCookieRequestPacket(ROOM_COOKIE));
this.sf$cookieState = SENT;
}
case RECV -> {
var ssr = SFCraft.getInjector().getInstance(RoomRegistry.class);
var room = ssr.getRoomBy(sf$room.identifier());
if (room != null) {
this.profile = new GameProfile(sf$room.profileUuid(), sf$room.profileName());
this.authenticatedProfile = new GameProfile(sf$room.profileUuid(), sf$room.profileName());
var session = room.getPlayerManager().getSessionBy(sf$room.profileUuid());
if (session == null) {
disconnect(Text.of("Session isn't exists."));
disconnect(Component.nullToEmpty("Session isn't exists."));
ci.cancel();
return;
}
session.onPlayerLogin(sf$room.profileUuid());
this.sf$cookieState = DONE;
this.startVerify(this.profile);
this.startClientVerification(this.authenticatedProfile);
ci.cancel();
return;
}
@@ -128,9 +128,9 @@ public abstract class ServerLoginNetworkHandlerMixin {
}
}
@Redirect(method = "tickVerify", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;checkCanJoin(Ljava/net/SocketAddress;Lcom/mojang/authlib/GameProfile;)Lnet/minecraft/text/Text;"))
private Text sf$bypassRoomPlayer(PlayerManager instance, SocketAddress address, GameProfile profile) {
@Redirect(method = "verifyLoginAndFinishConnectionSetup", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;canPlayerLogin(Ljava/net/SocketAddress;Lcom/mojang/authlib/GameProfile;)Lnet/minecraft/network/chat/Component;"))
private Component sf$bypassRoomPlayer(PlayerList instance, SocketAddress address, GameProfile profile) {
if (sf$cookieState == DONE) return null;
return instance.checkCanJoin(address, profile);
return instance.canPlayerLogin(address, profile);
}
}
@@ -2,9 +2,6 @@ package io.ib67.sfcraft.mixin.server.subserver;
import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.registry.RoomRegistry;
import net.minecraft.network.packet.s2c.play.PositionFlag;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -12,16 +9,19 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Set;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Relative;
@Mixin(ServerPlayerEntity.class)
@Mixin(ServerPlayer.class)
public abstract class ServerPlayerEntityMixin {
//todo test this
//todo fix playground operate players in main world
@Inject(at=@At("HEAD"), method = "teleport(Lnet/minecraft/server/world/ServerWorld;DDDLjava/util/Set;FFZ)Z")
public void sf$interceptTeleport(ServerWorld world, double destX, double destY, double destZ, Set<PositionFlag> flags, float yaw, float pitch, boolean resetCamera, CallbackInfoReturnable<Boolean> cir) {
var room = roomRegistry().getRoomBy($this().getUuid());
@Inject(at=@At("HEAD"), method = "teleportTo(Lnet/minecraft/server/level/ServerLevel;DDDLjava/util/Set;FFZ)Z")
public void sf$interceptTeleport(ServerLevel world, double destX, double destY, double destZ, Set<Relative> flags, float yaw, float pitch, boolean resetCamera, CallbackInfoReturnable<Boolean> cir) {
var room = roomRegistry().getRoomBy($this().getUUID());
if (room != null) {
if (world.getRegistryKey() != room.getSpawnPosition().dimension()) {
if (world.dimension() != room.getSpawnPosition().dimension()) {
cir.setReturnValue(false);
}
}
@@ -31,7 +31,7 @@ public abstract class ServerPlayerEntityMixin {
return SFCraft.getInjector().getInstance(RoomRegistry.class);
}
private ServerPlayerEntity $this() {
return (ServerPlayerEntity) (Object) this;
private ServerPlayer $this() {
return (ServerPlayer) (Object) this;
}
}
@@ -6,9 +6,9 @@ import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import io.ib67.sfcraft.module.chat.ChatPrefix;
import io.ib67.sfcraft.module.chat.ChatPrefixModule;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.CommonColors;
public class AFKModule extends ServerModule {
@Inject
@@ -21,7 +21,7 @@ public class AFKModule extends ServerModule {
public void onInitialize() {
SFCallbacks.PLAYER_IDLE.register(this::onAFK);
prefix = new ChatPrefix(
Text.literal("[挂机] ").withColor(Colors.LIGHT_GRAY),
Component.literal("[挂机] ").withColor(CommonColors.LIGHT_GRAY),
"afk",
true,
10
@@ -29,7 +29,7 @@ public class AFKModule extends ServerModule {
}
private void onAFK(ServerPlayerEntity player, boolean afk) {
private void onAFK(ServerPlayer player, boolean afk) {
if (afk) {
enAFK(player);
} else {
@@ -37,20 +37,20 @@ public class AFKModule extends ServerModule {
}
}
private void enAFK(ServerPlayerEntity player) {
private void enAFK(ServerPlayer player) {
chatPrefixModule.applyPrefix(player, prefix);
player.getServer().getPlayerManager().broadcast(
Text.literal(" * " + player.getName().getLiteralString() + " 正在挂机.").withColor(Colors.LIGHT_GRAY),
player.getServer().getPlayerList().broadcastSystemMessage(
Component.literal(" * " + player.getName().tryCollapseToString() + " 正在挂机.").withColor(CommonColors.LIGHT_GRAY),
false
);
SFCallbacks.PLAYER_AFK.invoker().onAFKStatus(player, true);
}
public void deAFK(ServerPlayerEntity player) {
String playerName = player.getName().getLiteralString();
public void deAFK(ServerPlayer player) {
String playerName = player.getName().tryCollapseToString();
chatPrefixModule.removePrefix(player, prefix);
player.getServer().getPlayerManager().broadcast(
Text.literal(" * " + playerName + " 回来了.").withColor(Colors.LIGHT_GRAY),
player.getServer().getPlayerList().broadcastSystemMessage(
Component.literal(" * " + playerName + " 回来了.").withColor(CommonColors.LIGHT_GRAY),
false
);
SFCallbacks.PLAYER_AFK.invoker().onAFKStatus(player, false);
@@ -4,27 +4,27 @@ import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.callback.SFCallbacks;
import it.unimi.dsi.fastutil.objects.*;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.util.math.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.util.CommonColors;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
public class ElytraSpeedMeterModule extends ServerModule {
private static final int BAR_LEN = 20;
private static final int MAX_NORMAL_SPEED = 6;
private static final int THRESHLD_OF_ELYTRA_FLY = 8;
private static final Text[] ELYTRA_DURABILITY = new Text[100];
private final Object2ObjectMap<PlayerEntity, BlockPos> playerFlyMap = new Object2ObjectOpenHashMap<>();
private final Object2FloatMap<PlayerEntity> lastMeasuredSpeed = new Object2FloatOpenHashMap<>();
private static final Component[] ELYTRA_DURABILITY = new Component[100];
private final Object2ObjectMap<Player, BlockPos> playerFlyMap = new Object2ObjectOpenHashMap<>();
private final Object2FloatMap<Player> lastMeasuredSpeed = new Object2FloatOpenHashMap<>();
static {
for (int i = 1; i <= 100; i++) {
ELYTRA_DURABILITY[i - 1] = Text.literal("ELYTRA: " + i + "%").withColor(getDamageColor(i));
ELYTRA_DURABILITY[i - 1] = Component.literal("ELYTRA: " + i + "%").withColor(getDamageColor(i));
}
}
@@ -34,68 +34,68 @@ public class ElytraSpeedMeterModule extends ServerModule {
ServerPlayConnectionEvents.DISCONNECT.register(this::onDisconnect);
}
private void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) {
private void onDisconnect(ServerGamePacketListenerImpl serverPlayNetworkHandler, MinecraftServer minecraftServer) {
clean(serverPlayNetworkHandler.getPlayer());
}
private void clean(ServerPlayerEntity player) {
private void clean(ServerPlayer player) {
playerFlyMap.remove(player);
lastMeasuredSpeed.removeFloat(player);
}
private void onFlying(PlayerEntity player, long f, boolean b) {
private void onFlying(Player player, long f, boolean b) {
if (f < THRESHLD_OF_ELYTRA_FLY * 20) {
return;
}
if (b) {
var text = Text.literal("");
text.append(genPitchMeter(player.getPitch()));
var text = Component.literal("");
text.append(genPitchMeter(player.getXRot()));
text.append(" ");
text.append(generateDurabilityMeter(f, player));
player.sendMessage(text, true);
player.displayClientMessage(text, true);
} else {
clean((ServerPlayerEntity) player);
clean((ServerPlayer) player);
if (f > THRESHLD_OF_ELYTRA_FLY * 20) {
player.sendMessage(Text.literal("!! LANDED !!").withColor(Colors.GREEN), true);
player.displayClientMessage(Component.literal("!! LANDED !!").withColor(CommonColors.GREEN), true);
} else {
player.sendMessage(Text.empty(), true);
player.displayClientMessage(Component.empty(), true);
}
}
}
private Text genPitchMeter(float pitch) {
MutableText text;
private Component genPitchMeter(float pitch) {
MutableComponent text;
var display = (Math.ceil(Math.abs(pitch) * 100) / 100);
if (pitch < 0) { // 朝上
text = Text.literal(" 🡹 " + display + "°");
text = Component.literal(" 🡹 " + display + "°");
} else {
text = Text.literal(" 🡻 " + display + "°");
text = Component.literal(" 🡻 " + display + "°");
}
if (pitch > 75) {
text.withColor(Colors.LIGHT_RED);
text.withColor(CommonColors.SOFT_RED);
}
return text;
}
private Text generateDurabilityMeter(long f, PlayerEntity player) {
var stack = player.getEquippedStack(EquipmentSlot.CHEST);
if (stack.isDamageable() && stack.isDamaged()) {
var remaining = stack.getMaxDamage() - stack.getDamage();
private Component generateDurabilityMeter(long f, Player player) {
var stack = player.getItemBySlot(EquipmentSlot.CHEST);
if (stack.isDamageableItem() && stack.isDamaged()) {
var remaining = stack.getMaxDamage() - stack.getDamageValue();
var percent = (int) Math.ceil(((double) remaining / stack.getMaxDamage()) * 100);
return ELYTRA_DURABILITY[Math.max(percent - 1, 0)];
}
return Text.literal("ELYTRA: INFINITY").withColor(Colors.BLUE);
return Component.literal("ELYTRA: INFINITY").withColor(CommonColors.BLUE);
}
private static int getDamageColor(int percent) {
if (percent > 70) {
return Colors.GREEN;
return CommonColors.GREEN;
} else if (percent > 50) {
return Colors.LIGHT_YELLOW;
return CommonColors.SOFT_YELLOW;
} else if (percent > 30) {
return Colors.LIGHT_RED;
return CommonColors.SOFT_RED;
}
return Colors.RED;
return CommonColors.RED;
}
}
@@ -6,54 +6,54 @@ import io.ib67.sfcraft.util.Helper;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
import net.minecraft.block.Fertilizable;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.BonemealableBlock;
public class FartFertilizerModule extends ServerModule {
private final Object2LongMap<PlayerEntity> lastSneaked = new Object2LongOpenHashMap<>();
private final Object2LongMap<Player> lastSneaked = new Object2LongOpenHashMap<>();
@Override
public void onInitialize() {
SFCallbacks.PLAYER_SNEAKING.register(this::onSneaking);
}
private void onSneaking(PlayerEntity player, boolean sneak) {
private void onSneaking(Player player, boolean sneak) {
if (sneak) {
var lastSneak = lastSneaked.getOrDefault(player, 0);
var dlta = Math.min(System.currentTimeMillis() - lastSneak, 100);
if (player.getRandom().nextBetween(50, 150) > dlta) {
var playerPos = player.getBlockPos();
var start = playerPos.add(-2, 0, -2);
var end = playerPos.add(2, 1, 2);
if (player.getRandom().nextIntBetweenInclusive(50, 150) > dlta) {
var playerPos = player.blockPosition();
var start = playerPos.offset(-2, 0, -2);
var end = playerPos.offset(2, 1, 2);
for (int dX = 0; dX < end.getX() - start.getX(); dX++) {
for (int dZ = 0; dZ < end.getZ() - start.getZ(); dZ++) {
for (int dY = 0; dY < end.getY() - start.getY(); dY++) {
var blockPos = start.add(dX, dY, dZ);
var state = player.getWorld().getBlockState(blockPos);
var blockPos = start.offset(dX, dY, dZ);
var state = player.level().getBlockState(blockPos);
var block = state.getBlock();
if (Helper.canFertilize(block)) {
var wld = (ServerWorld) player.getWorld();
wld.spawnParticles(
var wld = (ServerLevel) player.level();
wld.sendParticles(
ParticleTypes.COMPOSTER,
blockPos.getX(), blockPos.getY(), blockPos.getZ(), 5,
Math.max(0.5, Math.random()), Math.max(0.5, Math.random()), Math.max(0.5, Math.random()),
0.4
);
for (ServerPlayerEntity serverPlayerEntity : PlayerLookup.around(wld, blockPos, 6f)) {
serverPlayerEntity.playSoundToPlayer(
SoundEvents.BLOCK_COMPOSTER_FILL,
SoundCategory.BLOCKS,
for (ServerPlayer serverPlayerEntity : PlayerLookup.around(wld, blockPos, 6f)) {
serverPlayerEntity.playNotifySound(
SoundEvents.COMPOSTER_FILL,
SoundSource.BLOCKS,
((6 - serverPlayerEntity.distanceTo(player) + 1) / 6) * 50,
3f
);
}
if (player.getRandom().nextInt(10) < 3) {
((Fertilizable) block).grow(wld,
((BonemealableBlock) block).performBonemeal(wld,
wld.getRandom(), blockPos, state);
}
}
@@ -28,7 +28,7 @@ public class MotdModule extends ServerModule {
@Override
public void onEnable() {
originalMotd = minecraftServer.get().getServerMotd();
originalMotd = minecraftServer.get().getMotd();
minecraftServer.get().setMotd(motd);
}
@@ -12,15 +12,14 @@ import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.config.SFConfig;
import lombok.Setter;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.network.ClientConnection;
import net.minecraft.server.WhitelistEntry;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.util.Uuids;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.core.UUIDUtil;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.server.players.UserWhiteListEntry;
import net.minecraft.util.CommonColors;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -40,46 +39,46 @@ public class OfflineExemptModule extends ServerModule {
CommandRegistrationCallback.EVENT.register(this::registerCommand);
}
private void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment registrationEnvironment) {
private void registerCommand(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext registryAccess, Commands.CommandSelection registrationEnvironment) {
dispatcher.register(
LiteralArgumentBuilder.<ServerCommandSource>literal("addwl")
LiteralArgumentBuilder.<CommandSourceStack>literal("addwl")
.requires(i -> isEnabled())
.requires(it -> it.hasPermissionLevel(2) || SFConsts.COMMAND_ADDWL.hasPermission(it.getPlayer()))
.then(RequiredArgumentBuilder.<ServerCommandSource, String>argument("player", StringArgumentType.string())
.requires(it -> it.hasPermission(2) || SFConsts.COMMAND_ADDWL.hasPermission(it.getPlayer()))
.then(RequiredArgumentBuilder.<CommandSourceStack, String>argument("player", StringArgumentType.string())
.executes(it -> this.addPlayerOffline(it.getSource(), it.getArgument("player", String.class))))
);
dispatcher.register(LiteralArgumentBuilder.<ServerCommandSource>literal("listoffline")
dispatcher.register(LiteralArgumentBuilder.<CommandSourceStack>literal("listoffline")
.requires(i -> isEnabled())
.requires(it -> it.hasPermissionLevel(2) || SFConsts.COMMAND_LISTOFFLINE.hasPermission(it.getPlayer()))
.requires(it -> it.hasPermission(2) || SFConsts.COMMAND_LISTOFFLINE.hasPermission(it.getPlayer()))
.executes(this::listOffline)
);
}
public int addPlayerOffline(ServerCommandSource source, String player) {
public int addPlayerOffline(CommandSourceStack source, String player) {
player = player.trim();
var pm = source.getServer().getPlayerManager();
var wl = pm.getWhitelist();
if (List.of(wl.getNames()).contains(player)) {
source.sendError(Text.of(player + " is already whitelisted or this id is conflict with a online user."));
var pm = source.getServer().getPlayerList();
var wl = pm.getWhiteList();
if (List.of(wl.getUserList()).contains(player)) {
source.sendFailure(Component.nullToEmpty(player + " is already whitelisted or this id is conflict with a online user."));
return 0;
}
var profile = Uuids.getOfflinePlayerProfile(player);
wl.add(new WhitelistEntry(profile));
var uc = source.getServer().getUserCache();
var profile = UUIDUtil.createOfflineProfile(player);
wl.add(new UserWhiteListEntry(profile));
var uc = source.getServer().getProfileCache();
if (uc != null) uc.add(profile);
source.sendMessage(Text.of("[" + profile.getName() + "/" + profile.getId() + "]" + " is added!"));
source.sendSystemMessage(Component.nullToEmpty("[" + profile.getName() + "/" + profile.getId() + "]" + " is added!"));
return 0;
}
public int listOffline(CommandContext<ServerCommandSource> ctx) {
public int listOffline(CommandContext<CommandSourceStack> ctx) {
var source = ctx.getSource();
var server = source.getServer();
var wl = server.getPlayerManager().getWhitelist();
var names = wl.getNames();
source.sendMessage(Text.of("Offline Users:").copy().withColor(Colors.GREEN));
var r = Stream.of(names).filter(name -> wl.isAllowed(Uuids.getOfflinePlayerProfile(name))).collect(Collectors.joining(", "));
source.sendMessage(Text.of(r.isEmpty() ? "No offline users found in whitelist." : r));
var wl = server.getPlayerList().getWhiteList();
var names = wl.getUserList();
source.sendSystemMessage(Component.nullToEmpty("Offline Users:").copy().withColor(CommonColors.GREEN));
var r = Stream.of(names).filter(name -> wl.isWhiteListed(UUIDUtil.createOfflineProfile(name))).collect(Collectors.joining(", "));
source.sendSystemMessage(Component.nullToEmpty(r.isEmpty() ? "No offline users found in whitelist." : r));
return 0;
}
@@ -93,9 +92,9 @@ public class OfflineExemptModule extends ServerModule {
state = temporallyState || config.enableOfflineExempt;
}
private void onPreLogin(String s, ClientConnection connection, Consumer<Text> textConsumer, boolean offline) {
private void onPreLogin(String s, Connection connection, Consumer<Component> textConsumer, boolean offline) {
if (!state && offline) {
textConsumer.accept(Text.of("§c盗版赦免现已关闭"));
textConsumer.accept(Component.nullToEmpty("§c盗版赦免现已关闭"));
}
}
}
@@ -12,21 +12,20 @@ import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import io.ib67.sfcraft.registry.RoomRegistry;
import lombok.extern.log4j.Log4j2;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.network.PacketCallbacks;
import net.minecraft.network.packet.s2c.common.ServerTransferS2CPacket;
import net.minecraft.network.packet.s2c.common.StoreCookieS2CPacket;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.world.ChunkTicketType;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.Pair;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.core.BlockPos;
import net.minecraft.network.PacketSendListener;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.common.ClientboundStoreCookiePacket;
import net.minecraft.network.protocol.common.ClientboundTransferPacket;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.Tuple;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -44,7 +43,7 @@ public class RoomModule extends ServerModule {
private MinecraftServerSupplier serverSupplier;
@Inject
private SFConfig config;
private final List<Pair<RegistryKey<World>, BlockPos>> pregenQueue = new ArrayList<>();
private final List<Tuple<ResourceKey<Level>, BlockPos>> pregenQueue = new ArrayList<>();
private final Map<UUID, GameProfile> uuidMapper = new ConcurrentHashMap<>();
@Override
@@ -54,45 +53,45 @@ public class RoomModule extends ServerModule {
@Override
public void onEnable() {
for (Pair<RegistryKey<World>, BlockPos> registryKeyBlockPosPair : pregenQueue) {
var world = serverSupplier.get().getWorld(registryKeyBlockPosPair.getLeft());
for (Tuple<ResourceKey<Level>, BlockPos> registryKeyBlockPosPair : pregenQueue) {
var world = serverSupplier.get().getLevel(registryKeyBlockPosPair.getA());
if (world == null) {
log.warn("Cannot find world {}", registryKeyBlockPosPair.getLeft());
log.warn("Cannot find world {}", registryKeyBlockPosPair.getA());
continue;
}
world.getChunkManager().addTicket(ChunkTicketType.START, new ChunkPos(registryKeyBlockPosPair.getRight()), 64);
world.getChunkSource().addTicketWithRadius(TicketType.START, new ChunkPos(registryKeyBlockPosPair.getB()), 64);
}
}
private void registerCommand(CommandDispatcher<ServerCommandSource> serverCommandSourceCommandDispatcher, CommandRegistryAccess commandRegistryAccess, CommandManager.RegistrationEnvironment registrationEnvironment) {
private void registerCommand(CommandDispatcher<CommandSourceStack> serverCommandSourceCommandDispatcher, CommandBuildContext commandRegistryAccess, Commands.CommandSelection registrationEnvironment) {
serverCommandSourceCommandDispatcher.register(
LiteralArgumentBuilder.<ServerCommandSource>literal("reco")
.requires(it -> it.isExecutedByPlayer() && COMMAND_RECO.hasPermission(it.getPlayer()))
LiteralArgumentBuilder.<CommandSourceStack>literal("reco")
.requires(it -> it.isPlayer() && COMMAND_RECO.hasPermission(it.getPlayer()))
.executes(this::onCleanReconnect)
);
}
private int onCleanReconnect(CommandContext<ServerCommandSource> serverCommandSourceCommandContext) {
private int onCleanReconnect(CommandContext<CommandSourceStack> serverCommandSourceCommandContext) {
var player = serverCommandSourceCommandContext.getSource().getPlayer();
if (player == null) {
return 0;
}
if (!isVirtual(player.getUuid())) {
player.sendMessage(Text.literal("你不在任何 \"房间\" 内。"));
if (!isVirtual(player.getUUID())) {
player.sendSystemMessage(Component.literal("你不在任何 \"房间\" 内。"));
return 0;
}
var networkHandler = player.networkHandler;
networkHandler.send(new StoreCookieS2CPacket(ROOM_COOKIE, EMPTY), PacketCallbacks.always(() -> {
networkHandler.sendPacket(new ServerTransferS2CPacket(config.domain, serverSupplier.get().getServerPort()));
var networkHandler = player.connection;
networkHandler.send(new ClientboundStoreCookiePacket(ROOM_COOKIE, EMPTY), PacketSendListener.thenRun(() -> {
networkHandler.send(new ClientboundTransferPacket(config.domain, serverSupplier.get().getPort()));
}));
return 1;
}
public void enqueuePregen(RegistryKey<World> world, BlockPos spawnPos) {
pregenQueue.add(new Pair<>(world, spawnPos));
public void enqueuePregen(ResourceKey<Level> world, BlockPos spawnPos) {
pregenQueue.add(new Tuple<>(world, spawnPos));
}
public UUID generateIdForRoom(GameProfile issuer, String name, Identifier room) {
public UUID generateIdForRoom(GameProfile issuer, String name, ResourceLocation room) {
var uuid = UUID.nameUUIDFromBytes((name + "@" + room.toString()).getBytes(StandardCharsets.UTF_8));
var result = new UUID(uuid.getMostSignificantBits(), 0);
if (issuer != null) uuidMapper.put(result, issuer);
@@ -5,8 +5,8 @@ import io.ib67.sfcraft.config.SFConfig;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.SneakyThrows;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import org.apache.commons.lang3.RandomStringUtils;
import javax.crypto.SecretKeyFactory;
@@ -63,12 +63,12 @@ public class SignatureService {
long validUntil,
byte[] data
) {
public static final PacketCodec<ByteBuf, Signature> PACKET_CODEC = PacketCodec.tuple(
PacketCodecs.STRING, Signature::topic,
PacketCodecs.STRING, Signature::issuer,
PacketCodecs.VAR_INT, Signature::permission,
PacketCodecs.VAR_LONG, Signature::validUntil,
PacketCodecs.BYTE_ARRAY, Signature::data,
public static final StreamCodec<ByteBuf, Signature> PACKET_CODEC = StreamCodec.composite(
ByteBufCodecs.STRING_UTF8, Signature::topic,
ByteBufCodecs.STRING_UTF8, Signature::issuer,
ByteBufCodecs.VAR_INT, Signature::permission,
ByteBufCodecs.VAR_LONG, Signature::validUntil,
ByteBufCodecs.BYTE_ARRAY, Signature::data,
Signature::new
);
@@ -12,17 +12,10 @@ import io.ib67.sfcraft.inject.ConfigRoot;
import lombok.SneakyThrows;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.WrittenBookContentComponent;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.RawFilteredPair;
import net.minecraft.text.Text;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.file.Files;
@@ -63,25 +56,25 @@ public class WelcomeModule extends ServerModule {
}
}
public void onPlayerJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender
public void onPlayerJoin(ServerGamePacketListenerImpl serverPlayNetworkHandler, PacketSender
packetSender, MinecraftServer minecraftServer) {
if (!isEnabled()) return;
var player = serverPlayNetworkHandler.getPlayer();
if (!player.getCommandTags().contains("sf_unlock_recipe")) {
player.addCommandTag("sf_unlock_recipe");
if (!player.getTags().contains("sf_unlock_recipe")) {
player.addTag("sf_unlock_recipe");
unlockRecipe(player);
}
for (String s : announcements.keySet()) {
if (!player.getCommandTags().contains(s)) {
player.addCommandTag(s);
announcements.get(s).lines().map(Text::of).forEach(player::sendMessage);
if (!player.getTags().contains(s)) {
player.addTag(s);
announcements.get(s).lines().map(Component::nullToEmpty).forEach(player::sendSystemMessage);
}
}
}
private void unlockRecipe(ServerPlayerEntity player) {
private void unlockRecipe(ServerPlayer player) {
var recipe = player.getRecipeBook();
recipe.unlockRecipes(player.getServer().getRecipeManager().values(), player);
recipe.addRecipes(player.getServer().getRecipeManager().getRecipes(), player);
}
}
@@ -1,13 +1,13 @@
package io.ib67.sfcraft.module.chat;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
import java.util.Objects;
import net.minecraft.network.chat.Component;
public record ChatPrefix(
Text prefix,
Component prefix,
String id,
boolean temporary,
int priority
@@ -5,14 +5,13 @@ import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.TeamS2CPacket;
import net.minecraft.scoreboard.Team;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.text.Text;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.scores.PlayerTeam;
import java.util.*;
//todo rework
@@ -21,8 +20,8 @@ public class ChatPrefixModule extends ServerModule {
private MinecraftServerSupplier serverSupplier;
private volatile ChatPrefix empty;
private final Map<UUID, SortedSet<ChatPrefix>> playerPrefixes = new HashMap<>();
private final Map<String, Team> virtualTeams = new HashMap<>();
private final Map<UUID, Team> players = new HashMap<>();
private final Map<String, PlayerTeam> virtualTeams = new HashMap<>();
private final Map<UUID, PlayerTeam> players = new HashMap<>();
@Override
public void onInitialize() {
@@ -33,7 +32,7 @@ public class ChatPrefixModule extends ServerModule {
@Override
public void onEnable() {
empty = new ChatPrefix(
Text.empty(),
Component.empty(),
"EMPTY",
true,
1000
@@ -41,25 +40,25 @@ public class ChatPrefixModule extends ServerModule {
virtualTeams.put(empty.id(), createTeamFrom(empty));
}
private void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) {
private void onDisconnect(ServerGamePacketListenerImpl serverPlayNetworkHandler, MinecraftServer minecraftServer) {
var player = serverPlayNetworkHandler.getPlayer();
var current = getCurrentPrefix(player);
if (current != null && current.temporary()) {
removeFromTeam(player, players.get(player.getUuid()));
removeFromTeam(player, players.get(player.getUUID()));
}
}
private void onJoin(ServerPlayNetworkHandler networkHandler, PacketSender sender, MinecraftServer minecraftServer) {
private void onJoin(ServerGamePacketListenerImpl networkHandler, PacketSender sender, MinecraftServer minecraftServer) {
applyPrefix(networkHandler.getPlayer(), empty);
for (Map.Entry<UUID, Team> uuidTeamEntry : players.entrySet()) {
for (Map.Entry<UUID, PlayerTeam> uuidTeamEntry : players.entrySet()) {
var team = uuidTeamEntry.getValue();
sender.sendPacket(TeamS2CPacket.updateTeam(team, true));
sender.sendPacket(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true));
}
}
private void onPrefixUpdate(PlayerEntity player) {
var lastTeam = players.get(player.getUuid());
var current = virtualTeams.get(playerPrefixes.get(player.getUuid()).getFirst().id());
private void onPrefixUpdate(Player player) {
var lastTeam = players.get(player.getUUID());
var current = virtualTeams.get(playerPrefixes.get(player.getUUID()).getFirst().id());
if (lastTeam == current) return;
if (lastTeam != null) removeFromTeam(player, lastTeam);
if (current == null) {
@@ -68,49 +67,49 @@ public class ChatPrefixModule extends ServerModule {
addToTeam(player, current);
}
private void addToTeam(PlayerEntity player, Team team) {
var playerName = player.getName().getLiteralString();
private void addToTeam(Player player, PlayerTeam team) {
var playerName = player.getName().tryCollapseToString();
if(team == null) return;
team.getPlayerList().add(playerName);
players.put(player.getUuid(), team);
sendToAll(TeamS2CPacket.updateTeam(team, true));
team.getPlayers().add(playerName);
players.put(player.getUUID(), team);
sendToAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true));
}
private void removeFromTeam(PlayerEntity player, Team team) {
var playerName = player.getName().getLiteralString();
private void removeFromTeam(Player player, PlayerTeam team) {
var playerName = player.getName().tryCollapseToString();
if(team == null) return;
team.getPlayerList().remove(playerName);
sendToAll(TeamS2CPacket.updateTeam(team, true));
team.getPlayers().remove(playerName);
sendToAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true));
var current = getCurrentPrefix(player);
var newTeam = virtualTeams.get(current.id());
addToTeam(player, newTeam);
}
private void sendToAll(Packet<?> packet) {
serverSupplier.get().getPlayerManager().sendToAll(packet);
serverSupplier.get().getPlayerList().broadcastAll(packet);
}
public void applyPrefix(PlayerEntity player, ChatPrefix prefix) {
if (hasPrefix(player.getUuid(), prefix)) {
public void applyPrefix(Player player, ChatPrefix prefix) {
if (hasPrefix(player.getUUID(), prefix)) {
return;
}
playerPrefixes.get(player.getUuid()).add(prefix);
playerPrefixes.get(player.getUUID()).add(prefix);
onPrefixUpdate(player);
}
public void removePrefix(PlayerEntity player, ChatPrefix prefix) {
if (!hasPrefix(player.getUuid(), prefix)) {
public void removePrefix(Player player, ChatPrefix prefix) {
if (!hasPrefix(player.getUUID(), prefix)) {
return;
}
playerPrefixes.get(player.getUuid()).remove(prefix);
playerPrefixes.get(player.getUUID()).remove(prefix);
onPrefixUpdate(player);
}
public ChatPrefix getCurrentPrefix(PlayerEntity player) {
if (!playerPrefixes.containsKey(player.getUuid())) {
public ChatPrefix getCurrentPrefix(Player player) {
if (!playerPrefixes.containsKey(player.getUUID())) {
return null;
}
return playerPrefixes.get(player.getUuid()).first();
return playerPrefixes.get(player.getUUID()).first();
}
@@ -121,12 +120,12 @@ public class ChatPrefixModule extends ServerModule {
return playerPrefixes.computeIfAbsent(player, ignored -> new TreeSet<>(List.of(empty))).contains(prefix);
}
private Team createTeamFrom(ChatPrefix prefix) {
var t = new Team(
private PlayerTeam createTeamFrom(ChatPrefix prefix) {
var t = new PlayerTeam(
serverSupplier.get().getScoreboard(),
prefix.id()
);
t.setPrefix(prefix.prefix());
t.setPlayerPrefix(prefix.prefix());
return t;
}
}
@@ -5,13 +5,6 @@ import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.registry.chat.SimpleMessageDecorator;
import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import io.ib67.sfcraft.util.SFConsts;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.message.MessageDecorator;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
@@ -19,8 +12,15 @@ import java.util.List;
import java.util.Set;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import net.minecraft.network.chat.ChatDecorator;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.CommonColors;
import net.minecraft.world.entity.player.Player;
public class ChatPingModule extends ServerModule implements MessageDecorator {
public class ChatPingModule extends ServerModule implements ChatDecorator {
private static final Pattern PING = Pattern.compile("(@[\\w]+)?"); //todo remove the need of prefix
@Inject
MinecraftServerSupplier serverSupplier;
@@ -33,7 +33,7 @@ public class ChatPingModule extends ServerModule implements MessageDecorator {
}
@Override
public Text decorate(@Nullable ServerPlayerEntity sender, Text message) {
public Component decorate(@Nullable ServerPlayer sender, Component message) {
if (!isEnabled()) {
return message;
}
@@ -42,20 +42,20 @@ public class ChatPingModule extends ServerModule implements MessageDecorator {
return message;
}
}
var text = message.getLiteralString();
var text = message.tryCollapseToString();
if (text == null) return message;
var match = PING.matcher(text);
if (!match.find()) return message;
var foundPlayers = new HashSet<PlayerEntity>();
var foundPlayers = new HashSet<Player>();
var names = List.of(serverSupplier.get().getPlayerNames());
var r = Text.literal(match.replaceAll(it -> this.matchPlayer(it, names, foundPlayers)));
for (PlayerEntity foundPlayer : foundPlayers) {
var r = Component.literal(match.replaceAll(it -> this.matchPlayer(it, names, foundPlayers)));
for (Player foundPlayer : foundPlayers) {
if (sender != null) {
foundPlayer.sendMessage(Text.literal(sender.getName().getLiteralString() + " 正在叫你。").withColor(Colors.LIGHT_GRAY), true);
foundPlayer.displayClientMessage(Component.literal(sender.getName().tryCollapseToString() + " 正在叫你。").withColor(CommonColors.LIGHT_GRAY), true);
}
foundPlayer.playSoundToPlayer(
SoundEvents.ENTITY_ITEM_PICKUP,
SoundCategory.PLAYERS,
foundPlayer.playNotifySound(
SoundEvents.ITEM_PICKUP,
SoundSource.PLAYERS,
0.8f,
0.5f
);
@@ -63,14 +63,14 @@ public class ChatPingModule extends ServerModule implements MessageDecorator {
return r;
}
private String matchPlayer(MatchResult match, List<String> playerNames, Set<PlayerEntity> foundPlayers) {
private String matchPlayer(MatchResult match, List<String> playerNames, Set<Player> foundPlayers) {
for (int i = 0; i < match.groupCount(); i++) {
var r = match.group();
if (r.isEmpty()) continue;
final var d = r.substring(1);
return playerNames.stream()
.filter(it -> it.toLowerCase().startsWith(d))
.peek(it -> foundPlayers.add(serverSupplier.get().getPlayerManager().getPlayer(it)))
.peek(it -> foundPlayers.add(serverSupplier.get().getPlayerList().getPlayerByName(it)))
.findFirst()
.orElse(r);
}
@@ -5,17 +5,17 @@ import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.registry.chat.SimpleMessageDecorator;
import io.ib67.sfcraft.util.Helper;
import io.ib67.sfcraft.util.SFConsts;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.network.message.MessageDecorator;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.Text;
import net.minecraft.world.World;
import net.minecraft.network.chat.ChatDecorator;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;
public class ChatSendLocModule extends ServerModule implements MessageDecorator {
public class ChatSendLocModule extends ServerModule implements ChatDecorator {
@Inject
SimpleMessageDecorator messageDecorator;
@@ -25,7 +25,7 @@ public class ChatSendLocModule extends ServerModule implements MessageDecorator
}
@Override
public Text decorate(@Nullable ServerPlayerEntity sender, Text message) {
public Component decorate(@Nullable ServerPlayer sender, Component message) {
if (!isEnabled()) return message;
if (sender != null) {
if (!SFConsts.USE_BROADCAST_LOCATION.hasPermission(sender)) {
@@ -35,26 +35,26 @@ public class ChatSendLocModule extends ServerModule implements MessageDecorator
return ReplaceHelper.replace(sender, message, ".xyz", ChatSendLocModule::generateLocText);
}
private static Text generateLocText(ServerPlayerEntity sender) {
if (sender == null) return Text.of(" (invalid position) ");
sender.addStatusEffect(new StatusEffectInstance(StatusEffects.GLOWING, 15 * 20));
var x = sender.getBlockPos().getX();
var y = sender.getBlockPos().getY();
var z = sender.getBlockPos().getZ();
var key = sender.getWorld().getRegistryKey();
private static Component generateLocText(ServerPlayer sender) {
if (sender == null) return Component.nullToEmpty(" (invalid position) ");
sender.addEffect(new MobEffectInstance(MobEffects.GLOWING, 15 * 20));
var x = sender.blockPosition().getX();
var y = sender.blockPosition().getY();
var z = sender.blockPosition().getZ();
var key = sender.level().dimension();
var world = translate(key);
return Text
return Component
.literal(" " + x + ", " + y + ", " + z + world + " ")
.withColor(Helper.fromRgb(63, 254, 254))
.styled(style -> style.withClickEvent(new ClickEvent.RunCommand("/gps " + key + " " + x + " " + y + " " + z)));
.withStyle(style -> style.withClickEvent(new ClickEvent.RunCommand("/gps " + key + " " + x + " " + y + " " + z)));
}
private static String translate(RegistryKey<World> registryKey) {
if (registryKey == World.END) {
private static String translate(ResourceKey<Level> registryKey) {
if (registryKey == Level.END) {
return " (末地)";
} else if (registryKey == World.NETHER) {
} else if (registryKey == Level.NETHER) {
return " (地狱)";
} else if (registryKey == World.OVERWORLD) {
} else if (registryKey == Level.OVERWORLD) {
return "";
} else {
return " (未知)";
@@ -1,18 +1,17 @@
package io.ib67.sfcraft.module.chat.decorator;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.util.Locale;
import java.util.function.Function;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
class ReplaceHelper {
public static Text replace(ServerPlayerEntity sender, Text message, String s, Function<ServerPlayerEntity, Text> generator) {
var text = message.getLiteralString();
public static Component replace(ServerPlayer sender, Component message, String s, Function<ServerPlayer, Component> generator) {
var text = message.tryCollapseToString();
if (text == null || text.isEmpty()) return message;
text = text.trim();
var result = Text.literal("");
var result = Component.literal("");
var head = 0;
var lowercase = text.toLowerCase(Locale.ROOT);
var i = lowercase.indexOf(s);
@@ -8,14 +8,14 @@ import io.ib67.sfcraft.util.SFConsts;
import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.callback.SFCallbacks;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
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.Colors;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.CommonColors;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Player;
public class BackModule extends ServerModule {
@Override
@@ -24,38 +24,38 @@ public class BackModule extends ServerModule {
CommandRegistrationCallback.EVENT.register(this::registerCommands);
}
private void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment registrationEnvironment) {
dispatcher.register(LiteralArgumentBuilder.<ServerCommandSource>literal("back")
private void registerCommands(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext registryAccess, Commands.CommandSelection registrationEnvironment) {
dispatcher.register(LiteralArgumentBuilder.<CommandSourceStack>literal("back")
.requires(it -> this.isEnabled())
.requires(it -> it.getPlayer() != null)
.requires(it -> it.getPlayer().getLastDeathPos().isPresent())
.requires(it -> it.getPlayer().getLastDeathLocation().isPresent())
.requires(it -> SFConsts.COMMAND_BACK.hasPermission(it.getPlayer()))
.executes(this::onBack));
}
public int onBack(CommandContext<ServerCommandSource> it) {
public int onBack(CommandContext<CommandSourceStack> it) {
var player = it.getSource().getPlayer();
var pos = player.getLastDeathPos().get();
var wld = player.getServer().getWorld(pos.dimension());
var pos = player.getLastDeathLocation().get();
var wld = player.getServer().getLevel(pos.dimension());
var _pos = pos.pos();
if (wld == null) return 0;
var nearby = wld.getClosestPlayer(_pos.getX(), _pos.getY(), _pos.getZ(), 100, true);
var nearby = wld.getNearestPlayer(_pos.getX(), _pos.getY(), _pos.getZ(), 100, true);
if (nearby != null) {
_pos = nearby.getBlockPos();
_pos = nearby.blockPosition();
Helper.teleportSafely(player, wld, _pos.getX(), _pos.getY(), _pos.getZ(),0,0);
} else {
if (SFConsts.UNLIMITED_COMMAND_BACK.hasPermission(player)) {
Helper.teleportSafely(player, wld, _pos.getX(), _pos.getY(), _pos.getZ(),0,0);
return 0;
}
player.sendMessage(Text.of("周围没有玩家。").copy().withColor(Colors.RED));
player.sendSystemMessage(Component.nullToEmpty("周围没有玩家。").copy().withColor(CommonColors.RED));
}
return 0;
}
public void onPlayerDeath(PlayerEntity player, DamageSource damageSource) {
if (this.isEnabled() && Helper.canBack((ServerPlayerEntity) player)) {
player.sendMessage(Text.of("Tip: 死亡地点附近有玩家,可以使用 /back 传送到他们那里。(即使在对方也死亡的状态下)"), false);
public void onPlayerDeath(Player player, DamageSource damageSource) {
if (this.isEnabled() && Helper.canBack((ServerPlayer) player)) {
player.displayClientMessage(Component.nullToEmpty("Tip: 死亡地点附近有玩家,可以使用 /back 传送到他们那里。(即使在对方也死亡的状态下)"), false);
}
}
}
@@ -13,15 +13,14 @@ import io.ib67.sfcraft.ServerModule;
import lombok.SneakyThrows;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.util.CommonColors;
import java.lang.reflect.Field;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -38,72 +37,72 @@ public class ManagementModule extends ServerModule {
ServerPlayConnectionEvents.DISCONNECT.register(this::onDisconnect);
}
private void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) {
serverPlayNetworkHandler.getPlayer().removeCommandTag(SFConsts.SPECIAL_SUDO);
private void onDisconnect(ServerGamePacketListenerImpl serverPlayNetworkHandler, MinecraftServer minecraftServer) {
serverPlayNetworkHandler.getPlayer().removeTag(SFConsts.SPECIAL_SUDO);
}
private void registerCommands(
CommandDispatcher<ServerCommandSource> dispatcher,
CommandRegistryAccess registryAccess,
CommandManager.RegistrationEnvironment env) {
dispatcher.register(LiteralArgumentBuilder.<ServerCommandSource>literal("sudo")
CommandDispatcher<CommandSourceStack> dispatcher,
CommandBuildContext registryAccess,
Commands.CommandSelection env) {
dispatcher.register(LiteralArgumentBuilder.<CommandSourceStack>literal("sudo")
.requires(it -> this.isEnabled())
.requires(it -> it.hasPermissionLevel(2) && it.getPlayer() != null)
.requires(it -> it.hasPermission(2) && it.getPlayer() != null)
.executes(this::enterSudoMode)
);
dispatcher.register(LiteralArgumentBuilder.<ServerCommandSource>literal("listperm")
dispatcher.register(LiteralArgumentBuilder.<CommandSourceStack>literal("listperm")
.requires(it -> this.isEnabled())
.requires(it -> it.hasPermissionLevel(2) || SFConsts.COMMAND_LISTPERM.hasPermission(it.getPlayer()))
.requires(it -> it.hasPermission(2) || SFConsts.COMMAND_LISTPERM.hasPermission(it.getPlayer()))
.executes(this::listPerms)
);
dispatcher.register(LiteralArgumentBuilder.<ServerCommandSource>literal("listgeo")
dispatcher.register(LiteralArgumentBuilder.<CommandSourceStack>literal("listgeo")
.requires(it -> this.isEnabled())
.requires(it -> it.hasPermissionLevel(2) || SFConsts.COMMAND_LISTGEO.hasPermission(it.getPlayer()))
.requires(it -> it.hasPermission(2) || SFConsts.COMMAND_LISTGEO.hasPermission(it.getPlayer()))
.executes(this::listGeo)
);
}
private int listGeo(CommandContext<ServerCommandSource> ctx) {
private int listGeo(CommandContext<CommandSourceStack> ctx) {
var src = ctx.getSource();
var server = src.getServer();
src.sendMessage(Text.of("List of player with cities:"));
for (ServerPlayerEntity serverPlayerEntity : server.getPlayerManager().getPlayerList()) {
src.sendSystemMessage(Component.nullToEmpty("List of player with cities:"));
for (ServerPlayer serverPlayerEntity : server.getPlayerList().getPlayers()) {
try {
var addr = InetAddress.getByName(serverPlayerEntity.getIp());
var addr = InetAddress.getByName(serverPlayerEntity.getIpAddress());
var city = geoIPService.cityOf(addr);
src.sendMessage(
Text.literal(" - ")
.append(Text.literal("[" + city.getName() + "] ").withColor(Colors.BLUE))
.append(Text.literal(serverPlayerEntity.getName().getLiteralString()))
.append(Text.literal(" (" + Helper.hideIp(addr) + ")").withColor(Colors.LIGHT_GRAY))
src.sendSystemMessage(
Component.literal(" - ")
.append(Component.literal("[" + city.getName() + "] ").withColor(CommonColors.BLUE))
.append(Component.literal(serverPlayerEntity.getName().tryCollapseToString()))
.append(Component.literal(" (" + Helper.hideIp(addr) + ")").withColor(CommonColors.LIGHT_GRAY))
);
} catch (GeoIp2Exception | UnknownHostException e) {
src.sendMessage(Text.literal(" - [FAILED TO FETCH] " + serverPlayerEntity.getName().getLiteralString()).withColor(Colors.LIGHT_RED));
src.sendSystemMessage(Component.literal(" - [FAILED TO FETCH] " + serverPlayerEntity.getName().tryCollapseToString()).withColor(CommonColors.SOFT_RED));
}
}
return 0;
}
public int enterSudoMode(CommandContext<ServerCommandSource> ctx) {
public int enterSudoMode(CommandContext<CommandSourceStack> ctx) {
var player = ctx.getSource().getPlayer();
if (player.getCommandTags().contains(SFConsts.SPECIAL_SUDO)) {
player.removeCommandTag(SFConsts.SPECIAL_SUDO);
player.sendMessage(Text.of("Sudo is off.").copy().withColor(Colors.GREEN));
if (player.getTags().contains(SFConsts.SPECIAL_SUDO)) {
player.removeTag(SFConsts.SPECIAL_SUDO);
player.sendSystemMessage(Component.nullToEmpty("Sudo is off.").copy().withColor(CommonColors.GREEN));
} else {
player.addCommandTag(SFConsts.SPECIAL_SUDO);
player.sendMessage(Text.of("Sudo is on.").copy().withColor(Colors.GREEN));
player.addTag(SFConsts.SPECIAL_SUDO);
player.sendSystemMessage(Component.nullToEmpty("Sudo is on.").copy().withColor(CommonColors.GREEN));
}
return 0;
}
@SneakyThrows
public int listPerms(CommandContext<ServerCommandSource> ctx) {
public int listPerms(CommandContext<CommandSourceStack> ctx) {
var src = ctx.getSource();
src.sendMessage(Text.of("Permissions: ").copy().withColor(Colors.GREEN));
src.sendSystemMessage(Component.nullToEmpty("Permissions: ").copy().withColor(CommonColors.GREEN));
for (Field declaredField : SFConsts.class.getDeclaredFields()) {
if (Permission.class.isAssignableFrom(declaredField.getType())) {
var permission = (Permission<?>) declaredField.get(null);
src.sendMessage(Text.of(" - " + permission.key() + " " + (permission.byDefault() ? "(default)" : "")));
src.sendSystemMessage(Component.nullToEmpty(" - " + permission.key() + " " + (permission.byDefault() ? "(default)" : "")));
}
}
return 0;
@@ -2,24 +2,23 @@ package io.ib67.sfcraft.module.randomevt.longnight;
import io.ib67.sfcraft.module.randomevt.RandomEvent;
import lombok.RequiredArgsConstructor;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.world.World;
import net.minecraft.network.chat.Component;
import net.minecraft.util.CommonColors;
import net.minecraft.world.level.Level;
import java.awt.*;
@RequiredArgsConstructor
public class DawnAfterLongNightEvent extends RandomEvent {
private final World world;
private final Level world;
@Override
public int start() {
if (LongNightEvent.justExpirencedLongNight) {
LongNightEvent.justExpirencedLongNight = false;
world.getServer().getPlayerManager().broadcast(
Text.literal("\"月亮\"离开了。")
world.getServer().getPlayerList().broadcastSystemMessage(
Component.literal("\"月亮\"离开了。")
.withColor(new Color(235, 91, 0).getRGB())
.append(Text.literal("(永夜事件结束)").withColor(Colors.LIGHT_GRAY))
.append(Component.literal("(永夜事件结束)").withColor(CommonColors.LIGHT_GRAY))
, false);
}
return -1;
@@ -3,11 +3,10 @@ package io.ib67.sfcraft.module.randomevt.longnight;
import io.ib67.sfcraft.module.randomevt.RandomEvent;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.CommonColors;
import net.minecraft.world.level.GameRules;
@RequiredArgsConstructor
public class LongNightEvent extends RandomEvent {
@@ -15,20 +14,20 @@ public class LongNightEvent extends RandomEvent {
static boolean isAtLongNight;
@Getter
private static int remainingTicks;
private final ServerWorld world;
private final ServerLevel world;
private boolean doDaylightCycle;
private boolean doTraderSpawning;
@Override
public int start() {
var pm = world.getServer().getPlayerManager();
var pm = world.getServer().getPlayerList();
isAtLongNight = true;
pm.broadcast(Text.literal("月亮停滞在空中...").withColor(Colors.BLUE), false);
this.doDaylightCycle = world.getGameRules().getBoolean(GameRules.DO_DAYLIGHT_CYCLE);
this.doTraderSpawning = world.getGameRules().getBoolean(GameRules.DO_TRADER_SPAWNING);
world.getGameRules().get(GameRules.DO_DAYLIGHT_CYCLE).set(false, world.getServer());
world.getGameRules().get(GameRules.DO_TRADER_SPAWNING).set(false, world.getServer());
remainingTicks = world.random.nextBetween(8400, 2 * 8400);
pm.broadcastSystemMessage(Component.literal("月亮停滞在空中...").withColor(CommonColors.BLUE), false);
this.doDaylightCycle = world.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT);
this.doTraderSpawning = world.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING);
world.getGameRules().getRule(GameRules.RULE_DAYLIGHT).set(false, world.getServer());
world.getGameRules().getRule(GameRules.RULE_DO_TRADER_SPAWNING).set(false, world.getServer());
remainingTicks = world.random.nextIntBetweenInclusive(8400, 2 * 8400);
return remainingTicks;
}
@@ -42,8 +41,8 @@ public class LongNightEvent extends RandomEvent {
isAtLongNight = false;
justExpirencedLongNight = true;
remainingTicks = 0;
world.getGameRules().get(GameRules.DO_DAYLIGHT_CYCLE).set(doDaylightCycle, world.getServer());
world.getGameRules().get(GameRules.DO_TRADER_SPAWNING).set(doTraderSpawning, world.getServer());
world.getGameRules().getRule(GameRules.RULE_DAYLIGHT).set(doDaylightCycle, world.getServer());
world.getGameRules().getRule(GameRules.RULE_DO_TRADER_SPAWNING).set(doTraderSpawning, world.getServer());
}
public static boolean isRunning() {
@@ -23,21 +23,17 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.fabric.api.util.TriState;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.command.CommandSource;
import net.minecraft.command.EntitySelector;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.command.argument.GameModeArgumentType;
import net.minecraft.network.packet.s2c.play.TeamS2CPacket;
import net.minecraft.scoreboard.Team;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.arguments.GameModeArgument;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.world.GameMode;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.CommonColors;
import net.minecraft.world.level.GameType;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
@@ -66,7 +62,7 @@ public class CreativeRoomModule extends ServerModule {
@Override
public void onInitialize() {
prefix = new ChatPrefix(
Text.literal("[PLAYGRD] ").withColor(Colors.LIGHT_YELLOW),
Component.literal("[PLAYGRD] ").withColor(CommonColors.SOFT_YELLOW),
"playgrd",
true,
20
@@ -81,10 +77,10 @@ public class CreativeRoomModule extends ServerModule {
roomModule.enqueuePregen(CreativeSpaceRoom.WORLD, CreativeSpaceRoom.SPAWN_POS);
}
private @NotNull TriState onOtherCommands(@NotNull CommandSource commandSource, @NotNull String s) {
if (commandSource instanceof ServerCommandSource source && source.getPlayer() != null) {
private @NotNull TriState onOtherCommands(@NotNull SharedSuggestionProvider commandSource, @NotNull String s) {
if (commandSource instanceof CommandSourceStack source && source.getPlayer() != null) {
var p = source.getPlayer();
if (p.getWorld().getRegistryKey().equals(CreativeSpaceRoom.WORLD)) {
if (p.level().dimension().equals(CreativeSpaceRoom.WORLD)) {
if (BYPASS_PERMISSIONS.contains(s)) {
return TriState.TRUE;
}
@@ -93,10 +89,10 @@ public class CreativeRoomModule extends ServerModule {
return TriState.DEFAULT;
}
private @NotNull TriState onWorldEdit(@NotNull CommandSource commandSource, @NotNull String s) {
if (commandSource instanceof ServerCommandSource source && source.getPlayer() != null) {
private @NotNull TriState onWorldEdit(@NotNull SharedSuggestionProvider commandSource, @NotNull String s) {
if (commandSource instanceof CommandSourceStack source && source.getPlayer() != null) {
var p = source.getPlayer();
if (p.getWorld().getRegistryKey().equals(CreativeSpaceRoom.WORLD)) {
if (p.level().dimension().equals(CreativeSpaceRoom.WORLD)) {
if (s.startsWith("worldedit") && SFConsts.WORLDEDIT_AT_PLAYGROUND.hasPermission(p)) {
return TriState.TRUE;
}
@@ -105,89 +101,89 @@ public class CreativeRoomModule extends ServerModule {
return TriState.DEFAULT;
}
private void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher,
CommandRegistryAccess registry, CommandManager.RegistrationEnvironment env) {
private void registerCommand(CommandDispatcher<CommandSourceStack> dispatcher,
CommandBuildContext registry, Commands.CommandSelection env) {
dispatcher.register(
LiteralArgumentBuilder.<ServerCommandSource>literal("playgrd")
.requires(it -> it.isExecutedByPlayer() && SFConsts.COMMAND_PLAYGROUND.hasPermission(it.getPlayer()))
LiteralArgumentBuilder.<CommandSourceStack>literal("playgrd")
.requires(it -> it.isPlayer() && SFConsts.COMMAND_PLAYGROUND.hasPermission(it.getPlayer()))
.executes(this::gotoPlayground)
);
dispatcher.register(
CommandManager.literal("gm")
.then(CommandManager.argument("mode", GameModeArgumentType.gameMode())
.requires(it -> it.isExecutedByPlayer() && SFConsts.COMMAND_PLAYGROUND_GAMEMODE.hasPermission(it.getPlayer()))
Commands.literal("gm")
.then(Commands.argument("mode", GameModeArgument.gameMode())
.requires(it -> it.isPlayer() && SFConsts.COMMAND_PLAYGROUND_GAMEMODE.hasPermission(it.getPlayer()))
.executes(this::onGameMode)
)
);
dispatcher.register(
CommandManager.literal("pt")
.then(CommandManager.argument("dest", EntityArgumentType.entity())
.requires(it -> it.isExecutedByPlayer() && SFConsts.COMMAND_PLAYGROUND_TELEPORT.hasPermission(it.getPlayer()))
Commands.literal("pt")
.then(Commands.argument("dest", EntityArgument.entity())
.requires(it -> it.isPlayer() && SFConsts.COMMAND_PLAYGROUND_TELEPORT.hasPermission(it.getPlayer()))
.executes(this::onTeleport))
);
}
private int onTeleport(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
private int onTeleport(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
var src = ctx.getSource();
if (src instanceof ServerCommandSource source && source.getPlayer() != null) {
if (src instanceof CommandSourceStack source && source.getPlayer() != null) {
var p = source.getPlayer();
var dest = EntityArgumentType.getEntity(ctx, "dest");
if (p.getWorld().getRegistryKey().equals(CreativeSpaceRoom.WORLD)) {
if (dest.getWorld() == p.getWorld()) {
var dest = EntityArgument.getEntity(ctx, "dest");
if (p.level().dimension().equals(CreativeSpaceRoom.WORLD)) {
if (dest.level() == p.level()) {
Helper.teleportSafely(
p, p.getWorld(),
p, p.level(),
dest.getBlockX(), dest.getBlockY(), dest.getBlockZ(),
dest.getYaw(), dest.getPitch()
dest.getYRot(), dest.getXRot()
);
return Command.SINGLE_SUCCESS;
}
}
p.sendMessage(Text.of("You and target must be in playground!"));
p.sendSystemMessage(Component.nullToEmpty("You and target must be in playground!"));
}
return Command.SINGLE_SUCCESS;
}
private int onGameMode(CommandContext<ServerCommandSource> ctx) {
private int onGameMode(CommandContext<CommandSourceStack> ctx) {
var src = ctx.getSource();
if (src instanceof ServerCommandSource source && source.getPlayer() != null) {
if (src instanceof CommandSourceStack source && source.getPlayer() != null) {
var p = source.getPlayer();
var mode = ctx.getArgument("mode", GameMode.class);
if (p.getWorld().getRegistryKey().equals(CreativeSpaceRoom.WORLD)) {
p.changeGameMode(mode);
p.sendMessage(Text.of("Your gamemode has been changed to " + mode.asString()));
var mode = ctx.getArgument("mode", GameType.class);
if (p.level().dimension().equals(CreativeSpaceRoom.WORLD)) {
p.setGameMode(mode);
p.sendSystemMessage(Component.nullToEmpty("Your gamemode has been changed to " + mode.getSerializedName()));
} else {
p.sendMessage(Text.of("You can only use this in playground!"));
p.sendSystemMessage(Component.nullToEmpty("You can only use this in playground!"));
}
}
return Command.SINGLE_SUCCESS;
}
private int gotoPlayground(CommandContext<ServerCommandSource> serverCommandSourceCommandContext) {
private int gotoPlayground(CommandContext<CommandSourceStack> serverCommandSourceCommandContext) {
var player = serverCommandSourceCommandContext.getSource().getPlayer();
try {
teleporter.teleportTo(room, player);
} catch (Exception e) {
player.networkHandler.disconnect(Text.of(e.getMessage()));
player.connection.disconnect(Component.nullToEmpty(e.getMessage()));
e.printStackTrace();
}
return 0;
}
public void onPlayerJoin(ServerPlayerEntity player) {
player.sendMessage(Text.of("你现在正在创造游乐园中,使用 //schem list 查看可用投影。"));
player.sendMessage(Text.literal("以下功能现在可用:").withColor(Colors.WHITE)
.append(Text.literal("/player /track /summon /setblock /gamerule 及 WorldEdit 的所有命令").withColor(Color.MAGENTA.getRGB()).append("。")));
player.sendMessage(Text.of(" "));
player.sendMessage(Text.literal("如何上传投影到游乐场: ").withColor(Colors.GRAY)
.append(Text.literal("https://github.com/saltedfishclub/sfcraft-schematics").withColor(Colors.GRAY).styled(it -> it.withUnderline(true))));
player.sendMessage(Text.literal("游乐园中的生物不能逃逸到其他维度。").withColor(Colors.GRAY));
player.sendMessage(Text.literal("使用 /reco 或重新加入游戏即可离开。").withColor(Colors.GRAY));
player.changeGameMode(GameMode.CREATIVE);
public void onPlayerJoin(ServerPlayer player) {
player.sendSystemMessage(Component.nullToEmpty("你现在正在创造游乐园中,使用 //schem list 查看可用投影。"));
player.sendSystemMessage(Component.literal("以下功能现在可用:").withColor(CommonColors.WHITE)
.append(Component.literal("/player /track /summon /setblock /gamerule 及 WorldEdit 的所有命令").withColor(Color.MAGENTA.getRGB()).append("。")));
player.sendSystemMessage(Component.nullToEmpty(" "));
player.sendSystemMessage(Component.literal("如何上传投影到游乐场: ").withColor(CommonColors.GRAY)
.append(Component.literal("https://github.com/saltedfishclub/sfcraft-schematics").withColor(CommonColors.GRAY).withStyle(it -> it.withUnderlined(true))));
player.sendSystemMessage(Component.literal("游乐园中的生物不能逃逸到其他维度。").withColor(CommonColors.GRAY));
player.sendSystemMessage(Component.literal("使用 /reco 或重新加入游戏即可离开。").withColor(CommonColors.GRAY));
player.setGameMode(GameType.CREATIVE);
chatPrefixModule.applyPrefix(player, prefix);
}
public void onPlayerQuit(ServerPlayerEntity player) {
public void onPlayerQuit(ServerPlayer player) {
chatPrefixModule.removePrefix(player, prefix);
}
}
@@ -19,14 +19,14 @@ import io.netty.buffer.Unpooled;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.nbt.NbtAccounter;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.NbtSizeTracker;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.Text;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
@@ -55,22 +55,22 @@ public class SchematicUploader extends WebHandler {
CommandRegistrationCallback.EVENT.register(this::registerCommand);
}
private void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher, CommandRegistryAccess registry, CommandManager.RegistrationEnvironment env) {
dispatcher.register(CommandManager.literal("upload").then(
CommandManager.literal("schematic")
private void registerCommand(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext registry, Commands.CommandSelection env) {
dispatcher.register(Commands.literal("upload").then(
Commands.literal("schematic")
.executes(this::onRequestSchematic)
));
}
private int onRequestSchematic(CommandContext<ServerCommandSource> context) {
private int onRequestSchematic(CommandContext<CommandSourceStack> context) {
var source = context.getSource();
if (source.isExecutedByPlayer() && !SFConsts.COMMAND_UPLOAD_SCHEMATIC.hasPermission(source.getPlayer())) {
source.sendMessage(Text.literal("你没有使用上传功能的权限!请联系管理员申请"));
if (source.isPlayer() && !SFConsts.COMMAND_UPLOAD_SCHEMATIC.hasPermission(source.getPlayer())) {
source.sendSystemMessage(Component.literal("你没有使用上传功能的权限!请联系管理员申请"));
return Command.SINGLE_SUCCESS;
}
var url = generateSchematicUrl(source.isExecutedByPlayer() ? source.getPlayer().getName().getLiteralString() : "CONSOLE");
source.sendMessage(Text.literal("Click this URL to upload schematic files.").withColor(Color.GREEN.getRGB()));
source.sendMessage(Text.literal(url).styled(it -> it.withClickEvent(new ClickEvent.OpenUrl(URI.create(url)))));
var url = generateSchematicUrl(source.isPlayer() ? source.getPlayer().getName().tryCollapseToString() : "CONSOLE");
source.sendSystemMessage(Component.literal("Click this URL to upload schematic files.").withColor(Color.GREEN.getRGB()));
source.sendSystemMessage(Component.literal(url).withStyle(it -> it.withClickEvent(new ClickEvent.OpenUrl(URI.create(url)))));
return Command.SINGLE_SUCCESS;
}
@@ -139,14 +139,14 @@ public class SchematicUploader extends WebHandler {
if (fileName.length() <= 10) return;
var baseFileName = Helper.cleanFileName(fileName.substring(0, fileName.length() - 10));
var sign = context.<SignatureService.Signature>attribute("sign");
var player = serverSupplier.get().getPlayerManager().getPlayer(sign.issuer());
var player = serverSupplier.get().getPlayerList().getPlayerByName(sign.issuer());
log.info("Handling file {} from player {}", fileName, sign.issuer());
if (fileName.endsWith(".schematic") || fileName.endsWith(".schem")) {
Files.write(SCHEMATIC_DIR.resolve(baseFileName + ".schematic"), file.content().readAllBytes());
log.info("Saved " + fileName + " as a schematic.");
sendSuccess(player, baseFileName);
} else if (fileName.endsWith(".litematic")) {
try (var converter = new LitematicConverterV3(file.content(), new NbtSizeTracker(config.maxSchematicSize, 64))) {
try (var converter = new LitematicConverterV3(file.content(), new NbtAccounter(config.maxSchematicSize, 64))) {
converter.read((name, nbt) -> {
name = baseFileName + "-" + Helper.cleanFileName(name) + ".schematic";
try {
@@ -169,12 +169,12 @@ public class SchematicUploader extends WebHandler {
context.result("Uploaded!");
}
private static void sendSuccess(ServerPlayerEntity player, String fileName) {
private static void sendSuccess(ServerPlayer player, String fileName) {
if (player == null) {
return;
}
player.sendMessage(Text.literal("Schematic " + fileName + " has been saved! Use //schem list to find it").withColor(Color.GREEN.getRGB()));
player.sendMessage(Text.literal("Or you can click this").styled(it -> it.withUnderline(true).withClickEvent(
player.sendSystemMessage(Component.literal("Schematic " + fileName + " has been saved! Use //schem list to find it").withColor(Color.GREEN.getRGB()));
player.sendSystemMessage(Component.literal("Or you can click this").withStyle(it -> it.withUnderlined(true).withClickEvent(
new ClickEvent.SuggestCommand("//schem load " + fileName)
)));
}
@@ -2,15 +2,14 @@ package io.ib67.sfcraft.registry;
import io.ib67.sfcraft.module.randomevt.ActiveEvent;
import io.ib67.sfcraft.module.randomevt.RandomEvent;
import net.minecraft.registry.RegistryKey;
import net.minecraft.world.World;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
public interface RandomEventRegistry {
List<ActiveEvent> getActiveEvents();
void registerEvent(Function<World, RandomEvent> event, RegistryKey<World> world, Predicate<World> worldTickPredicate);
void registerEvent(Function<Level, RandomEvent> event, ResourceKey<Level> world, Predicate<Level> worldTickPredicate);
}
@@ -3,24 +3,23 @@ package io.ib67.sfcraft.registry;
import io.ib67.sfcraft.subserver.Room;
import io.ib67.sfcraft.subserver.RoomFactory;
import io.ib67.sfcraft.subserver.RoomSession;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.world.World;
import java.util.Collection;
import java.util.UUID;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
public interface RoomRegistry {
Collection<? extends Room> getRooms();
Room getRoomBy(Identifier identifier);
Room getRoomBy(ResourceLocation identifier);
RoomSession getRoomBy(UUID player);
<T extends Room> T createRoomOf(Class<T> type, Identifier roomId, ServerPlayerEntity issuer, String... arguments);
<T extends Room> T createRoomOf(Class<T> type, ResourceLocation roomId, ServerPlayer issuer, String... arguments);
boolean isRoomWorld(RegistryKey<World> world);
boolean isRoomWorld(ResourceKey<Level> world);
<T extends Room> void registerRoomType(Class<T> type, RegistryKey<World> worldKey, RoomFactory<T> factory);
<T extends Room> void registerRoomType(Class<T> type, ResourceKey<Level> worldKey, RoomFactory<T> factory);
}
@@ -1,31 +1,31 @@
package io.ib67.sfcraft.registry.chat;
import net.minecraft.network.message.MessageDecorator;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.network.chat.ChatDecorator;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
public class SimpleMessageDecorator implements MessageDecorator {
protected final List<MessageDecorator> decorators = new ArrayList<>();
public class SimpleMessageDecorator implements ChatDecorator {
protected final List<ChatDecorator> decorators = new ArrayList<>();
protected SimpleMessageDecorator() {
}
public void registerDecorator(MessageDecorator decorator) {
public void registerDecorator(ChatDecorator decorator) {
decorators.add(decorator);
}
@Override
public Text decorate(@Nullable ServerPlayerEntity sender, Text message) {
var targets = new ArrayList<Text>();
public Component decorate(@Nullable ServerPlayer sender, Component message) {
var targets = new ArrayList<Component>();
targets.add(message);
for (MessageDecorator decorator : decorators) {
var newRd = new ArrayList<Text>();
for (Text target : targets) {
for (ChatDecorator decorator : decorators) {
var newRd = new ArrayList<Component>();
for (Component target : targets) {
var r = decorator.decorate(sender, target);
var copy = r.copy();
copy.getSiblings().clear();
@@ -34,7 +34,7 @@ public class SimpleMessageDecorator implements MessageDecorator {
}
targets = newRd;
}
var result = Text.empty();
var result = Component.empty();
targets.forEach(result::append);
return result;
}
@@ -7,11 +7,10 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.registry.RegistryKey;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.World;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
@@ -35,15 +34,15 @@ public class SimpleRandomEventRegistry implements RandomEventRegistry {
activeEvents.clear();
}
private void afterWorldTick(ServerWorld serverWorld) {
private void afterWorldTick(ServerLevel serverWorld) {
if (shutdown) return;
triggerEvents(serverWorld);
clearActiveEvents();
}
private void triggerEvents(ServerWorld serverWorld) {
private void triggerEvents(ServerLevel serverWorld) {
for (RegisteredEntry entry : entries) {
if (entry.world == serverWorld.getRegistryKey()
if (entry.world == serverWorld.dimension()
&& !entry.started && entry.worldTickPredicate.test(serverWorld)) {
var event = entry.event.apply(serverWorld);
var ticks = event.start();
@@ -74,7 +73,7 @@ public class SimpleRandomEventRegistry implements RandomEventRegistry {
}
@Override
public void registerEvent(Function<World, RandomEvent> event, RegistryKey<World> world, Predicate<World> worldTickPredicate) {
public void registerEvent(Function<Level, RandomEvent> event, ResourceKey<Level> world, Predicate<Level> worldTickPredicate) {
entries.add(new RegisteredEntry(world, event, worldTickPredicate));
}
@@ -94,9 +93,9 @@ public class SimpleRandomEventRegistry implements RandomEventRegistry {
@RequiredArgsConstructor
private static final class RegisteredEntry {
private final RegistryKey<World> world;
private final Function<World, RandomEvent> event;
private final Predicate<World> worldTickPredicate;
private final ResourceKey<Level> world;
private final Function<Level, RandomEvent> event;
private final Predicate<Level> worldTickPredicate;
private boolean started;
}
}
@@ -4,21 +4,20 @@ import io.ib67.sfcraft.registry.RoomRegistry;
import io.ib67.sfcraft.subserver.Room;
import io.ib67.sfcraft.subserver.RoomFactory;
import io.ib67.sfcraft.subserver.RoomSession;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.world.World;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
public class SimpleRoomRegistry implements RoomRegistry {
private final ConcurrentMap<Identifier, Room> rooms = new ConcurrentHashMap<>();
private final ConcurrentMap<ResourceLocation, Room> rooms = new ConcurrentHashMap<>();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final Map<Class<?>, RoomFactory<?>> factories = new HashMap<>();
private final Set<RegistryKey<World>> roomWorlds = new HashSet<>();
private final Set<ResourceKey<Level>> roomWorlds = new HashSet<>();
@Override
public Collection<? extends Room> getRooms() {
@@ -26,7 +25,7 @@ public class SimpleRoomRegistry implements RoomRegistry {
}
@Override
public Room getRoomBy(Identifier identifier) {
public Room getRoomBy(ResourceLocation identifier) {
return rooms.get(identifier);
}
@@ -44,7 +43,7 @@ public class SimpleRoomRegistry implements RoomRegistry {
}
@Override
public <T extends Room> T createRoomOf(Class<T> type, Identifier roomId, ServerPlayerEntity issuer, String... arguments) {
public <T extends Room> T createRoomOf(Class<T> type, ResourceLocation roomId, ServerPlayer issuer, String... arguments) {
if (getRoomBy(roomId) != null) {
throw new IllegalArgumentException("duplicate room id: " + roomId);
}
@@ -59,12 +58,12 @@ public class SimpleRoomRegistry implements RoomRegistry {
}
@Override
public boolean isRoomWorld(RegistryKey<World> world) {
public boolean isRoomWorld(ResourceKey<Level> world) {
return roomWorlds.contains(world);
}
@Override
public <T extends Room> void registerRoomType(Class<T> type, RegistryKey<World> worldKey, RoomFactory<T> factory) {
public <T extends Room> void registerRoomType(Class<T> type, ResourceKey<Level> worldKey, RoomFactory<T> factory) {
roomWorlds.add(worldKey);
factories.put(type, factory);
}
@@ -2,23 +2,21 @@ package io.ib67.sfcraft.room;
import com.mojang.serialization.Codec;
import io.netty.buffer.ByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.util.Identifier;
import net.minecraft.util.Uuids;
import net.minecraft.util.dynamic.Codecs;
import java.util.UUID;
import net.minecraft.core.UUIDUtil;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
public record RequestedRoom(
Identifier identifier,
ResourceLocation identifier,
String profileName,
UUID profileUuid
) {
public static final PacketCodec<ByteBuf, RequestedRoom> PACKET_CODEC = PacketCodec.tuple(
Identifier.PACKET_CODEC, RequestedRoom::identifier,
PacketCodecs.STRING, RequestedRoom::profileName,
Uuids.PACKET_CODEC, RequestedRoom::profileUuid,
public static final StreamCodec<ByteBuf, RequestedRoom> PACKET_CODEC = StreamCodec.composite(
ResourceLocation.STREAM_CODEC, RequestedRoom::identifier,
ByteBufCodecs.STRING_UTF8, RequestedRoom::profileName,
UUIDUtil.STREAM_CODEC, RequestedRoom::profileUuid,
RequestedRoom::new
);
}
@@ -9,13 +9,13 @@ import io.ib67.sfcraft.module.SignatureService;
import io.ib67.sfcraft.registry.RoomRegistry;
import io.ib67.sfcraft.subserver.Room;
import io.netty.buffer.Unpooled;
import net.minecraft.network.PacketCallbacks;
import net.minecraft.network.packet.s2c.common.ServerTransferS2CPacket;
import net.minecraft.network.packet.s2c.common.StoreCookieS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.util.Identifier;
import net.minecraft.network.PacketSendListener;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.common.ClientboundStoreCookiePacket;
import net.minecraft.network.protocol.common.ClientboundTransferPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.CommonColors;
public class RoomTeleporter {
@Inject
@@ -29,21 +29,21 @@ public class RoomTeleporter {
@Inject
private SFConfig config;
public static final Identifier ROOM_COOKIE = Identifier.of(SFCraft.MOD_ID, "room");
public static final ResourceLocation ROOM_COOKIE = ResourceLocation.fromNamespaceAndPath(SFCraft.MOD_ID, "room");
public void teleportTo(Room room, ServerPlayerEntity player) {
if (roomModule.isVirtual(player.getUuid())) {
player.sendMessage(Text.literal("您已经在某个房间里了").withColor(Colors.LIGHT_RED));
public void teleportTo(Room room, ServerPlayer player) {
if (roomModule.isVirtual(player.getUUID())) {
player.sendSystemMessage(Component.literal("您已经在某个房间里了").withColor(CommonColors.SOFT_RED));
return;
}
var finalUuid = roomModule.generateIdForRoom(player.getGameProfile(), player.getName().getLiteralString(), room.getServerIdentifier());
var finalUuid = roomModule.generateIdForRoom(player.getGameProfile(), player.getName().tryCollapseToString(), room.getServerIdentifier());
var sess = room.getPlayerManager().createSessionFor(finalUuid);
var name = player.getName().getLiteralString();
if (player.getServer().getWorld(sess.getSpawnPosition().dimension()) == null) {
var name = player.getName().tryCollapseToString();
if (player.getServer().getLevel(sess.getSpawnPosition().dimension()) == null) {
throw new IllegalStateException("world isn't exist");
}
var networkHandler = player.networkHandler;
networkHandler.reconfigure();
var networkHandler = player.connection;
networkHandler.switchToConfig();
var request = new RequestedRoom(room.getServerIdentifier(), name, finalUuid);
var requestBuf = Unpooled.buffer();
RequestedRoom.PACKET_CODEC.encode(requestBuf, request);
@@ -56,8 +56,8 @@ public class RoomTeleporter {
requestBuf.array()
)
);
networkHandler.send(new StoreCookieS2CPacket(ROOM_COOKIE, cookie), PacketCallbacks.always(() -> {
networkHandler.sendPacket(new ServerTransferS2CPacket(config.domain, config.port));
networkHandler.send(new ClientboundStoreCookiePacket(ROOM_COOKIE, cookie), PacketSendListener.thenRun(() -> {
networkHandler.send(new ClientboundTransferPacket(config.domain, config.port));
}));
}
}
@@ -6,9 +6,8 @@ import io.ib67.sfcraft.subserver.RoomSession;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.GlobalPos;
import net.minecraft.core.GlobalPos;
import net.minecraft.server.level.ServerPlayer;
import java.util.*;
public abstract class SimpleRoomPlayerManager implements RoomPlayerManager {
@@ -20,7 +19,7 @@ public abstract class SimpleRoomPlayerManager implements RoomPlayerManager {
}
@Override
public List<ServerPlayerEntity> getJoinedPlayers() {
public List<ServerPlayer> getJoinedPlayers() {
return onlinePlayers.values().stream().map(it -> it.player).toList();
}
@@ -49,7 +48,7 @@ public abstract class SimpleRoomPlayerManager implements RoomPlayerManager {
}
@Override
public ServerPlayerEntity getPlayer(UUID uuid) {
public ServerPlayer getPlayer(UUID uuid) {
return onlinePlayers.get(uuid).getPlayer();
}
@@ -72,14 +71,14 @@ public abstract class SimpleRoomPlayerManager implements RoomPlayerManager {
}
@Override
public void onPlayerJoin(ServerPlayerEntity player) {
onlinePlayers.get(player.getUuid()).setPlayer(player);
public void onPlayerJoin(ServerPlayer player) {
onlinePlayers.get(player.getUUID()).setPlayer(player);
session.onPlayerJoin(player);
}
@Override
public void onPlayerQuit(ServerPlayerEntity player) {
onlinePlayers.remove(player.getUuid());
public void onPlayerQuit(ServerPlayer player) {
onlinePlayers.remove(player.getUUID());
session.onPlayerQuit(player);
}
}
@@ -87,7 +86,7 @@ public abstract class SimpleRoomPlayerManager implements RoomPlayerManager {
@Data
@AllArgsConstructor
class PlayerEntry {
private ServerPlayerEntity player;
private ServerPlayer player;
private RoomSession session;
}
}
@@ -3,14 +3,9 @@ package io.ib67.sfcraft.room.create;
import io.ib67.sfcraft.module.room.CreativeRoomModule;
import io.ib67.sfcraft.subserver.Room;
import io.ib67.sfcraft.subserver.RoomSession;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.GlobalPos;
import net.minecraft.world.GameMode;
import java.util.UUID;
import net.minecraft.core.GlobalPos;
import net.minecraft.server.level.ServerPlayer;
public class CreativePlayerSession extends RoomSession {
private final GlobalPos spawn;
@@ -26,7 +21,7 @@ public class CreativePlayerSession extends RoomSession {
}
@Override
public void onPlayerJoin(ServerPlayerEntity player) {
public void onPlayerJoin(ServerPlayer player) {
module.onPlayerJoin(player);
}
@@ -41,7 +36,7 @@ public class CreativePlayerSession extends RoomSession {
}
@Override
public void onPlayerQuit(ServerPlayerEntity player) {
public void onPlayerQuit(ServerPlayer player) {
module.onPlayerQuit(player);
}
}
@@ -2,14 +2,14 @@ package io.ib67.sfcraft.room.create;
import io.ib67.sfcraft.subserver.RoomFactory;
import lombok.RequiredArgsConstructor;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.level.ServerPlayer;
@RequiredArgsConstructor
public class CreativeSpaceFactory implements RoomFactory<CreativeSpaceRoom> {
private final CreativeSpaceRoom room;
@Override
public CreativeSpaceRoom create(ServerPlayerEntity issuer, String[] arguments) {
public CreativeSpaceRoom create(ServerPlayer issuer, String[] arguments) {
return room;
}
}
@@ -5,17 +5,17 @@ import io.ib67.sfcraft.module.room.CreativeRoomModule;
import io.ib67.sfcraft.subserver.Room;
import io.ib67.sfcraft.subserver.RoomPlayerManager;
import lombok.Getter;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
public class CreativeSpaceRoom implements Room {
public static final RegistryKey<World> WORLD = RegistryKey.of(RegistryKeys.WORLD, Identifier.of(SFCraft.MOD_ID, "playground"));
public static final Identifier IDENTIFIER = Identifier.of(SFCraft.MOD_ID, "creative_space");
public static final ResourceKey<Level> WORLD = ResourceKey.create(Registries.DIMENSION, ResourceLocation.fromNamespaceAndPath(SFCraft.MOD_ID, "playground"));
public static final ResourceLocation IDENTIFIER = ResourceLocation.fromNamespaceAndPath(SFCraft.MOD_ID, "creative_space");
public static final BlockPos SPAWN_POS = new BlockPos(0, 66, 0);
@Getter
private final RoomPlayerManager playerManager;
@@ -26,13 +26,13 @@ public class CreativeSpaceRoom implements Room {
@Override
public void shutdown() {
for (ServerPlayerEntity joinedPlayer : playerManager.getJoinedPlayers()) {
joinedPlayer.networkHandler.disconnect(Text.of("Room is shutting down"));
for (ServerPlayer joinedPlayer : playerManager.getJoinedPlayers()) {
joinedPlayer.connection.disconnect(Component.nullToEmpty("Room is shutting down"));
}
}
@Override
public Identifier getServerIdentifier() {
public ResourceLocation getServerIdentifier() {
return IDENTIFIER;
}
}
@@ -1,15 +1,12 @@
package io.ib67.sfcraft.subserver;
import net.minecraft.network.packet.s2c.common.StoreCookieS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.GlobalPos;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import net.minecraft.resources.ResourceLocation;
public interface Room {
Identifier getServerIdentifier();
ResourceLocation getServerIdentifier();
RoomPlayerManager getPlayerManager();
@@ -1,8 +1,8 @@
package io.ib67.sfcraft.subserver;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.level.ServerPlayer;
@FunctionalInterface
public interface RoomFactory<T extends Room> {
T create(ServerPlayerEntity issuer, String[] arguments);
T create(ServerPlayer issuer, String[] arguments);
}
@@ -1,12 +1,11 @@
package io.ib67.sfcraft.subserver;
import net.minecraft.server.network.ServerPlayerEntity;
import java.util.List;
import java.util.UUID;
import net.minecraft.server.level.ServerPlayer;
public interface RoomPlayerManager {
List<ServerPlayerEntity> getJoinedPlayers();
List<ServerPlayer> getJoinedPlayers();
List<RoomSession> getSessions();
@@ -14,5 +13,5 @@ public interface RoomPlayerManager {
RoomSession getSessionBy(UUID uuid);
ServerPlayerEntity getPlayer(UUID uuid);
ServerPlayer getPlayer(UUID uuid);
}
@@ -1,9 +1,8 @@
package io.ib67.sfcraft.subserver;
import lombok.Getter;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.GlobalPos;
import net.minecraft.core.GlobalPos;
import net.minecraft.server.level.ServerPlayer;
import java.util.UUID;
public abstract class RoomSession {
@@ -18,7 +17,7 @@ public abstract class RoomSession {
public abstract void onPlayerLogin(UUID uuid);
public abstract void onPlayerJoin(ServerPlayerEntity player);
public abstract void onPlayerJoin(ServerPlayer player);
public abstract void onPlayerQuit(ServerPlayerEntity player);
public abstract void onPlayerQuit(ServerPlayer player);
}
+27 -34
View File
@@ -8,24 +8,17 @@ import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.config.SFConfig;
import io.ib67.sfcraft.geoip.GeoIPService;
import lombok.SneakyThrows;
import net.minecraft.block.Block;
import net.minecraft.block.CropBlock;
import net.minecraft.block.Fertilizable;
import net.minecraft.block.SaplingBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.EmptyFluid;
import net.minecraft.fluid.LavaFluid;
import net.minecraft.fluid.WaterFluid;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.GameMode;
import net.minecraft.world.World;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.CropBlock;
import net.minecraft.world.level.block.SaplingBlock;
import net.minecraft.world.level.material.EmptyFluid;
import net.minecraft.world.level.material.WaterFluid;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
@@ -41,13 +34,13 @@ public class Helper {
private static final Pattern NON_ASCII = Pattern.compile("[^a-zA-Z0-9_+()]");
public static final char COLOR = '§';
public static boolean canBack(ServerPlayerEntity player) {
public static boolean canBack(ServerPlayer player) {
if (!SFConsts.COMMAND_BACK.hasPermission(player)) return false;
var pos = player.getLastDeathPos().get();
var wld = player.getServer().getWorld(pos.dimension());
var pos = player.getLastDeathLocation().get();
var wld = player.getServer().getLevel(pos.dimension());
var _pos = pos.pos();
if (wld == null) return false;
var nearby = wld.getClosestPlayer(_pos.getX(), _pos.getY(), _pos.getZ(), 100, true);
var nearby = wld.getNearestPlayer(_pos.getX(), _pos.getY(), _pos.getZ(), 100, true);
return nearby != null;
}
@@ -60,37 +53,37 @@ public class Helper {
return NON_ASCII.matcher(name).replaceAll("");
}
public static boolean teleportSafely(ServerPlayerEntity player, ServerWorld world, int x, int y, int z, float yaw, float pitch) {
if (player.getGameMode() == GameMode.CREATIVE) return true;
public static boolean teleportSafely(ServerPlayer player, ServerLevel world, int x, int y, int z, float yaw, float pitch) {
if (player.gameMode() == GameType.CREATIVE) return true;
var pos = new BlockPos(x, y, z);
var stand = world.getBlockState(pos);
if (!stand.isAir() && !stand.isSolidBlock(world, pos)) {
if (!stand.isAir() && !stand.isRedstoneConductor(world, pos)) {
// check block type
var fluid = stand.getFluidState().getFluid();
var fluid = stand.getFluidState().getType();
if (!(fluid instanceof EmptyFluid) && !(fluid instanceof WaterFluid)) {
player.sendMessage(Text.literal("§c传送目的地具有非水流体, 因此拒绝传送。"));
player.sendSystemMessage(Component.literal("§c传送目的地具有非水流体, 因此拒绝传送。"));
return false;
}
}
var groundPos = new BlockPos(x, y - 1, z);
var ground = world.getBlockState(groundPos);
if (!ground.hasSolidTopSurface(world, groundPos, player)
&& !stand.isSolidSurface(world, pos, player, Direction.DOWN)) {
player.sendMessage(Text.literal("§c传送目的地没有可靠落地点,且为非空气方块, 因此拒绝传送。"));
if (!ground.entityCanStandOn(world, groundPos, player)
&& !stand.entityCanStandOnFace(world, pos, player, Direction.DOWN)) {
player.sendSystemMessage(Component.literal("§c传送目的地没有可靠落地点,且为非空气方块, 因此拒绝传送。"));
return false;
} else {
var deltaY = 0.0;
var deltaX = 0.5;
var deltaZ = 0.5;
if (!stand.isAir()) {
deltaY = stand.getCollisionShape(world, pos).getMax(Direction.Axis.Y);
deltaY = stand.getCollisionShape(world, pos).max(Direction.Axis.Y);
deltaY = Double.isFinite(deltaY) ? deltaY + 0.1 : 0;
deltaX = stand.getCollisionShape(world, pos).getMax(Direction.Axis.X);
deltaX = stand.getCollisionShape(world, pos).max(Direction.Axis.X);
deltaX = Double.isFinite(deltaX) ? deltaX / 2 : 0.5;
deltaZ = stand.getCollisionShape(world, pos).getMax(Direction.Axis.X);
deltaZ = stand.getCollisionShape(world, pos).max(Direction.Axis.X);
deltaZ = Double.isFinite(deltaZ) ? deltaZ / 2 : 0.5;
}
player.teleport(world, x + deltaX, y + deltaY, z + deltaZ, Set.of(), yaw, pitch, true);
player.teleportTo(world, x + deltaX, y + deltaY, z + deltaZ, Set.of(), yaw, pitch, true);
}
return true;
}
@@ -1,9 +1,8 @@
package io.ib67.sfcraft.util;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import java.util.Objects;
public record Permission<T extends Entity>(String key, boolean byDefault) {
@@ -24,8 +23,8 @@ public record Permission<T extends Entity>(String key, boolean byDefault) {
}
private boolean check(T t, String permission){
if(t instanceof PlayerEntity player) {
if (player.getCommandTags().contains(permission)){
if(t instanceof Player player) {
if (player.getTags().contains(permission)){
return true;
}
}
@@ -4,30 +4,29 @@ import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.util.Permission;
import lombok.experimental.UtilityClass;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.world.entity.player.Player;
@UtilityClass
public class SFConsts {
public static final String VERSION = FabricLoader.getInstance().getModContainer(SFCraft.MOD_ID).get().getMetadata().getVersion().getFriendlyString();
public static final String SPECIAL_SUDO = "sfcraft.special.state.sudo";
public static final Permission<PlayerEntity> USE_AT = ofSFCPermission("chat.at", true);
public static final Permission<PlayerEntity> USE_BROADCAST_LOCATION = ofSFCPermission("chat.xyz", true);
public static final Permission<PlayerEntity> COMMAND_BACK = ofSFCPermission("command.back", true);
public static final Permission<PlayerEntity> UNLIMITED_COMMAND_BACK = ofSFCPermission("command.back.unlimited", false);
public static final Permission<PlayerEntity> WORLDEDIT_AT_PLAYGROUND = ofSFCPermission("worldedit", true);
public static final Permission<Player> USE_AT = ofSFCPermission("chat.at", true);
public static final Permission<Player> USE_BROADCAST_LOCATION = ofSFCPermission("chat.xyz", true);
public static final Permission<Player> COMMAND_BACK = ofSFCPermission("command.back", true);
public static final Permission<Player> UNLIMITED_COMMAND_BACK = ofSFCPermission("command.back.unlimited", false);
public static final Permission<Player> WORLDEDIT_AT_PLAYGROUND = ofSFCPermission("worldedit", true);
public static final Permission<PlayerEntity> COMMAND_ADDWL = ofSFCPermission("command.addwl", false);
public static final Permission<PlayerEntity> COMMAND_UPLOAD_SCHEMATIC = ofSFCPermission("command.upload.schematic", false);
public static final Permission<PlayerEntity> COMMAND_LISTOFFLINE = ofSFCPermission("command.listoffline", false);
public static final Permission<PlayerEntity> COMMAND_LISTPERM = ofSFCPermission("command.listperm", false);
public static final Permission<PlayerEntity> COMMAND_LISTGEO = ofSFCPermission("command.listgeo", false);
public static final Permission<PlayerEntity> COMMAND_PLAYGROUND = ofSFCPermission("command.playground", true);
public static final Permission<PlayerEntity> COMMAND_PLAYGROUND_GAMEMODE = ofSFCPermission("command.playground.gamemode", true);
public static final Permission<PlayerEntity> COMMAND_PLAYGROUND_TELEPORT = ofSFCPermission("command.playground.teleport", true);
public static final Permission<PlayerEntity> COMMAND_RECO = ofSFCPermission("command.reco", true);
public static final Permission<Player> COMMAND_ADDWL = ofSFCPermission("command.addwl", false);
public static final Permission<Player> COMMAND_UPLOAD_SCHEMATIC = ofSFCPermission("command.upload.schematic", false);
public static final Permission<Player> COMMAND_LISTOFFLINE = ofSFCPermission("command.listoffline", false);
public static final Permission<Player> COMMAND_LISTPERM = ofSFCPermission("command.listperm", false);
public static final Permission<Player> COMMAND_LISTGEO = ofSFCPermission("command.listgeo", false);
public static final Permission<Player> COMMAND_PLAYGROUND = ofSFCPermission("command.playground", true);
public static final Permission<Player> COMMAND_PLAYGROUND_GAMEMODE = ofSFCPermission("command.playground.gamemode", true);
public static final Permission<Player> COMMAND_PLAYGROUND_TELEPORT = ofSFCPermission("command.playground.teleport", true);
public static final Permission<Player> COMMAND_RECO = ofSFCPermission("command.reco", true);
public static Permission<PlayerEntity> ofSFCPermission(String key, boolean byDefault) {
public static Permission<Player> ofSFCPermission(String key, boolean byDefault) {
return new Permission<>("sfcraft." + key, byDefault);
}
}
@@ -1,15 +1,14 @@
package io.ib67.sfcraft.util;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import java.io.DataOutput;
import java.io.IOException;
import java.util.List;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
public class TypedNbtList extends NbtList {
public class TypedNbtList extends ListTag {
private final byte heldType;
public TypedNbtList(List<NbtElement> list, byte type) {
public TypedNbtList(List<Tag> list, byte type) {
super(list);
this.heldType = type;
}
@@ -19,7 +18,7 @@ public class TypedNbtList extends NbtList {
output.writeByte(heldType);
output.writeInt(this.size());
for (NbtElement nbtElement : this) {
for (Tag nbtElement : this) {
nbtElement.write(output);
}
}
@@ -5,7 +5,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.SneakyThrows;
import net.minecraft.nbt.*;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.FriendlyByteBuf;
import org.apache.commons.compress.utils.Lists;
import java.io.InputStream;
@@ -16,20 +16,20 @@ import java.util.stream.Collectors;
/**
* A cleaned up version of https://github.com/GoldenDelicios/Lite2Edit
* Uses {@link NbtCompound} from Minecraft.
* Uses {@link CompoundTag} from Minecraft.
*/
public class LitematicConverter implements AutoCloseable {
protected final InputStream input;
protected final NbtSizeTracker sizeTracker;
protected final NbtAccounter sizeTracker;
public LitematicConverter(InputStream input, NbtSizeTracker sizeTracker) {
public LitematicConverter(InputStream input, NbtAccounter sizeTracker) {
this.input = input;
this.sizeTracker = sizeTracker;
}
@SneakyThrows
public void read(
BiConsumer<String, NbtCompound> schematicOutput
BiConsumer<String, CompoundTag> schematicOutput
) {
var root = NbtIo.readCompressed(input, sizeTracker);
var dataVersion = root.getInt("MinecraftDataVersion")
@@ -37,7 +37,7 @@ public class LitematicConverter implements AutoCloseable {
var regionsNbt = root.getCompound("Regions")
.orElseThrow(() -> new IllegalStateException("Regions not found"));
var i = 0;
for (String regionName : regionsNbt.getKeys()) {
for (String regionName : regionsNbt.keySet()) {
var compound = regionsNbt.getCompound(regionName)
.orElseThrow(() -> new IllegalStateException("Region " + regionName + " not found"));
var j = i++;
@@ -46,8 +46,8 @@ public class LitematicConverter implements AutoCloseable {
}
}
protected NbtCompound convertRegionToSchematic(int dataVersion, NbtCompound region) {
var worldEditTag = new NbtCompound();
protected CompoundTag convertRegionToSchematic(int dataVersion, CompoundTag region) {
var worldEditTag = new CompoundTag();
// prepare metadata
var size = readSizeTuple(region);
@@ -62,20 +62,20 @@ public class LitematicConverter implements AutoCloseable {
// block & tile entities
var paletteNbt = region.getListOrEmpty("BlockStatePalette");
var wePalette = convertToWEPalette(paletteNbt);
worldEditTag.putInt("PaletteMax", wePalette.getKeys().size());
worldEditTag.putInt("PaletteMax", wePalette.keySet().size());
worldEditTag.put("Palette", wePalette);
var tileEntities = region.getListOrEmpty("TileEntities");
worldEditTag.put("BlockEntities", convertToWETileEntities(tileEntities));
worldEditTag.putInt("Version", 2);
worldEditTag.putIntArray("Offset", new int[3]);
worldEditTag.putByteArray("BlockData", convertToWEBlocks(size, region));
var schematicsRoot = new NbtCompound();
var schematicsRoot = new CompoundTag();
schematicsRoot.put("Schematic", worldEditTag);
return schematicsRoot;
}
protected SizeTuple readSizeTuple(NbtCompound region) {
var size = (NbtCompound) region.get("Size");
protected SizeTuple readSizeTuple(CompoundTag region) {
var size = (CompoundTag) region.get("Size");
if (size == null) {
throw new IllegalStateException("Size not found");
}
@@ -88,12 +88,12 @@ public class LitematicConverter implements AutoCloseable {
return new SizeTuple(sizeX, sizeY, sizeZ);
}
protected NbtList convertToWETileEntities(NbtList tileEntities) {
var weTEs = new TypedNbtList(Lists.newArrayList(), NbtElement.COMPOUND_TYPE);
protected ListTag convertToWETileEntities(ListTag tileEntities) {
var weTEs = new TypedNbtList(Lists.newArrayList(), Tag.TAG_COMPOUND);
for (NbtElement _tileEntity : tileEntities) {
var weTE = new NbtCompound();
var tE = (NbtCompound) _tileEntity;
for (Tag _tileEntity : tileEntities) {
var weTE = new CompoundTag();
var tE = (CompoundTag) _tileEntity;
weTE.putIntArray("Pos", new int[]{
tE.getInt("x")
.orElseThrow(() -> new IllegalStateException("Pos X not found")),
@@ -114,17 +114,17 @@ public class LitematicConverter implements AutoCloseable {
return weTEs;
}
protected NbtCompound convertToWEPalette(NbtList paletteNbt) {
var wePalette = new NbtCompound();
protected CompoundTag convertToWEPalette(ListTag paletteNbt) {
var wePalette = new CompoundTag();
for (int i = 0; i < paletteNbt.size(); i++) {
var entry = (NbtCompound) paletteNbt.get(i);
var entry = (CompoundTag) paletteNbt.get(i);
var name = new StringBuilder(entry.getString("Name").orElseThrow(() -> new IllegalStateException("Name not found")));
var _properties = entry.getCompound("Properties");
if (_properties.isPresent()) {
var properties = _properties.get();
name.append("[");
var props = new ArrayList<String>();
for (String key : properties.getKeys()) {
for (String key : properties.keySet()) {
props.add(key + "=" + properties.getString(key));
}
name.append(String.join(",", props));
@@ -135,25 +135,25 @@ public class LitematicConverter implements AutoCloseable {
return wePalette;
}
protected NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) {
var pos = (NbtCompound) region.get("Position");
protected Tag convertToWeMeta(SizeTuple size, CompoundTag region) {
var pos = (CompoundTag) region.get("Position");
if (pos == null){
throw new IllegalStateException("Pos not found");
}
var nbt = new NbtCompound();
var nbt = new CompoundTag();
nbt.putInt("WEOffsetX", pos.getInt("x").orElseThrow() + (size.x < 0 ? size.x + 1 : 0));
nbt.putInt("WEOffsetY", pos.getInt("y").orElseThrow() + (size.y < 0 ? size.y + 1 : 0));
nbt.putInt("WEOffsetZ", pos.getInt("z").orElseThrow() + (size.z < 0 ? size.z + 1 : 0));
return nbt;
}
protected byte[] convertToWEBlocks(SizeTuple size, NbtCompound region) {
protected byte[] convertToWEBlocks(SizeTuple size, CompoundTag region) {
var blockCount = Math.abs(size.x * size.y * size.z);
var blockStates = region.getLongArray("BlockStates").orElse(new long[0]);
int bitsPerBlock = region.getListOrEmpty("BlockStatePalette").size();
bitsPerBlock = Math.max(2, Integer.SIZE - Integer.numberOfLeadingZeros(bitsPerBlock - 1));
int maxEntryValue = (1 << bitsPerBlock) - 1;
var buffer = new PacketByteBuf(Unpooled.buffer());
var buffer = new FriendlyByteBuf(Unpooled.buffer());
for (int index = 0; index < blockCount; index++) {
int startBit = index * bitsPerBlock;
int startLongIndex = startBit / 64;
@@ -4,23 +4,22 @@ import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import lombok.extern.log4j.Log4j2;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtSizeTracker;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.math.Vec3i;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtAccounter;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import java.io.InputStream;
@Log4j2
public class LitematicConverterV3 extends LitematicConverter {
public LitematicConverterV3(InputStream input, NbtSizeTracker sizeTracker) {
public LitematicConverterV3(InputStream input, NbtAccounter sizeTracker) {
super(input, sizeTracker);
}
@Override
protected NbtCompound convertRegionToSchematic(int dataVersion, NbtCompound region) {
var schematicsTag = new NbtCompound();
protected CompoundTag convertRegionToSchematic(int dataVersion, CompoundTag region) {
var schematicsTag = new CompoundTag();
// prepare metadata
var size = readSizeTuple(region);
@@ -39,30 +38,30 @@ public class LitematicConverterV3 extends LitematicConverter {
var wePalette = convertToWEPalette(paletteNbt);
var tileEntities = region.getListOrEmpty("TileEntities");
var blocksNbt = new NbtCompound();
var blocksNbt = new CompoundTag();
blocksNbt.put("Palette", wePalette);
var weBlockData = convertToWEBlocks(size, region);
blocksNbt.putByteArray("Data", weBlockData);
blocksNbt.put("BlockEntities", convertToWETileEntities(tileEntities));
validateData(wePalette, weBlockData, Math.abs(size.x()), Math.abs(size.z()));
schematicsTag.put("Blocks", blocksNbt);
var schematicsRoot = new NbtCompound();
var schematicsRoot = new CompoundTag();
schematicsRoot.put("Schematic", schematicsTag);
return schematicsRoot;
}
private void validateData(
NbtCompound wePalette,
CompoundTag wePalette,
byte[] weBlockData,
int width,
int length
) {
log.info("Validating schematic");
// find invalid palette ids
var buf = new PacketByteBuf(Unpooled.wrappedBuffer(weBlockData));
var buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(weBlockData));
var paletteIds = new Int2ObjectOpenHashMap<>();
var touchedIds = new IntOpenHashSet();
for (String key : wePalette.getKeys()) {
for (String key : wePalette.keySet()) {
paletteIds.put(
wePalette.getInt(key)
.orElseThrow(() -> new IllegalStateException("Cannot find key " + key + " in palette from worldedit schematic"))
@@ -97,18 +96,18 @@ public class LitematicConverterV3 extends LitematicConverter {
}
@Override
protected NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) {
var pos = (NbtCompound) region.get("Position");
protected Tag convertToWeMeta(SizeTuple size, CompoundTag region) {
var pos = (CompoundTag) region.get("Position");
if (pos == null) {
throw new IllegalStateException("Cannot find Position");
}
var worldEditNbt = new NbtCompound();
var worldEditNbt = new CompoundTag();
worldEditNbt.putIntArray("Origin", new int[]{
pos.getInt("x").orElseThrow() + (size.x() < 0 ? size.x() + 1 : 0),
pos.getInt("y").orElseThrow() + (size.y() < 0 ? size.y() + 1 : 0),
pos.getInt("z").orElseThrow() + (size.z() < 0 ? size.z() + 1 : 0)
});
var Metadata = new NbtCompound();
var Metadata = new CompoundTag();
Metadata.put("WorldEdit", worldEditNbt);
Metadata.putLong("Date", System.currentTimeMillis());
+2 -3
View File
@@ -1,4 +1,3 @@
accessWidener v2 named
mutable field net/minecraft/item/Item registryEntry Lnet/minecraft/registry/entry/RegistryEntry$Reference;
accessible method net/minecraft/nbt/NbtList <init> (Ljava/util/List;)V
extendable class net/minecraft/nbt/NbtList
accessible method net/minecraft/nbt/ListTag <init> (Ljava/util/List;)V
extendable class net/minecraft/nbt/ListTag