refactor(ALL): bump minecraft version to 1.21.5

trimmed unused feature: /gamerule CustomEntity API, Custom Item API

We'll use Polymer for replacement in the future.
Tests needed.
This commit is contained in:
iceBear67 committed 2025-03-27 23:24:49 +08:00
1 parent 83c7930142
commit b75b4e1df1
39 files changed
+124 -658

No files matched your search

+1 -2
View File
@@ -2,7 +2,7 @@ plugins {
id 'maven-publish' id 'maven-publish'
id("io.freefair.lombok") version "8.6" id("io.freefair.lombok") version "8.6"
id("com.github.johnrengelman.shadow") version "8.1.1" id("com.github.johnrengelman.shadow") version "8.1.1"
id 'fabric-loom' version '1.7.3' id 'fabric-loom' version '1.10.1'
} }
version = project.mod_version version = project.mod_version
@@ -18,7 +18,6 @@ repositories {
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically. // Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html // See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories. // for more information about repositories.
maven { url 'https://maven.wispforest.io/releases/' }
} }
dependencies { dependencies {
+9 -17
View File
@@ -1,19 +1,11 @@
# Done to increase the memory available to gradle. # Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G org.gradle.jvmargs=-Xmx4G
minecraft_version=1.21.5
# Fabric Properties yarn_mappings=1.21.5+build.1
# check these on https://modmuss50.me/fabric.html loader_version=0.16.10
minecraft_version=1.21 # Fabric API
yarn_mappings=1.21+build.7 fabric_version=0.119.5+1.21.5
loader_version=0.15.11
# Mod Properties # Mod Properties
mod_version = 1.0.0 mod_version=1.0.0
maven_group = io.ib67 maven_group=io.ib67
archives_base_name = sfcraft archives_base_name=sfcraft
# Dependencies
# check this on https://modmuss50.me/fabric.html
fabric_version=0.100.4+1.21
owo_version=0.12.10+1.21
@@ -8,7 +8,6 @@ import io.ib67.sfcraft.module.chat.ChatPrefixModule;
import io.ib67.sfcraft.module.chat.decorator.ChatPingModule; import io.ib67.sfcraft.module.chat.decorator.ChatPingModule;
import io.ib67.sfcraft.module.chat.decorator.ChatSendLocModule; import io.ib67.sfcraft.module.chat.decorator.ChatSendLocModule;
import io.ib67.sfcraft.module.compat.ModCompatModule; import io.ib67.sfcraft.module.compat.ModCompatModule;
import io.ib67.sfcraft.module.randomevt.LongNightModule;
import io.ib67.sfcraft.module.room.CreativeRoomModule; import io.ib67.sfcraft.module.room.CreativeRoomModule;
import io.ib67.sfcraft.module.supervisor.WebModule; import io.ib67.sfcraft.module.supervisor.WebModule;
import io.ib67.sfcraft.module.supervisor.web.SchematicUploader; import io.ib67.sfcraft.module.supervisor.web.SchematicUploader;
@@ -25,9 +24,6 @@ import io.ib67.sfcraft.module.command.ManagementModule;
import io.ib67.sfcraft.registry.room.SimpleRoomRegistry; import io.ib67.sfcraft.registry.room.SimpleRoomRegistry;
import io.ib67.sfcraft.room.RoomTeleporter; import io.ib67.sfcraft.room.RoomTeleporter;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
@Log4j2 @Log4j2
@@ -61,12 +57,10 @@ public class SFCraftInitializer extends GuiceModInitializer {
registerFeature(FartFertilizerModule.class); registerFeature(FartFertilizerModule.class);
registerFeature(ChatPingModule.class); registerFeature(ChatPingModule.class);
registerFeature(ChatSendLocModule.class); registerFeature(ChatSendLocModule.class);
registerFeature(LongNightModule.class);
registerFeature(ModCompatModule.class); registerFeature(ModCompatModule.class);
registerFeature(RoomModule.class); registerFeature(RoomModule.class);
registerFeature(CreativeRoomModule.class); registerFeature(CreativeRoomModule.class);
registerFeature(ChatPrefixModule.class); registerFeature(ChatPrefixModule.class);
registerFeature(CustomItemModule.class);
registerWebModules(); registerWebModules();
} }
@@ -91,7 +85,6 @@ public class SFCraftInitializer extends GuiceModInitializer {
@Override @Override
protected Injector onInit() { protected Injector onInit() {
SFEntityType.registerEntities();
return SFCraft.injector = Guice.createInjector( return SFCraft.injector = Guice.createInjector(
new SFCraft(), new SFCraft(),
this this
@@ -1,52 +0,0 @@
package io.ib67.sfcraft;
import io.ib67.sfcraft.entity.SFGuiderEntity;
import lombok.experimental.UtilityClass;
import lombok.extern.log4j.Log4j2;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Log4j2
public class SFEntityType {
public static final EntityType<SFGuiderEntity> GUIDER = Registry.register(
Registries.ENTITY_TYPE,
Identifier.of(SFCraft.MOD_ID , "guider"),
EntityType.Builder.create(SFGuiderEntity::new, SpawnGroup.CREATURE)
.dimensions(0.35F, 0.6F)
.eyeHeight(0.36F)
.vehicleAttachment(0.04F)
.maxTrackingRange(8)
.trackingTickInterval(2).build()
);
private static SFEntityType registry;
private final Map<EntityType<?>, EntityType<?>> mappedEntityTypes = new ConcurrentHashMap<>();
private void init() {
register(GUIDER, EntityType.ALLAY, SFGuiderEntity.createAllayAttributes().build());
}
private <A extends LivingEntity, B extends LivingEntity> void register(EntityType<B> custom, EntityType<A> origin, DefaultAttributeContainer attr) {
FabricDefaultAttributeRegistry.register(custom, attr);
mappedEntityTypes.put(custom, origin);
}
static void registerEntities() {
registry = new SFEntityType();
registry.init();
}
public static <T extends LivingEntity> EntityType<T> mapToVanilla(EntityType<?> type) {
return (EntityType<T>) registry.mappedEntityTypes.getOrDefault(type, type);
}
}
@@ -1,33 +0,0 @@
package io.ib67.sfcraft;
import io.ib67.sfcraft.item.AeroBackpack;
import io.ib67.sfcraft.mixin.common.bridge.ItemBridge;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.Item;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.util.Identifier;
import static io.ib67.sfcraft.SFRegistries.ITEMS;
public class SFItems {
public static final Item AERO_BACKPACK = register(
new AeroBackpack(new Item.Settings().maxDamage(ArmorItem.Type.CHESTPLATE.getMaxDamage(15))), "aero_backpack");
public static final String SF_ITEM_TYPE_KEY = "sf_type";
public static void init() {
}
private static Item register(Item item, String id) {
Identifier itemID = Identifier.of(SFCraft.MOD_ID, id);
Item registeredItem = Registry.register(ITEMS, itemID, item);
((ItemBridge) registeredItem).setRegistryEntry(ITEMS.getEntry(itemID).get());
return registeredItem;
}
public static Item getById(Identifier item) {
return ITEMS.get(item);
}
}
@@ -1,26 +0,0 @@
package io.ib67.sfcraft.item;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.text.Text;
public class AeroBackpack extends ArmorItem implements TickableItem, SFItem {
private static final Text STATUS_MESSAGE = Text.of("You're wearing aero backpack!");
public AeroBackpack(Settings settings) {
super(ArmorMaterials.IRON, Type.CHESTPLATE, settings);
}
@Override
public void onUpdate(PlayerEntity player, ItemStack stack, EquipmentSlot slot) {
if (slot != EquipmentSlot.CHEST) return;
player.sendMessage(STATUS_MESSAGE, true);
}
@Override
public Item getMappedItem() {
return Items.IRON_CHESTPLATE;
}
}
@@ -1,8 +0,0 @@
package io.ib67.sfcraft.item;
import net.minecraft.item.Item;
import net.minecraft.registry.entry.RegistryEntry;
public interface SFItem {
Item getMappedItem();
}
@@ -1,10 +0,0 @@
package io.ib67.sfcraft.item;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity;
public interface TickableItem {
void onUpdate(PlayerEntity player, ItemStack stack, EquipmentSlot slot);
}
@@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(Entity.class) @Mixin(Entity.class)
public interface EntityBridge { public interface EntityBridge {
@Accessor("FALL_FLYING_FLAG_INDEX") @Accessor("GLIDING_FLAG_INDEX")
static int sfcraft$getFlyingFlagIndex() { static int sfcraft$getFlyingFlagIndex() {
throw new AssertionError(); throw new AssertionError();
} }
@@ -8,6 +8,7 @@ import net.minecraft.block.entity.AbstractFurnaceBlockEntity;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.GameRules; import net.minecraft.world.GameRules;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -26,15 +27,17 @@ public abstract class AbstractFurnaceBlockMixin extends BlockWithEntity {
* @author icybear * @author icybear
* @reason to replace their ticker * @reason to replace their ticker
*/ */
@Nullable
@Overwrite @Overwrite
public static <T extends BlockEntity> @Nullable BlockEntityTicker<T> validateTicker( public static <T extends BlockEntity> BlockEntityTicker<T> validateTicker(
World world, BlockEntityType<T> givenType, BlockEntityType<? extends AbstractFurnaceBlockEntity> expectedType World world, BlockEntityType<T> givenType, BlockEntityType<? extends AbstractFurnaceBlockEntity> expectedType
) { ) {
return world.isClient ? null : BlockWithEntity.validateTicker(givenType, expectedType, AbstractFurnaceBlockMixin::tickMultiple); return world instanceof ServerWorld sw ? BlockWithEntity.validateTicker(givenType, expectedType, AbstractFurnaceBlockMixin::tickMultiple) : null;
} }
@Unique @Unique
private static void tickMultiple(World world, BlockPos pos, BlockState state, AbstractFurnaceBlockEntity blockEntity) { private static <E extends AbstractFurnaceBlockEntity> void tickMultiple(World _world, BlockPos pos, BlockState state, E blockEntity) {
var world = (ServerWorld) _world;
AbstractFurnaceBlockEntity.tick(world, pos, state, blockEntity); AbstractFurnaceBlockEntity.tick(world, pos, state, blockEntity);
int i = world.getGameRules().getInt(GameRules.PLAYERS_SLEEPING_PERCENTAGE); int i = world.getGameRules().getInt(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
if (((ServerWorldBridge) world).getSleepManager().canSkipNight(i)) { if (((ServerWorldBridge) world).getSleepManager().canSkipNight(i)) {
@@ -0,0 +1,12 @@
package io.ib67.sfcraft.mixin.server;
import net.minecraft.server.world.ChunkLevelManager;
import net.minecraft.server.world.ServerChunkManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerChunkManager.class)
public interface ServerChunkManagerMixin {
@Accessor("levelManager")
ChunkLevelManager getLevelManager();
}
@@ -1,11 +1,19 @@
package io.ib67.sfcraft.mixin.server; package io.ib67.sfcraft.mixin.server;
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.util.MixinHelper; import io.ib67.sfcraft.util.MixinHelper;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.GameRules; import net.minecraft.world.GameRules;
import net.minecraft.world.World;
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.Unique;
import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ServerWorld.class) @Mixin(ServerWorld.class)
public abstract class ServerWorldMixin { public abstract class ServerWorldMixin {
@@ -1,17 +0,0 @@
package io.ib67.sfcraft.mixin.server.hack;
import io.ib67.sfcraft.SFCraftInitializer;
import io.ib67.sfcraft.SFEntityType;
import net.minecraft.entity.EntityType;
import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(EntitySpawnS2CPacket.class)
public class EntitySpawnS2CPacketMixin {
@ModifyArg(method = "write", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/codec/PacketCodec;encode(Ljava/lang/Object;Ljava/lang/Object;)V"), index = 1)
public Object mapModType(Object type) {
return SFEntityType.mapToVanilla((EntityType<?>) type);
}
}
@@ -1,18 +0,0 @@
package io.ib67.sfcraft.mixin.server.hack;
import io.ib67.sfcraft.SFCraftInitializer;
import io.ib67.sfcraft.SFEntityType;
import net.minecraft.entity.EntityType;
import net.minecraft.text.HoverEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(HoverEvent.EntityContent.class)
public class HoverEntityContentMixin {
@Inject(method = "method_54198", at = @At("HEAD"), cancellable = true)
private static void sf$mapToVanilla(HoverEvent.EntityContent content, CallbackInfoReturnable<EntityType> cir) {
cir.setReturnValue(SFEntityType.mapToVanilla(content.entityType));
}
}
@@ -1,21 +0,0 @@
package io.ib67.sfcraft.mixin.server.hack;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.fabricmc.fabric.impl.registry.sync.packet.DirectRegistryPacketHandler;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@Mixin(DirectRegistryPacketHandler.class)
public abstract class RegistryHandlerMixin {
@Inject(method = "sendPacket", at = @At("HEAD"), remap = false)
public void sf$removeRegistry(Consumer<DirectRegistryPacketHandler.Payload> sender, Map<Identifier, Object2IntMap<Identifier>> registryMap, CallbackInfo ci) {
registryMap.clear();
}
}
@@ -1,23 +0,0 @@
package io.ib67.sfcraft.mixin.server.item;
import io.ib67.sfcraft.item.SFItem;
import net.minecraft.item.Item;
import net.minecraft.registry.DefaultedRegistry;
import net.minecraft.registry.entry.RegistryEntry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Item.class)
public abstract class ItemMixin {
@Redirect(
method ="<init>",
at= @At(value = "INVOKE", target = "Lnet/minecraft/registry/DefaultedRegistry;createEntry(Ljava/lang/Object;)Lnet/minecraft/registry/entry/RegistryEntry$Reference;")
)
public RegistryEntry.Reference sf$redirectCreateEntry(DefaultedRegistry instance, Object o){
if(this instanceof SFItem) {
return null;
}
return instance.createEntry(o);
}
}
@@ -1,71 +0,0 @@
package io.ib67.sfcraft.mixin.server.item;
import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.SFItems;
import io.ib67.sfcraft.SFRegistries;
import net.minecraft.component.ComponentHolder;
import net.minecraft.component.ComponentMapImpl;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ItemStack.class)
public abstract class ItemStackMixin implements ComponentHolder {
@Shadow
@Final
@Deprecated
@Nullable
private Item item;
@Shadow @Final private static Logger LOGGER;
@Unique
private Item sfItem;
@Shadow public abstract boolean isEmpty();
@Inject(method = "<init>(Lnet/minecraft/item/ItemConvertible;ILnet/minecraft/component/ComponentMapImpl;)V", at = @At("TAIL"))
private void initSFItem(ItemConvertible item, int count, ComponentMapImpl components, CallbackInfo ci) {
var _id = get(DataComponentTypes.CUSTOM_DATA);
if (_id != null && _id.contains(SFItems.SF_ITEM_TYPE_KEY)) {
var id = _id.copyNbt().getString(SFItems.SF_ITEM_TYPE_KEY);
try {
sfItem = SFRegistries.ITEMS.get(Identifier.of(SFCraft.MOD_ID, id));
}catch(Exception e){
e.printStackTrace();
}
if(sfItem == null){
LOGGER.warn("A invalid sfItem is being created: {}", id);
new IllegalStateException("Just stacktrace").printStackTrace();
}
}
}
@Inject(method = "getItem", at = @At("HEAD"), cancellable = true)
private void beforeGetItem(CallbackInfoReturnable<Item> cir) {
if (sfItem != null) cir.setReturnValue(sfItem);
}
@Redirect(method = "getRegistryEntry", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;"))
private Item sf$getMappedEntry(ItemStack instance) {
return isEmpty() ? Items.AIR : this.item;
}
@Redirect(method = "copy", at= @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;"))
private Item sf$getCopySubject(ItemStack instance){
return isEmpty() ? Items.AIR : this.item;
}
}
@@ -1,42 +0,0 @@
package io.ib67.sfcraft.mixin.server.item;
import io.ib67.sfcraft.item.TickableItem;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
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;
@Mixin(PlayerEntity.class)
public abstract class PlayerEntityMixin {
@Shadow
public abstract ItemStack getEquippedStack(EquipmentSlot slot);
@Inject(method = "updateTurtleHelmet", at = @At("TAIL"))
public void sf$tickMyItems(CallbackInfo ci) {
checkAndUpdate(EquipmentSlot.OFFHAND);
checkAndUpdate(EquipmentSlot.MAINHAND);
checkAndUpdate(EquipmentSlot.HEAD);
checkAndUpdate(EquipmentSlot.CHEST);
checkAndUpdate(EquipmentSlot.LEGS);
checkAndUpdate(EquipmentSlot.FEET);
checkAndUpdate(EquipmentSlot.BODY);
}
@Unique
private void checkAndUpdate(EquipmentSlot equipmentSlot) {
var item = getEquippedStack(equipmentSlot);
if (item.getItem() instanceof TickableItem tickableItem) {
tickableItem.onUpdate($this(), item, equipmentSlot);
}
}
@Unique
private PlayerEntity $this() {
return (PlayerEntity) (Object) this;
}
}
@@ -2,6 +2,7 @@ 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.mixin.server.ServerChunkManagerMixin;
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 io.ib67.sfcraft.util.Helper; import io.ib67.sfcraft.util.Helper;
@@ -70,8 +71,8 @@ public abstract class PlayerManagerMixin {
private void teleportToRoom(ServerPlayerEntity player, GlobalPos spawn) { private void teleportToRoom(ServerPlayerEntity player, GlobalPos spawn) {
var world = player.getServer().getWorld(spawn.dimension()); var world = player.getServer().getWorld(spawn.dimension());
var pos = spawn.pos(); var pos = spawn.pos();
world.getChunkManager().chunkLoadingManager.getTicketManager().handleChunkEnter(player.getWatchedSection(), player); ((ServerChunkManagerMixin)world.getChunkManager()).getLevelManager().handleChunkEnter(player.getWatchedSection(), player);
player.teleport(world, pos.getX(), pos.getY(), pos.getZ(), Set.of(), 0, 0); player.teleport(world, pos.getX(), pos.getY(), pos.getZ(), Set.of(), 0, 0, true);
} }
@Inject(method = "remove", at = @At("HEAD")) @Inject(method = "remove", at = @At("HEAD"))
@@ -15,8 +15,10 @@ import java.util.Set;
@Mixin(ServerPlayerEntity.class) @Mixin(ServerPlayerEntity.class)
public abstract class ServerPlayerEntityMixin { public abstract class ServerPlayerEntityMixin {
@Inject(at = @At("HEAD"), method = "teleport(Lnet/minecraft/server/world/ServerWorld;DDDLjava/util/Set;FF)Z", cancellable = true) //todo test this
public void sf$interceptTeleport(ServerWorld world, double destX, double destY, double destZ, Set<PositionFlag> flags, float yaw, float pitch, CallbackInfoReturnable<Boolean> cir) { //todo fix playground operate players in main world
@Inject(at=@At("HEAD"), method = "teleport(Lnet/minecraft/server/world/ServerWorld;DDDLjava/util/Set;FFZ)Z")
public void sf$interceptTeleport(ServerWorld world, double destX, double destY, double destZ, Set<PositionFlag> flags, float yaw, float pitch, boolean resetCamera, CallbackInfoReturnable<Boolean> cir) {
var room = roomRegistry().getRoomBy($this().getUuid()); var room = roomRegistry().getRoomBy($this().getUuid());
if (room != null) { if (room != null) {
if (world.getRegistryKey() != room.getSpawnPosition().dimension()) { if (world.getRegistryKey() != room.getSpawnPosition().dimension()) {
@@ -25,16 +27,6 @@ public abstract class ServerPlayerEntityMixin {
} }
} }
@Inject(at = @At("HEAD"), method = "teleport(Lnet/minecraft/server/world/ServerWorld;DDDFF)V", cancellable = true)
public void sf$interceptTeleport(ServerWorld targetWorld, double x, double y, double z, float yaw, float pitch, CallbackInfo ci) {
var room = roomRegistry().getRoomBy($this().getUuid());
if (room != null) {
if (targetWorld.getRegistryKey() != room.getSpawnPosition().dimension()) {
ci.cancel();
}
}
}
private RoomRegistry roomRegistry() { private RoomRegistry roomRegistry() {
return SFCraft.getInjector().getInstance(RoomRegistry.class); return SFCraft.getInjector().getInstance(RoomRegistry.class);
} }
@@ -1,35 +0,0 @@
package io.ib67.sfcraft.mixin.server.subserver;
import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.module.RoomModule;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(World.class)
public abstract class WorldMixin {
@Shadow
public abstract boolean isClient();
@Shadow
@Final
private RegistryKey<World> registryKey;
@Unique
private GameRules sfcraft$customGameRule;
@Inject(method = "getGameRules", at = @At("HEAD"), cancellable = true)
private void beforeGetGameRules(CallbackInfoReturnable<GameRules> cir) {
if (!isClient() && registryKey.getValue().getNamespace().equals(SFCraft.MOD_ID)) {
if (sfcraft$customGameRule == null) {
sfcraft$customGameRule = SFCraft.getInjector().getInstance(RoomModule.class).readGameRuleForRoom((ServerWorld) (Object) this);
}
cir.setReturnValue(sfcraft$customGameRule);
}
}
}
@@ -1,65 +0,0 @@
package io.ib67.sfcraft.module;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.ib67.sfcraft.SFItems;
import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.item.SFItem;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.command.argument.IdentifierArgumentType;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.NbtComponent;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public class CustomItemModule extends ServerModule {
@Override
public void onInitialize() {
SFItems.init();
CommandRegistrationCallback.EVENT
.register(this::registerCommand);
}
private void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment) {
dispatcher.register(
CommandManager.literal("sfgive")
.then(
CommandManager.argument("item", IdentifierArgumentType.identifier())
.executes(this::performGive)
)
);
}
private static ItemStack getItemByName(Identifier id) throws CommandSyntaxException {
var item = SFItems.getById(id);
if(item == null) return null;
var stack = new ItemStack(((SFItem) item).getMappedItem());
var cmp = new NbtCompound();
cmp.putString(SFItems.SF_ITEM_TYPE_KEY, item.getRegistryEntry().getKey().map(it -> it.getValue().getPath()).orElseThrow());
stack.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(cmp));
return stack.copy();
}
private int performGive(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
var item = IdentifierArgumentType.getIdentifier(context, "item");
if (!context.getSource().isExecutedByPlayer()) {
context.getSource().sendMessage(Text.of("Can't be executed by non-players"));
return 0;
}
var player = context.getSource().getPlayer();
var itemStack = getItemByName(item);
if (itemStack != null) {
player.giveItemStack(itemStack);
}else{
player.sendMessage(Text.of("Item with id "+item.toString()+" not exists."));
}
return 1;
}
}
@@ -2,16 +2,10 @@ package io.ib67.sfcraft.module;
import io.ib67.sfcraft.ServerModule; import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.callback.SFCallbacks; import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.util.ColorHelper;
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.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ElytraItem;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.SubtitleS2CPacket;
import net.minecraft.network.packet.s2c.play.TitleFadeS2CPacket;
import net.minecraft.network.packet.s2c.play.TitleS2CPacket;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
@@ -19,10 +13,6 @@ import net.minecraft.text.MutableText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Colors; import net.minecraft.util.Colors;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Unique;
import java.awt.*;
import java.text.DecimalFormat;
public class ElytraSpeedMeterModule extends ServerModule { public class ElytraSpeedMeterModule extends ServerModule {
private static final int BAR_LEN = 20; private static final int BAR_LEN = 20;
@@ -89,7 +79,7 @@ public class ElytraSpeedMeterModule extends ServerModule {
} }
private Text generateDurabilityMeter(long f, PlayerEntity player) { private Text generateDurabilityMeter(long f, PlayerEntity player) {
var stack = player.getInventory().getArmorStack(PlayerInventory.ARMOR_SLOTS[2]); var stack = player.getEquippedStack(EquipmentSlot.CHEST);
if (stack.isDamageable() && stack.isDamaged()) { if (stack.isDamageable() && stack.isDamaged()) {
var remaining = stack.getMaxDamage() - stack.getDamage(); var remaining = stack.getMaxDamage() - stack.getDamage();
var percent = (int) Math.ceil(((double) remaining / stack.getMaxDamage()) * 100); var percent = (int) Math.ceil(((double) remaining / stack.getMaxDamage()) * 100);
@@ -2,48 +2,32 @@ package io.ib67.sfcraft.module;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import io.ib67.sfcraft.ServerModule; import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.config.SFConfig; import io.ib67.sfcraft.config.SFConfig;
import io.ib67.sfcraft.inject.MinecraftServerSupplier; import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import io.ib67.sfcraft.room.RequestedRoom;
import io.ib67.sfcraft.registry.RoomRegistry; import io.ib67.sfcraft.registry.RoomRegistry;
import io.ib67.sfcraft.room.data.RoomWorldDataLoader;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.command.CommandRegistryAccess;
import net.minecraft.network.PacketCallbacks; import net.minecraft.network.PacketCallbacks;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.network.packet.s2c.common.ServerTransferS2CPacket; import net.minecraft.network.packet.s2c.common.ServerTransferS2CPacket;
import net.minecraft.network.packet.s2c.common.StoreCookieS2CPacket; import net.minecraft.network.packet.s2c.common.StoreCookieS2CPacket;
import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKey;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.world.ChunkTicketType; import net.minecraft.server.world.ChunkTicketType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Pair; import net.minecraft.util.Pair;
import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.GameRules;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.apache.commons.lang3.RandomStringUtils;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.spec.KeySpec;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -76,7 +60,7 @@ public class RoomModule extends ServerModule {
log.warn("Cannot find world {}", registryKeyBlockPosPair.getLeft()); log.warn("Cannot find world {}", registryKeyBlockPosPair.getLeft());
continue; continue;
} }
world.getChunkManager().addTicket(ChunkTicketType.START, new ChunkPos(registryKeyBlockPosPair.getRight()), 64, Unit.INSTANCE); world.getChunkManager().addTicket(ChunkTicketType.START, new ChunkPos(registryKeyBlockPosPair.getRight()), 64);
} }
} }
@@ -90,6 +74,9 @@ public class RoomModule extends ServerModule {
private int onCleanReconnect(CommandContext<ServerCommandSource> serverCommandSourceCommandContext) { private int onCleanReconnect(CommandContext<ServerCommandSource> serverCommandSourceCommandContext) {
var player = serverCommandSourceCommandContext.getSource().getPlayer(); var player = serverCommandSourceCommandContext.getSource().getPlayer();
if (player == null) {
return 0;
}
if (!isVirtual(player.getUuid())) { if (!isVirtual(player.getUuid())) {
player.sendMessage(Text.literal("你不在任何 \"房间\" 内。")); player.sendMessage(Text.literal("你不在任何 \"房间\" 内。"));
return 0; return 0;
@@ -119,8 +106,4 @@ public class RoomModule extends ServerModule {
public GameProfile devirtualize(UUID virtual) { public GameProfile devirtualize(UUID virtual) {
return uuidMapper.get(virtual); return uuidMapper.get(virtual);
} }
public GameRules readGameRuleForRoom(ServerWorld world){
return RoomWorldDataLoader.get(world).getGameRules();
}
} }
@@ -23,6 +23,7 @@ import net.minecraft.text.RawFilteredPair;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Clock; import java.time.Clock;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@@ -51,7 +52,7 @@ public class WelcomeModule extends ServerModule {
player.sendMessage(Text.of("§a您受本服务器成员邀请加入本服务器,以下是一些注意事项:")); player.sendMessage(Text.of("§a您受本服务器成员邀请加入本服务器,以下是一些注意事项:"));
player.sendMessage(Text.of(" - 服务器内已有的设施均为其他玩家的财产,(如可以)使用时请注意礼貌")); player.sendMessage(Text.of(" - 服务器内已有的设施均为其他玩家的财产,(如可以)使用时请注意礼貌"));
player.sendMessage(Text.literal(" - 服务器内有一些非原版特性,可以点击此条消息查看 [特性列表]") player.sendMessage(Text.literal(" - 服务器内有一些非原版特性,可以点击此条消息查看 [特性列表]")
.styled(s -> s.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://wiki.sfclub.cc/s/sfcraft-features")))); .styled(s -> s.withClickEvent(new ClickEvent.OpenUrl(URI.create("https://wiki.sfclub.cc/s/sfcraft-features")))));
player.sendMessage(Text.of("§c - 邀请新成员即等同为其作担保")); player.sendMessage(Text.of("§c - 邀请新成员即等同为其作担保"));
player.sendMessage(Text.of("§7如果您想邀请朋友加入服务器, 可以向管理员提出申请§7 (需备注正/盗版/小号)")); player.sendMessage(Text.of("§7如果您想邀请朋友加入服务器, 可以向管理员提出申请§7 (需备注正/盗版/小号)"));
player.sendMessage(Text.of("§7此外, 本服务器无密码登录,盗版账号安全责任自负")); player.sendMessage(Text.of("§7此外, 本服务器无密码登录,盗版账号安全责任自负"));
@@ -21,7 +21,7 @@ import java.util.regex.MatchResult;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class ChatPingModule extends ServerModule implements MessageDecorator { public class ChatPingModule extends ServerModule implements MessageDecorator {
private static final Pattern PING = Pattern.compile("(@[\\w]+)?"); private static final Pattern PING = Pattern.compile("(@[\\w]+)?"); //todo remove the need of prefix
@Inject @Inject
MinecraftServerSupplier serverSupplier; MinecraftServerSupplier serverSupplier;
@Inject @Inject
@@ -51,7 +51,7 @@ public class ChatPingModule extends ServerModule implements MessageDecorator {
var r = Text.literal(match.replaceAll(it -> this.matchPlayer(it, names, foundPlayers))); var r = Text.literal(match.replaceAll(it -> this.matchPlayer(it, names, foundPlayers)));
for (PlayerEntity foundPlayer : foundPlayers) { for (PlayerEntity foundPlayer : foundPlayers) {
if (sender != null) { if (sender != null) {
foundPlayer.sendMessage(Text.literal(sender.getName().getLiteralString() + " 正在叫你。").withColor(Colors.LIGHT_GRAY)); foundPlayer.sendMessage(Text.literal(sender.getName().getLiteralString() + " 正在叫你。").withColor(Colors.LIGHT_GRAY), true);
} }
foundPlayer.playSoundToPlayer( foundPlayer.playSoundToPlayer(
SoundEvents.ENTITY_ITEM_PICKUP, SoundEvents.ENTITY_ITEM_PICKUP,
@@ -37,7 +37,7 @@ public class ChatSendLocModule extends ServerModule implements MessageDecorator
private static Text generateLocText(ServerPlayerEntity sender) { private static Text generateLocText(ServerPlayerEntity sender) {
if (sender == null) return Text.of(" (invalid position) "); if (sender == null) return Text.of(" (invalid position) ");
sender.addStatusEffect(new StatusEffectInstance(StatusEffects.GLOWING, 15*20)); sender.addStatusEffect(new StatusEffectInstance(StatusEffects.GLOWING, 15 * 20));
var x = sender.getBlockPos().getX(); var x = sender.getBlockPos().getX();
var y = sender.getBlockPos().getY(); var y = sender.getBlockPos().getY();
var z = sender.getBlockPos().getZ(); var z = sender.getBlockPos().getZ();
@@ -46,7 +46,7 @@ public class ChatSendLocModule extends ServerModule implements MessageDecorator
return Text return Text
.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(ClickEvent.Action.RUN_COMMAND, "/gps " + key + " " + x + " " + y + " " + z))); .styled(style -> style.withClickEvent(new ClickEvent.RunCommand("/gps " + key + " " + x + " " + y + " " + z)));
} }
private static String translate(RegistryKey<World> registryKey) { private static String translate(RegistryKey<World> registryKey) {
@@ -55,7 +55,7 @@ public class BackModule extends ServerModule {
public void onPlayerDeath(PlayerEntity player, DamageSource damageSource) { public void onPlayerDeath(PlayerEntity player, DamageSource damageSource) {
if (this.isEnabled() && Helper.canBack((ServerPlayerEntity) player)) { if (this.isEnabled() && Helper.canBack((ServerPlayerEntity) player)) {
player.sendMessage(Text.of("Tip: 死亡地点附近有玩家,可以使用 /back 传送到他们那里。(即使在对方也死亡的状态下)")); player.sendMessage(Text.of("Tip: 死亡地点附近有玩家,可以使用 /back 传送到他们那里。(即使在对方也死亡的状态下)"), false);
} }
} }
} }
@@ -1,54 +0,0 @@
package io.ib67.sfcraft.module.randomevt;
import com.google.inject.Inject;
import com.mojang.datafixers.util.Either;
import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.module.randomevt.longnight.DawnAfterLongNightEvent;
import io.ib67.sfcraft.module.randomevt.longnight.LongNightEvent;
import io.ib67.sfcraft.registry.RandomEventRegistry;
import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.text.Text;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class LongNightModule extends ServerModule {
@Inject
RandomEventRegistry registry;
@Override
public void onInitialize() {
registry.registerEvent(LongNightEvent::new, World.OVERWORLD
, world -> !LongNightEvent.isRunning()
&& isEnabled()
&& world.getTimeOfDay() % 24000 == 18000
&& world.getRandom().nextBetween(0, 100) < 5); // At midnight
registry.registerEvent(DawnAfterLongNightEvent::new, World.OVERWORLD
, world -> world.getTimeOfDay() % 22200 == 0); // At dawn
SFCallbacks.PLAYER_SLEEP.register(this::onPlayerSleep);
UseItemCallback.EVENT.register(this::onUseClock);
}
private TypedActionResult<ItemStack> onUseClock(PlayerEntity player, World world, Hand hand) {
if (player.isSpectator()) return TypedActionResult.pass(ItemStack.EMPTY);
if (player.getStackInHand(hand).isOf(Items.CLOCK)) {
if (LongNightEvent.isRunning())
player.sendMessage(Text.literal("永夜还将持续约 " + LongNightEvent.getRemainingTicks() / 20 + " 秒。").withColor(Colors.LIGHT_GRAY));
}
return TypedActionResult.pass(ItemStack.EMPTY);
}
public Either<PlayerEntity.SleepFailureReason, Unit> onPlayerSleep(PlayerEntity player, BlockPos pos) {
if (!isEnabled()) return Either.right(Unit.INSTANCE);
if (LongNightEvent.isRunning()) {
player.sendMessage(Text.literal("你感到焦躁不安!").withColor(Colors.LIGHT_RED)
.append(Text.literal(" (永夜事件期间无法睡觉)").withColor(Colors.LIGHT_GRAY)));
return Either.left(PlayerEntity.SleepFailureReason.NOT_POSSIBLE_HERE);
}
return Either.right(Unit.INSTANCE);
}
}
@@ -3,6 +3,7 @@ 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.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Colors; import net.minecraft.util.Colors;
import net.minecraft.world.GameRules; import net.minecraft.world.GameRules;
@@ -14,7 +15,7 @@ public class LongNightEvent extends RandomEvent {
static boolean isAtLongNight; static boolean isAtLongNight;
@Getter @Getter
private static int remainingTicks; private static int remainingTicks;
private final World world; private final ServerWorld world;
private boolean doDaylightCycle; private boolean doDaylightCycle;
private boolean doTraderSpawning; private boolean doTraderSpawning;
@@ -45,7 +45,6 @@ import java.util.Set;
public class CreativeRoomModule extends ServerModule { public class CreativeRoomModule extends ServerModule {
private static final Set<String> BYPASS_PERMISSIONS = Set.of( private static final Set<String> BYPASS_PERMISSIONS = Set.of(
"minecraft.command.gamerule",
"carpet.command.player", "carpet.command.player",
"carpet.command.track", "carpet.command.track",
"minecraft.command.setblock", "minecraft.command.setblock",
@@ -30,6 +30,7 @@ import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.awt.*; import java.awt.*;
import java.net.URI;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Base64; import java.util.Base64;
@@ -69,7 +70,7 @@ public class SchematicUploader extends WebHandler {
} }
var url = generateSchematicUrl(source.isExecutedByPlayer() ? source.getPlayer().getName().getLiteralString() : "CONSOLE"); var url = generateSchematicUrl(source.isExecutedByPlayer() ? source.getPlayer().getName().getLiteralString() : "CONSOLE");
source.sendMessage(Text.literal("Click this URL to upload schematic files.").withColor(Color.GREEN.getRGB())); source.sendMessage(Text.literal("Click this URL to upload schematic files.").withColor(Color.GREEN.getRGB()));
source.sendMessage(Text.literal(url).styled(it -> it.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)))); source.sendMessage(Text.literal(url).styled(it -> it.withClickEvent(new ClickEvent.OpenUrl(URI.create(url)))));
return Command.SINGLE_SUCCESS; return Command.SINGLE_SUCCESS;
} }
@@ -173,8 +174,8 @@ public class SchematicUploader extends WebHandler {
return; return;
} }
player.sendMessage(Text.literal("Schematic " + fileName + " has been saved! Use //schem list to find it").withColor(Color.GREEN.getRGB())); player.sendMessage(Text.literal("Schematic " + fileName + " has been saved! Use //schem list to find it").withColor(Color.GREEN.getRGB()));
player.sendMessage(Text.literal("Or you can click this").styled(it->it.withUnderline(true).withClickEvent( player.sendMessage(Text.literal("Or you can click this").styled(it -> it.withUnderline(true).withClickEvent(
new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "//schem load " + fileName) new ClickEvent.SuggestCommand("//schem load " + fileName)
))); )));
} }
} }
@@ -1,55 +0,0 @@
package io.ib67.sfcraft.room.data;
import com.mojang.serialization.Dynamic;
import lombok.Getter;
import net.minecraft.datafixer.DataFixTypes;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtOps;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.GameRules;
import net.minecraft.world.PersistentState;
import java.util.Objects;
@Getter
public class RoomWorldDataLoader extends PersistentState {
private static final String NAME = "sfcraft_room_data";
private static final Type<RoomWorldDataLoader> TYPE = new Type<>(RoomWorldDataLoader::new, RoomWorldDataLoader::readNbt, DataFixTypes.LEVEL);
private static final String TAG_GAME_RULES = "gameRules";
private final GameRules gameRules;
public RoomWorldDataLoader() {
this(new GameRules());
}
public RoomWorldDataLoader(GameRules gameRules) {
this.gameRules = gameRules;
}
public static RoomWorldDataLoader get(ServerWorld world) {
Objects.requireNonNull(world);
var state = world.getPersistentStateManager().getOrCreate(TYPE, NAME);
state.markDirty();
return state;
}
@Override
public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registry) {
nbt.put(TAG_GAME_RULES, gameRules.toNbt());
return nbt;
}
private static RoomWorldDataLoader readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registry) {
if (nbt.contains(TAG_GAME_RULES)) {
var c = nbt.getCompound(TAG_GAME_RULES);
var dynamic = new Dynamic<>(NbtOps.INSTANCE, c);
var rule = new GameRules(dynamic);
return new RoomWorldDataLoader(rule);
}
return new RoomWorldDataLoader();
}
}
@@ -31,6 +31,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -87,7 +88,7 @@ public class Helper {
deltaZ = stand.getCollisionShape(world, pos).getMax(Direction.Axis.X); deltaZ = stand.getCollisionShape(world, pos).getMax(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, yaw, pitch); player.teleport(world, x + deltaX, y + deltaY, z + deltaZ, Set.of(), yaw, pitch, true);
} }
return true; return true;
} }
@@ -8,13 +8,15 @@ import java.io.IOException;
import java.util.List; import java.util.List;
public class TypedNbtList extends NbtList { public class TypedNbtList extends NbtList {
private final byte heldType;
public TypedNbtList(List<NbtElement> list, byte type) { public TypedNbtList(List<NbtElement> list, byte type) {
super(list, type); super(list);
this.heldType = type;
} }
@Override @Override
public void write(DataOutput output) throws IOException { public void write(DataOutput output) throws IOException {
output.writeByte(this.getHeldType()); output.writeByte(heldType);
output.writeInt(this.size()); output.writeInt(this.size());
for (NbtElement nbtElement : this) { for (NbtElement nbtElement : this) {
@@ -10,6 +10,7 @@ import org.apache.commons.compress.utils.Lists;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -31,11 +32,14 @@ public class LitematicConverter implements AutoCloseable {
BiConsumer<String, NbtCompound> schematicOutput BiConsumer<String, NbtCompound> schematicOutput
) { ) {
var root = NbtIo.readCompressed(input, sizeTracker); var root = NbtIo.readCompressed(input, sizeTracker);
var dataVersion = root.getInt("MinecraftDataVersion"); var dataVersion = root.getInt("MinecraftDataVersion")
var regionsNbt = root.getCompound("Regions"); .orElseThrow(() -> new IllegalStateException("MinecraftDataVersion not found"));
var regionsNbt = root.getCompound("Regions")
.orElseThrow(() -> new IllegalStateException("Regions not found"));
var i = 0; var i = 0;
for (String regionName : regionsNbt.getKeys()) { for (String regionName : regionsNbt.getKeys()) {
var compound = regionsNbt.getCompound(regionName); var compound = regionsNbt.getCompound(regionName)
.orElseThrow(() -> new IllegalStateException("Region " + regionName + " not found"));
var j = i++; var j = i++;
var schematic = convertRegionToSchematic(dataVersion, compound); var schematic = convertRegionToSchematic(dataVersion, compound);
schematicOutput.accept(regionName, schematic); schematicOutput.accept(regionName, schematic);
@@ -56,11 +60,11 @@ public class LitematicConverter implements AutoCloseable {
worldEditTag.putShort("Width", (short) Math.abs(size.x)); worldEditTag.putShort("Width", (short) Math.abs(size.x));
// block & tile entities // block & tile entities
var paletteNbt = region.getList("BlockStatePalette", NbtElement.COMPOUND_TYPE); var paletteNbt = region.getListOrEmpty("BlockStatePalette");
var wePalette = convertToWEPalette(paletteNbt); var wePalette = convertToWEPalette(paletteNbt);
worldEditTag.putInt("PaletteMax", wePalette.getKeys().size()); worldEditTag.putInt("PaletteMax", wePalette.getKeys().size());
worldEditTag.put("Palette", wePalette); worldEditTag.put("Palette", wePalette);
var tileEntities = region.getList("TileEntities", NbtElement.COMPOUND_TYPE); 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]);
@@ -72,9 +76,15 @@ public class LitematicConverter implements AutoCloseable {
protected SizeTuple readSizeTuple(NbtCompound region) { protected SizeTuple readSizeTuple(NbtCompound region) {
var size = (NbtCompound) region.get("Size"); var size = (NbtCompound) region.get("Size");
var sizeX = size.getInt("x"); if (size == null) {
var sizeY = size.getInt("y"); throw new IllegalStateException("Size not found");
var sizeZ = size.getInt("z"); }
var sizeX = size.getInt("x")
.orElseThrow(() -> new IllegalStateException("Size X not found"));
var sizeY = size.getInt("y")
.orElseThrow(() -> new IllegalStateException("Size Y not found"));
var sizeZ = size.getInt("z")
.orElseThrow(() -> new IllegalStateException("Size Z not found"));
return new SizeTuple(sizeX, sizeY, sizeZ); return new SizeTuple(sizeX, sizeY, sizeZ);
} }
@@ -85,11 +95,14 @@ public class LitematicConverter implements AutoCloseable {
var weTE = new NbtCompound(); var weTE = new NbtCompound();
var tE = (NbtCompound) _tileEntity; var tE = (NbtCompound) _tileEntity;
weTE.putIntArray("Pos", new int[]{ weTE.putIntArray("Pos", new int[]{
tE.getInt("x"), tE.getInt("x")
tE.getInt("y"), .orElseThrow(() -> new IllegalStateException("Pos X not found")),
tE.getInt("y")
.orElseThrow(() -> new IllegalStateException("Pos Y not found")),
tE.getInt("z") tE.getInt("z")
.orElseThrow(() -> new IllegalStateException("Pos Z not found"))
}); });
weTE.putString("Id", tE.getString("id")); weTE.putString("Id", tE.getString("id").orElseThrow(() -> new IllegalStateException("Id not found")));
// other properties // other properties
tE.remove("x"); tE.remove("x");
tE.remove("y"); tE.remove("y");
@@ -105,15 +118,15 @@ public class LitematicConverter implements AutoCloseable {
var wePalette = new NbtCompound(); var wePalette = new NbtCompound();
for (int i = 0; i < paletteNbt.size(); i++) { for (int i = 0; i < paletteNbt.size(); i++) {
var entry = (NbtCompound) paletteNbt.get(i); var entry = (NbtCompound) paletteNbt.get(i);
var name = new StringBuilder(entry.getString("Name")); var name = new StringBuilder(entry.getString("Name").orElseThrow(() -> new IllegalStateException("Name not found")));
var properties = entry.getCompound("Properties"); var properties = entry.getCompound("Properties").orElseThrow(() -> new IllegalStateException("Properties not found"));
if (!properties.isEmpty()) { if (!properties.isEmpty()) {
name.append("["); name.append("[");
var props = new ArrayList<String>(); var props = new ArrayList<String>();
for (String key : properties.getKeys()) { for (String key : properties.getKeys()) {
props.add(key + "=" + properties.getString(key)); props.add(key + "=" + properties.getString(key));
} }
name.append(props.stream().collect(Collectors.joining(","))); name.append(String.join(",", props));
name.append("]"); name.append("]");
} }
wePalette.putInt(name.toString(), i); wePalette.putInt(name.toString(), i);
@@ -123,17 +136,20 @@ public class LitematicConverter implements AutoCloseable {
protected NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) { protected NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) {
var pos = (NbtCompound) region.get("Position"); var pos = (NbtCompound) region.get("Position");
if (pos == null){
throw new IllegalStateException("Pos not found");
}
var nbt = new NbtCompound(); var nbt = new NbtCompound();
nbt.putInt("WEOffsetX", pos.getInt("x") + (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") + (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") + (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, NbtCompound 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"); var blockStates = region.getLongArray("BlockStates").orElse(new long[0]);
int bitsPerBlock = region.getList("BlockStatePalette", NbtElement.COMPOUND_TYPE).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 PacketByteBuf(Unpooled.buffer());
@@ -35,9 +35,9 @@ public class LitematicConverterV3 extends LitematicConverter {
schematicsTag.putShort("Width", (short) Math.abs(size.x())); schematicsTag.putShort("Width", (short) Math.abs(size.x()));
// block & tile entities // block & tile entities
var paletteNbt = region.getList("BlockStatePalette", NbtElement.COMPOUND_TYPE); var paletteNbt = region.getListOrEmpty("BlockStatePalette");
var wePalette = convertToWEPalette(paletteNbt); var wePalette = convertToWEPalette(paletteNbt);
var tileEntities = region.getList("TileEntities", NbtElement.COMPOUND_TYPE); var tileEntities = region.getListOrEmpty("TileEntities");
var blocksNbt = new NbtCompound(); var blocksNbt = new NbtCompound();
blocksNbt.put("Palette", wePalette); blocksNbt.put("Palette", wePalette);
@@ -63,7 +63,11 @@ public class LitematicConverterV3 extends LitematicConverter {
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.getKeys()) {
paletteIds.put(wePalette.getInt(key), key); paletteIds.put(
wePalette.getInt(key)
.orElseThrow(() -> new IllegalStateException("Cannot find key " + key + " in palette from worldedit schematic"))
, key
);
} }
int counter = 0; int counter = 0;
try { try {
@@ -79,8 +83,8 @@ public class LitematicConverterV3 extends LitematicConverter {
} catch (Exception e) { } catch (Exception e) {
log.error("Error validing schematic", e); log.error("Error validing schematic", e);
} }
paletteIds.keySet().intStream().filter(it->!touchedIds.contains(it)) paletteIds.keySet().intStream().filter(it -> !touchedIds.contains(it))
.forEach(it-> log.error("Unused palette id: {}, blockState: {}", it, paletteIds.get(it))); .forEach(it -> log.error("Unused palette id: {}, blockState: {}", it, paletteIds.get(it)));
} }
private static Vec3i decodePositionFromDataIndex(int width, int length, int index) { private static Vec3i decodePositionFromDataIndex(int width, int length, int index) {
@@ -95,11 +99,14 @@ public class LitematicConverterV3 extends LitematicConverter {
@Override @Override
protected NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) { protected NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) {
var pos = (NbtCompound) region.get("Position"); var pos = (NbtCompound) region.get("Position");
if (pos == null) {
throw new IllegalStateException("Cannot find Position");
}
var worldEditNbt = new NbtCompound(); var worldEditNbt = new NbtCompound();
worldEditNbt.putIntArray("Origin", new int[]{ worldEditNbt.putIntArray("Origin", new int[]{
pos.getInt("x") + (size.x() < 0 ? size.x() + 1 : 0), pos.getInt("x").orElseThrow() + (size.x() < 0 ? size.x() + 1 : 0),
pos.getInt("y") + (size.y() < 0 ? size.y() + 1 : 0), pos.getInt("y").orElseThrow() + (size.y() < 0 ? size.y() + 1 : 0),
pos.getInt("z") + (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 NbtCompound();
Metadata.put("WorldEdit", worldEditNbt); Metadata.put("WorldEdit", worldEditNbt);
+2 -1
View File
@@ -1,3 +1,4 @@
accessWidener v2 named accessWidener v2 named
mutable field net/minecraft/item/Item registryEntry Lnet/minecraft/registry/entry/RegistryEntry$Reference; mutable field net/minecraft/item/Item registryEntry Lnet/minecraft/registry/entry/RegistryEntry$Reference;
accessible method net/minecraft/nbt/NbtList <init> (Ljava/util/List;B)V accessible method net/minecraft/nbt/NbtList <init> (Ljava/util/List;)V
extendable class net/minecraft/nbt/NbtList
+2 -8
View File
@@ -7,7 +7,8 @@
"common.bridge.EntityBridge", "common.bridge.EntityBridge",
"common.bridge.ItemBridge", "common.bridge.ItemBridge",
"common.bridge.ServerPlayerBridge", "common.bridge.ServerPlayerBridge",
"common.bridge.ServerWorldBridge" "common.bridge.ServerWorldBridge",
"server.ServerChunkManagerMixin"
], ],
"client": [ "client": [
], ],
@@ -26,12 +27,6 @@
"server.SleepManagerMixin", "server.SleepManagerMixin",
"server.fixes.EndermanEntityMixin", "server.fixes.EndermanEntityMixin",
"server.fixes.ProjectileEntityMixin", "server.fixes.ProjectileEntityMixin",
"server.hack.EntitySpawnS2CPacketMixin",
"server.hack.HoverEntityContentMixin",
"server.hack.RegistryHandlerMixin",
"server.item.ItemMixin",
"server.item.ItemStackMixin",
"server.item.PlayerEntityMixin",
"server.optimize.LivingEntityMixin", "server.optimize.LivingEntityMixin",
"server.subserver.EntityMixin", "server.subserver.EntityMixin",
"server.subserver.PlayerListS2CPacket$EntryMixin", "server.subserver.PlayerListS2CPacket$EntryMixin",
@@ -39,7 +34,6 @@
"server.subserver.PlayerSaveHandlerMixin", "server.subserver.PlayerSaveHandlerMixin",
"server.subserver.ServerLoginNetworkHandlerMixin", "server.subserver.ServerLoginNetworkHandlerMixin",
"server.subserver.ServerPlayerEntityMixin", "server.subserver.ServerPlayerEntityMixin",
"server.subserver.WorldMixin",
"server.subserver.command.GameRuleCommandMixin" "server.subserver.command.GameRuleCommandMixin"
], ],
"injectors": { "injectors": {