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