remove pca

This commit is contained in:
zly2006 committed 2024-07-11 12:14:02 +08:00
1 parent cb3443d37f
commit 4ba22176bc
24 files changed
+389 -1070

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
plugins { plugins {
id 'fabric-loom' version '1.0-SNAPSHOT' id 'fabric-loom' version '1.6-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
} }
@@ -47,9 +47,6 @@ public class SLSCarpetSettings {
@Rule(categories = {CARPET_ID, PCA, RuleCategory.FEATURE, NEED_CLIENT}) @Rule(categories = {CARPET_ID, PCA, RuleCategory.FEATURE, NEED_CLIENT})
public static boolean emptyShulkerBoxStack = false; public static boolean emptyShulkerBoxStack = false;
@Rule(categories = {CARPET_ID, PCA, RuleCategory.FEATURE})
public static boolean useDyeOnShulkerBox = false;
@Rule(categories = {CARPET_ID, PCA, PROTOCOL}, strict = false, options = {"#none"}) @Rule(categories = {CARPET_ID, PCA, PROTOCOL}, strict = false, options = {"#none"})
public static String xaeroWorldName = "#none"; public static String xaeroWorldName = "#none";
@@ -45,7 +45,6 @@ public class ServerMain implements ModInitializer, CarpetExtension {
public void onInitialize() { public void onInitialize() {
INSTANCE = this; INSTANCE = this;
CarpetServer.manageExtension(this); CarpetServer.manageExtension(this);
PcaSyncProtocol.init();
} }
@Override @Override
@@ -316,7 +316,7 @@ public class BotCommand {
private static int maxNameLength(MinecraftServer server) private static int maxNameLength(MinecraftServer server)
{ {
return server.getServerPort() >= 0 ? PlayerEntity.field_30643 : 40; return 40;
} }
private static int manipulate(CommandContext<ServerCommandSource> context, Consumer<EntityPlayerActionPack> action) private static int manipulate(CommandContext<ServerCommandSource> context, Consumer<EntityPlayerActionPack> action)
@@ -1,55 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.item;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.item.DyeItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.util.ActionResult;
import net.minecraft.util.DyeColor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(DyeItem.class)
public abstract class MixinDyeItem extends Item {
public MixinDyeItem(Settings settings) {
super(settings);
}
@Shadow
public abstract DyeColor getColor();
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
if (!SLSCarpetSettings.useDyeOnShulkerBox) {
return ActionResult.PASS;
}
World world = context.getWorld();
BlockPos pos = context.getBlockPos();
BlockState blockState = world.getBlockState(pos);
if (blockState.isOf(Blocks.SHULKER_BOX)) {
if (!world.isClient()) {
ShulkerBoxBlockEntity blockEntity = (ShulkerBoxBlockEntity) world.getBlockEntity(pos);
BlockState newBlockState = ShulkerBoxBlock.get(getColor()).getDefaultState().with(ShulkerBoxBlock.FACING, blockState.get(ShulkerBoxBlock.FACING));
if (world.setBlockState(pos, newBlockState)) {
ShulkerBoxBlockEntity newBlockEntity = (ShulkerBoxBlockEntity) world.getBlockEntity(pos);
assert blockEntity != null;
assert newBlockEntity != null;
newBlockEntity.readInventoryNbt(blockEntity.createNbt());
newBlockEntity.setCustomName(blockEntity.getCustomName());
newBlockEntity.markDirty();
context.getStack().decrement(1);
}
}
return ActionResult.success(world.isClient);
}
return ActionResult.PASS;
}
}
@@ -1,68 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.item;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.potion.PotionUtil;
import net.minecraft.potion.Potions;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
@Mixin(PotionItem.class)
public abstract class MixinPotionItem extends Item {
public MixinPotionItem(Settings settings) {
super(settings);
}
@Inject(method = "useOnBlock", at = @At(value = "HEAD"), cancellable = true)
public void useOnBlock(ItemUsageContext context, CallbackInfoReturnable<ActionResult> cir) {
ItemStack itemStack = context.getStack();
PlayerEntity player = context.getPlayer();
if (!SLSCarpetSettings.useDyeOnShulkerBox ||
player == null ||
itemStack.getItem() != Items.POTION ||
PotionUtil.getPotion(itemStack) != Potions.WATER) {
return;
}
World world = context.getWorld();
BlockPos pos = context.getBlockPos();
BlockState blockState = world.getBlockState(pos);
Block block = blockState.getBlock();
if (block instanceof ShulkerBoxBlock && ((ShulkerBoxBlock) block).getColor() != null) {
if (!world.isClient()) {
ShulkerBoxBlockEntity blockEntity = (ShulkerBoxBlockEntity) world.getBlockEntity(pos);
BlockState newBlockState = Blocks.SHULKER_BOX.getDefaultState().
with(ShulkerBoxBlock.FACING, blockState.get(ShulkerBoxBlock.FACING));
if (world.setBlockState(pos, newBlockState)) {
ShulkerBoxBlockEntity newBlockEntity = (ShulkerBoxBlockEntity) world.getBlockEntity(pos);
assert blockEntity != null;
assert newBlockEntity != null;
newBlockEntity.readInventoryNbt(blockEntity.createNbt());
newBlockEntity.setCustomName(blockEntity.getCustomName());
newBlockEntity.markDirty();
if (!player.isCreative()) {
context.getStack().decrement(1);
Objects.requireNonNull(context.getPlayer()).getInventory().insertStack(new ItemStack(Items.GLASS_BOTTLE));
}
}
}
cir.setReturnValue(ActionResult.success(world.isClient));
}
}
}
@@ -1,61 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.player;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.util.ShulkerBoxItemUtil;
import me.fallenbreath.conditionalmixin.api.annotation.Condition;
import me.fallenbreath.conditionalmixin.api.annotation.Restriction;
import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Nameable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Restriction(
conflict = @Condition("pca")
)
@Mixin(PlayerInventory.class)
public abstract class MixinPlayerInventory implements Inventory, Nameable {
@Redirect(method = "insertStack(ILnet/minecraft/item/ItemStack;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;getAbilities()Lnet/minecraft/entity/player/PlayerAbilities;"))
private PlayerAbilities insertStack(PlayerEntity instance) {
if (SLSCarpetSettings.creativeNoInfinitePickup) {
AccessorPlayerAbilities accessor = (AccessorPlayerAbilities) instance.getAbilities();
PlayerAbilities abilities = new PlayerAbilities();
AccessorPlayerAbilities accessor1 = (AccessorPlayerAbilities) abilities;
accessor1.setCreativeMode(false);
accessor1.setFlying(accessor.isFlying());
accessor1.setFlyingSpeed(accessor.getFlyingSpeed());
accessor1.setInvulnerable(accessor.isInvulnerable());
accessor1.setAllowFlying(accessor.isAllowFlying());
accessor1.setAllowModifyWorld(accessor.isAllowModifyWorld());
accessor1.setWalkingSpeed(accessor.getWalkingSpeed());
return abilities;
}
return instance.getAbilities();
}
// 修改潜影盒拾取逻辑,使从地上捡起潜影盒时仍可堆叠
@Redirect(method = "canStackAddMore", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isStackable()Z", ordinal = 0))
private boolean canStackAddMoreIsStackable(ItemStack itemStack) {
return ShulkerBoxItemUtil.isStackable(itemStack);
}
@Redirect(method = "canStackAddMore", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getMaxCount()I", ordinal = 0))
private int canStackAddMoreGetMaxCount(ItemStack itemStack) {
return ShulkerBoxItemUtil.getMaxCount(itemStack);
}
@Redirect(method = "addStack(ILnet/minecraft/item/ItemStack;)I", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getMaxCount()I", ordinal = -1))
private int addStackGetMaxCount(ItemStack itemStack) {
return ShulkerBoxItemUtil.getMaxCount(itemStack);
}
// 避免死循环
@Redirect(method = "offer", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getMaxCount()I", ordinal = 0))
private int offerGetMaxCount(ItemStack itemStack) {
return ShulkerBoxItemUtil.getMaxCount(itemStack);
}
}
@@ -1,31 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.AbstractFurnaceBlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.LockableContainerBlockEntity;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.recipe.RecipeInputProvider;
import net.minecraft.recipe.RecipeUnlocker;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(AbstractFurnaceBlockEntity.class)
public abstract class MixinAbstractFurnaceBlockEntity extends LockableContainerBlockEntity implements SidedInventory, RecipeUnlocker, RecipeInputProvider {
protected MixinAbstractFurnaceBlockEntity(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) {
super(blockEntityType, blockPos, blockState);
}
@Override
public void markDirty() {
super.markDirty();
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update AbstractFurnaceBlockEntity: {}", this.pos);
}
}
}
@@ -1,28 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BarrelBlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.LootableContainerBlockEntity;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(BarrelBlockEntity.class)
public abstract class MixinBarrelBlockEntity extends LootableContainerBlockEntity {
protected MixinBarrelBlockEntity(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) {
super(blockEntityType, blockPos, blockState);
}
@Override
public void markDirty() {
super.markDirty();
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update BarrelBlockEntity: {}", this.pos);
}
}
}
@@ -1,62 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BeehiveBlockEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Objects;
@Mixin(BeehiveBlockEntity.class)
public abstract class MixinBeehiveBlockEntity extends BlockEntity {
public MixinBeehiveBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}
@Inject(method = "tickBees", at = @At(value = "INVOKE", target = "Ljava/util/Iterator;remove()V", shift = At.Shift.AFTER))
private static void postTickBees(World world, BlockPos pos, BlockState state, List<Object> bees, BlockPos flowerPos, CallbackInfo ci) {
BlockEntity blockEntity = world.getBlockEntity(pos);
if (blockEntity != null) {
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(blockEntity)) {
ServerMain.LOGGER.debug("update BeehiveBlockEntity: {}", pos);
}
}
}
@Inject(method = "tryReleaseBee", at = @At(value = "RETURN"))
public void postTryReleaseBee(BlockState state, BeehiveBlockEntity.BeeState beeState, CallbackInfoReturnable<List<Entity>> cir) {
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this) && cir.getReturnValue() != null) {
ServerMain.LOGGER.debug("update BeehiveBlockEntity: {}", this.pos);
}
}
@Inject(method = "readNbt", at = @At(value = "RETURN"))
public void postFromTag(NbtCompound nbt, CallbackInfo ci) {
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update BeehiveBlockEntity: {}", this.pos);
}
}
@Inject(method = "tryEnterHive(Lnet/minecraft/entity/Entity;ZI)V", at = @At(value = "INVOKE",
target = "Lnet/minecraft/entity/Entity;discard()V", ordinal = 0))
public void postEnterHive(Entity entity, boolean hasNectar, int ticksInHive, CallbackInfo ci) {
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update BeehiveBlockEntity: {}", this.pos);
}
}
}
@@ -1,28 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.BrewingStandBlockEntity;
import net.minecraft.block.entity.LockableContainerBlockEntity;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(BrewingStandBlockEntity.class)
public abstract class MixinBrewingStandBlockEntity extends LockableContainerBlockEntity implements SidedInventory {
protected MixinBrewingStandBlockEntity(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) {
super(blockEntityType, blockPos, blockState);
}
@Override
public void markDirty() {
super.markDirty();
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update BrewingStandBlockEntity: {}", this.pos);
}
}
}
@@ -1,30 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.block.entity.LidOpenable;
import net.minecraft.block.entity.LootableContainerBlockEntity;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
// 由于陷阱箱继承自箱子,因此不用 mixin 陷阱箱
// implements ChestAnimationProgress 会出错 不知道为啥
@Mixin(ChestBlockEntity.class)
public abstract class MixinChestBlockEntity extends LootableContainerBlockEntity implements LidOpenable {
protected MixinChestBlockEntity(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) {
super(blockEntityType, blockPos, blockState);
}
@Override
public void markDirty() {
super.markDirty();
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update ChestBlockEntity: {}", this.pos);
}
}
}
@@ -1,26 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.ComparatorBlockEntity;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(ComparatorBlockEntity.class)
public abstract class MixinComparatorBlockEntity extends BlockEntity {
public MixinComparatorBlockEntity(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) {
super(blockEntityType, blockPos, blockState);
}
@Override
public void markDirty() {
super.markDirty();
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update ComparatorBlockEntity: {}", this.pos);
}
}
}
@@ -1,27 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.DispenserBlockEntity;
import net.minecraft.block.entity.LootableContainerBlockEntity;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(DispenserBlockEntity.class)
public abstract class MixinDispenserBlockEntity extends LootableContainerBlockEntity {
protected MixinDispenserBlockEntity(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) {
super(blockEntityType, blockPos, blockState);
}
@Override
public void markDirty() {
super.markDirty();
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update DispenserBlockEntity: {}", this.pos);
}
}
}
@@ -1,41 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.Hopper;
import net.minecraft.block.entity.HopperBlockEntity;
import net.minecraft.block.entity.LootableContainerBlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.function.BooleanSupplier;
@Mixin(HopperBlockEntity.class)
public abstract class MixinHopperBlockEntity extends LootableContainerBlockEntity implements Hopper {
protected MixinHopperBlockEntity(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) {
super(blockEntityType, blockPos, blockState);
}
@Inject(method = "insertAndExtract", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/entity/HopperBlockEntity;markDirty(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V"))
private static void onInsertAndExtract(World world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier booleanSupplier, CallbackInfoReturnable<Boolean> cir) {
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(blockEntity)) {
ServerMain.LOGGER.debug("update HopperBlockEntity: {}", pos);
}
}
@Override
public void markDirty() {
super.markDirty();
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update HopperBlockEntity: {}", this.pos);
}
}
}
@@ -1,28 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.LootableContainerBlockEntity;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(ShulkerBoxBlockEntity.class)
public abstract class MixinShulkerBoxBlockEntity extends LootableContainerBlockEntity implements SidedInventory {
protected MixinShulkerBoxBlockEntity(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) {
super(blockEntityType, blockPos, blockState);
}
@Override
public void markDirty() {
super.markDirty();
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncBlockEntityToClient(this)) {
ServerMain.LOGGER.debug("update ShulkerBoxBlockEntity: {}", this.pos);
}
}
}
@@ -1,31 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.entity;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.JumpingMount;
import net.minecraft.entity.Saddleable;
import net.minecraft.entity.passive.AbstractHorseEntity;
import net.minecraft.entity.passive.AnimalEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.InventoryChangedListener;
import net.minecraft.world.World;
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;
@Mixin(AbstractHorseEntity.class)
public abstract class MixinHorseBaseEntity extends AnimalEntity implements InventoryChangedListener, JumpingMount, Saddleable {
protected MixinHorseBaseEntity(EntityType<? extends AnimalEntity> entityType, World world) {
super(entityType, world);
}
@Inject(method = "onInventoryChanged", at = @At(value = "HEAD"))
private void updateEntity(Inventory sender, CallbackInfo ci) {
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncEntityToClient(this)) {
ServerMain.LOGGER.debug("update HorseBaseEntity inventory: onInventoryChanged.");
}
}
}
@@ -1,48 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.entity;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.Npc;
import net.minecraft.entity.passive.MerchantEntity;
import net.minecraft.entity.passive.PassiveEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.InventoryChangedListener;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.village.Merchant;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MerchantEntity.class)
public abstract class MixinMerchantEntity extends PassiveEntity implements Npc, Merchant, InventoryChangedListener {
@Final
@Shadow
private SimpleInventory inventory;
protected MixinMerchantEntity(EntityType<? extends PassiveEntity> entityType, World world) {
super(entityType, world);
}
@Inject(method = "<init>(Lnet/minecraft/entity/EntityType;Lnet/minecraft/world/World;)V", at = @At(value = "RETURN"))
private void addInventoryListener(EntityType<? extends MerchantEntity> entityType, World world, CallbackInfo info) {
if (this.getWorld().isClient()) {
return;
}
this.inventory.addListener(this);
}
@Override
public void onInventoryChanged(Inventory inventory) {
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncEntityToClient(this)) {
ServerMain.LOGGER.debug("update villager inventory: onInventoryChanged.");
}
}
}
@@ -1,29 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.protocol.pcaSyncProtocol.entity;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.network.pca.PcaSyncProtocol;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.StorageMinecartEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.world.World;
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;
@Mixin(StorageMinecartEntity.class)
public abstract class MixinStorageMinecartEntity extends AbstractMinecartEntity implements Inventory, NamedScreenHandlerFactory {
protected MixinStorageMinecartEntity(EntityType<?> entityType, World world) {
super(entityType, world);
}
@Inject(method = "markDirty", at = @At(value = "RETURN"))
private void updateInventory(CallbackInfo ci) {
if (SLSCarpetSettings.pcaSyncProtocol && PcaSyncProtocol.syncEntityToClient(this)) {
ServerMain.LOGGER.debug("update StorageMinecartEntity inventory.");
}
}
}
@@ -1,31 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.screen;
import com.github.zly2006.carpetslsaddition.util.ShulkerBoxItemUtil;
import me.fallenbreath.conditionalmixin.api.annotation.Condition;
import me.fallenbreath.conditionalmixin.api.annotation.Restriction;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.ScreenHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Restriction(
conflict = @Condition("pca")
)
@Mixin(ScreenHandler.class)
public class MixinScreenHandler {
@Redirect(method = "insertItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isStackable()Z", ordinal = 0))
private boolean insertItemIsStackable(ItemStack itemStack) {
return ShulkerBoxItemUtil.isStackable(itemStack);
}
@Redirect(method = "insertItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getMaxCount()I"))
private int insertItemGetMaxCount0(ItemStack itemStack) {
return ShulkerBoxItemUtil.getMaxCount(itemStack);
}
@Redirect(method = "internalOnSlotClick", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getMaxCount()I", ordinal = -1))
private int removeStackGetMaxCount(ItemStack itemStack) {
return ShulkerBoxItemUtil.getMaxCount(itemStack);
}
}
@@ -1,38 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.server;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
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.zip.CRC32;
@Mixin(PlayerManager.class)
public class MixinPlayerManager {
@Inject(method = "sendWorldInfo", at = @At(value = "RETURN"))
public void preOnSendWorldInfo(ServerPlayerEntity player, ServerWorld world, CallbackInfo ci) {
if (SLSCarpetSettings.xaeroWorldName.equals("#none")) {
return;
}
Identifier xaeroworldmap = new Identifier("xaeroworldmap", "main");
Identifier xaerominimap = new Identifier("xaerominimap", "main");
CRC32 crc = new CRC32();
crc.update(SLSCarpetSettings.xaeroWorldName.getBytes());
ByteBuf buf = Unpooled.buffer();
buf.writeByte(0);
buf.writeInt((int) crc.getValue());
ServerPlayNetworking.send(player, xaeroworldmap, new PacketByteBuf(buf.duplicate()));
ServerPlayNetworking.send(player, xaerominimap, new PacketByteBuf(buf.duplicate()));
}
}
@@ -42,383 +42,383 @@ import java.util.Set;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
public class PcaSyncProtocol { public class PcaSyncProtocol {
//
public static final ReentrantLock lock = new ReentrantLock(true); // public static final ReentrantLock lock = new ReentrantLock(true);
public static final ReentrantLock pairLock = new ReentrantLock(true); // public static final ReentrantLock pairLock = new ReentrantLock(true);
// 发送包 // // 发送包
private static final Identifier ENABLE_PCA_SYNC_PROTOCOL = createId("enable_pca_sync_protocol"); // private static final Identifier ENABLE_PCA_SYNC_PROTOCOL = createId("enable_pca_sync_protocol");
private static final Identifier DISABLE_PCA_SYNC_PROTOCOL = createId("disable_pca_sync_protocol"); // private static final Identifier DISABLE_PCA_SYNC_PROTOCOL = createId("disable_pca_sync_protocol");
private static final Identifier UPDATE_ENTITY = createId("update_entity"); // private static final Identifier UPDATE_ENTITY = createId("update_entity");
private static final Identifier UPDATE_BLOCK_ENTITY = createId("update_block_entity"); // private static final Identifier UPDATE_BLOCK_ENTITY = createId("update_block_entity");
// 响应包 // // 响应包
private static final Identifier SYNC_BLOCK_ENTITY = createId("sync_block_entity"); // private static final Identifier SYNC_BLOCK_ENTITY = createId("sync_block_entity");
private static final Identifier SYNC_ENTITY = createId("sync_entity"); // private static final Identifier SYNC_ENTITY = createId("sync_entity");
private static final Identifier CANCEL_SYNC_BLOCK_ENTITY = createId("cancel_sync_block_entity"); // private static final Identifier CANCEL_SYNC_BLOCK_ENTITY = createId("cancel_sync_block_entity");
private static final Identifier CANCEL_SYNC_ENTITY = createId("cancel_sync_entity"); // private static final Identifier CANCEL_SYNC_ENTITY = createId("cancel_sync_entity");
private static final Map<ServerPlayerEntity, Pair<Identifier, BlockPos>> playerWatchBlockPos = new HashMap<>(); // private static final Map<ServerPlayerEntity, Pair<Identifier, BlockPos>> playerWatchBlockPos = new HashMap<>();
private static final Map<ServerPlayerEntity, Pair<Identifier, Entity>> playerWatchEntity = new HashMap<>(); // private static final Map<ServerPlayerEntity, Pair<Identifier, Entity>> playerWatchEntity = new HashMap<>();
private static final Map<Pair<Identifier, BlockPos>, Set<ServerPlayerEntity>> blockPosWatchPlayerSet = new HashMap<>(); // private static final Map<Pair<Identifier, BlockPos>, Set<ServerPlayerEntity>> blockPosWatchPlayerSet = new HashMap<>();
private static final Map<Pair<Identifier, Entity>, Set<ServerPlayerEntity>> entityWatchPlayerSet = new HashMap<>(); // private static final Map<Pair<Identifier, Entity>, Set<ServerPlayerEntity>> entityWatchPlayerSet = new HashMap<>();
private static final MutablePair<Identifier, Entity> identifierEntityPair = new MutablePair<>(); // private static final MutablePair<Identifier, Entity> identifierEntityPair = new MutablePair<>();
private static final MutablePair<Identifier, BlockPos> identifierBlockPosPair = new MutablePair<>(); // private static final MutablePair<Identifier, BlockPos> identifierBlockPosPair = new MutablePair<>();
//
// 通知客户端服务器已启用 PcaSyncProtocol // // 通知客户端服务器已启用 PcaSyncProtocol
public static void enablePcaSyncProtocol(@NotNull ServerPlayerEntity player) { // public static void enablePcaSyncProtocol(@NotNull ServerPlayerEntity player) {
// 在这写如果是在 BC 端的情况下,ServerPlayNetworking.canSend 在这个时机调用会出现错误 // // 在这写如果是在 BC 端的情况下,ServerPlayNetworking.canSend 在这个时机调用会出现错误
ServerMain.LOGGER.debug("Try enablePcaSyncProtocol: {}", player.getName().getString()); // ServerMain.LOGGER.debug("Try enablePcaSyncProtocol: {}", player.getName().getString());
// bc 端比较奇怪,canSend 工作不正常 // // bc 端比较奇怪,canSend 工作不正常
// if (ServerPlayNetworking.canSend(player, ENABLE_PCA_SYNC_PROTOCOL)) { // // if (ServerPlayNetworking.canSend(player, ENABLE_PCA_SYNC_PROTOCOL)) {
PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); // PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
ServerPlayNetworking.send(player, ENABLE_PCA_SYNC_PROTOCOL, buf); // ServerPlayNetworking.send(player, ENABLE_PCA_SYNC_PROTOCOL, buf);
ServerMain.LOGGER.debug("send enablePcaSyncProtocol to {}!", player.getName().getString()); // ServerMain.LOGGER.debug("send enablePcaSyncProtocol to {}!", player.getName().getString());
lock.lock(); // lock.lock();
lock.unlock(); // lock.unlock();
} // }
//
// 通知客户端服务器已停用 PcaSyncProtocol // // 通知客户端服务器已停用 PcaSyncProtocol
public static void disablePcaSyncProtocol(@NotNull ServerPlayerEntity player) { // public static void disablePcaSyncProtocol(@NotNull ServerPlayerEntity player) {
PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); // PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
ServerPlayNetworking.send(player, DISABLE_PCA_SYNC_PROTOCOL, buf); // ServerPlayNetworking.send(player, DISABLE_PCA_SYNC_PROTOCOL, buf);
ServerMain.LOGGER.debug("send disablePcaSyncProtocol to {}!", player.getName().getString()); // ServerMain.LOGGER.debug("send disablePcaSyncProtocol to {}!", player.getName().getString());
} // }
//
// 通知客户端更新 Entity // // 通知客户端更新 Entity
// 包内包含 World 的 Identifier, entityId, entity 的 nbt 数据 // // 包内包含 World 的 Identifier, entityId, entity 的 nbt 数据
// 传输 World 是为了通知客户端该 Entity 属于哪个 World // // 传输 World 是为了通知客户端该 Entity 属于哪个 World
public static void updateEntity(@NotNull ServerPlayerEntity player, @NotNull Entity entity) { // public static void updateEntity(@NotNull ServerPlayerEntity player, @NotNull Entity entity) {
PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); // PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
buf.writeIdentifier(entity.getEntityWorld().getRegistryKey().getValue()); // buf.writeIdentifier(entity.getEntityWorld().getRegistryKey().getValue());
buf.writeInt(entity.getId()); // buf.writeInt(entity.getId());
buf.writeNbt(entity.writeNbt(new NbtCompound())); // buf.writeNbt(entity.writeNbt(new NbtCompound()));
ServerPlayNetworking.send(player, UPDATE_ENTITY, buf); // ServerPlayNetworking.send(player, UPDATE_ENTITY, buf);
} // }
//
// 通知客户端更新 BlockEntity // // 通知客户端更新 BlockEntity
// 包内包含 World 的 Identifier, pos, blockEntity 的 nbt 数据 // // 包内包含 World 的 Identifier, pos, blockEntity 的 nbt 数据
// 传输 World 是为了通知客户端该 BlockEntity 属于哪个世界 // // 传输 World 是为了通知客户端该 BlockEntity 属于哪个世界
public static void updateBlockEntity(@NotNull ServerPlayerEntity player, @NotNull BlockEntity blockEntity) { // public static void updateBlockEntity(@NotNull ServerPlayerEntity player, @NotNull BlockEntity blockEntity) {
World world = blockEntity.getWorld(); // World world = blockEntity.getWorld();
//
// 在生成世界时可能会产生空指针 // // 在生成世界时可能会产生空指针
if (world == null) { // if (world == null) {
return; // return;
} // }
//
PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); // PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
buf.writeIdentifier(world.getRegistryKey().getValue()); // buf.writeIdentifier(world.getRegistryKey().getValue());
buf.writeBlockPos(blockEntity.getPos()); // buf.writeBlockPos(blockEntity.getPos());
buf.writeNbt(blockEntity.createNbt()); // buf.writeNbt(blockEntity.createNbt());
ServerPlayNetworking.send(player, UPDATE_BLOCK_ENTITY, buf); // ServerPlayNetworking.send(player, UPDATE_BLOCK_ENTITY, buf);
} // }
//
public static void init() { // public static void init() {
ServerPlayNetworking.registerGlobalReceiver(SYNC_BLOCK_ENTITY, PcaSyncProtocol::syncBlockEntityHandler); // ServerPlayNetworking.registerGlobalReceiver(SYNC_BLOCK_ENTITY, PcaSyncProtocol::syncBlockEntityHandler);
ServerPlayNetworking.registerGlobalReceiver(SYNC_ENTITY, PcaSyncProtocol::syncEntityHandler); // ServerPlayNetworking.registerGlobalReceiver(SYNC_ENTITY, PcaSyncProtocol::syncEntityHandler);
ServerPlayNetworking.registerGlobalReceiver(CANCEL_SYNC_BLOCK_ENTITY, PcaSyncProtocol::cancelSyncBlockEntityHandler); // ServerPlayNetworking.registerGlobalReceiver(CANCEL_SYNC_BLOCK_ENTITY, PcaSyncProtocol::cancelSyncBlockEntityHandler);
ServerPlayNetworking.registerGlobalReceiver(CANCEL_SYNC_ENTITY, PcaSyncProtocol::cancelSyncEntityHandler); // ServerPlayNetworking.registerGlobalReceiver(CANCEL_SYNC_ENTITY, PcaSyncProtocol::cancelSyncEntityHandler);
ServerPlayConnectionEvents.JOIN.register(PcaSyncProtocol::onJoin); // ServerPlayConnectionEvents.JOIN.register(PcaSyncProtocol::onJoin);
ServerPlayConnectionEvents.DISCONNECT.register(PcaSyncProtocol::onDisconnect); // ServerPlayConnectionEvents.DISCONNECT.register(PcaSyncProtocol::onDisconnect);
} // }
//
private static void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) { // private static void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) {
if (SLSCarpetSettings.pcaSyncProtocol) { // if (SLSCarpetSettings.pcaSyncProtocol) {
ServerMain.LOGGER.debug("onDisconnect remove: {}", serverPlayNetworkHandler.player.getName().getString()); // ServerMain.LOGGER.debug("onDisconnect remove: {}", serverPlayNetworkHandler.player.getName().getString());
} // }
} // }
//
private static void onJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) { // private static void onJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) {
if (SLSCarpetSettings.pcaSyncProtocol) { // if (SLSCarpetSettings.pcaSyncProtocol) {
enablePcaSyncProtocol(serverPlayNetworkHandler.player); // enablePcaSyncProtocol(serverPlayNetworkHandler.player);
} // }
} // }
//
// 客户端通知服务端取消 BlockEntity 同步 // // 客户端通知服务端取消 BlockEntity 同步
private static void cancelSyncBlockEntityHandler(MinecraftServer server, ServerPlayerEntity player, // private static void cancelSyncBlockEntityHandler(MinecraftServer server, ServerPlayerEntity player,
ServerPlayNetworkHandler handler, PacketByteBuf buf, // ServerPlayNetworkHandler handler, PacketByteBuf buf,
PacketSender responseSender) { // PacketSender responseSender) {
if (!SLSCarpetSettings.pcaSyncProtocol) { // if (!SLSCarpetSettings.pcaSyncProtocol) {
return; // return;
} // }
ServerMain.LOGGER.debug("{} cancel watch blockEntity.", player.getName().getString()); // ServerMain.LOGGER.debug("{} cancel watch blockEntity.", player.getName().getString());
PcaSyncProtocol.clearPlayerWatchBlock(player); // PcaSyncProtocol.clearPlayerWatchBlock(player);
} // }
//
// 客户端通知服务端取消 Entity 同步 // // 客户端通知服务端取消 Entity 同步
private static void cancelSyncEntityHandler(MinecraftServer server, ServerPlayerEntity player, // private static void cancelSyncEntityHandler(MinecraftServer server, ServerPlayerEntity player,
ServerPlayNetworkHandler handler, PacketByteBuf buf, // ServerPlayNetworkHandler handler, PacketByteBuf buf,
PacketSender responseSender) { // PacketSender responseSender) {
if (!SLSCarpetSettings.pcaSyncProtocol) { // if (!SLSCarpetSettings.pcaSyncProtocol) {
return; // return;
} // }
ServerMain.LOGGER.debug("{} cancel watch entity.", player.getName().getString()); // ServerMain.LOGGER.debug("{} cancel watch entity.", player.getName().getString());
PcaSyncProtocol.clearPlayerWatchEntity(player); // PcaSyncProtocol.clearPlayerWatchEntity(player);
} // }
//
// 客户端请求同步 BlockEntity // // 客户端请求同步 BlockEntity
// 包内包含 pos // // 包内包含 pos
// 由于正常的场景一般不会跨世界请求数据,因此包内并不包含 World,以玩家所在的 World 为准 // // 由于正常的场景一般不会跨世界请求数据,因此包内并不包含 World,以玩家所在的 World 为准
private static void syncBlockEntityHandler(MinecraftServer server, ServerPlayerEntity player, // private static void syncBlockEntityHandler(MinecraftServer server, ServerPlayerEntity player,
ServerPlayNetworkHandler handler, PacketByteBuf buf, // ServerPlayNetworkHandler handler, PacketByteBuf buf,
PacketSender responseSender) { // PacketSender responseSender) {
if (!SLSCarpetSettings.pcaSyncProtocol) { // if (!SLSCarpetSettings.pcaSyncProtocol) {
return; // return;
} // }
BlockPos pos = buf.readBlockPos(); // BlockPos pos = buf.readBlockPos();
ServerWorld world = player.getServerWorld(); // ServerWorld world = player.getServerWorld();
BlockState blockState = world.getBlockState(pos); // BlockState blockState = world.getBlockState(pos);
clearPlayerWatchData(player); // clearPlayerWatchData(player);
ServerMain.LOGGER.debug("{} watch blockpos {}: {}", player.getName().getString(), pos, blockState); // ServerMain.LOGGER.debug("{} watch blockpos {}: {}", player.getName().getString(), pos, blockState);
//
BlockEntity blockEntityAdj = null; // BlockEntity blockEntityAdj = null;
// 不是单个箱子则需要更新隔壁箱子 // // 不是单个箱子则需要更新隔壁箱子
if (blockState.getBlock() instanceof ChestBlock) { // if (blockState.getBlock() instanceof ChestBlock) {
if (blockState.get(ChestBlock.CHEST_TYPE) != ChestType.SINGLE) { // if (blockState.get(ChestBlock.CHEST_TYPE) != ChestType.SINGLE) {
BlockPos posAdj = pos.offset(ChestBlock.getFacing(blockState)); // BlockPos posAdj = pos.offset(ChestBlock.getFacing(blockState));
// The method in World now checks that the caller is from the same thread... // // The method in World now checks that the caller is from the same thread...
blockEntityAdj = world.getWorldChunk(posAdj).getBlockEntity(posAdj); // blockEntityAdj = world.getWorldChunk(posAdj).getBlockEntity(posAdj);
} // }
} else if (ServerMain.tisCarpetLoaded && blockState.isOf(Blocks.BARREL) && RuleHelper.getBooleanValue(getCarpetRule("largeBarrel"))) { // } else if (ServerMain.tisCarpetLoaded && blockState.isOf(Blocks.BARREL) && RuleHelper.getBooleanValue(getCarpetRule("largeBarrel"))) {
Direction directionOpposite = blockState.get(BarrelBlock.FACING).getOpposite(); // Direction directionOpposite = blockState.get(BarrelBlock.FACING).getOpposite();
BlockPos posAdj = pos.offset(directionOpposite); // BlockPos posAdj = pos.offset(directionOpposite);
BlockState blockStateAdj = world.getBlockState(posAdj); // BlockState blockStateAdj = world.getBlockState(posAdj);
if (blockStateAdj.isOf(Blocks.BARREL) && blockStateAdj.get(BarrelBlock.FACING) == directionOpposite) { // if (blockStateAdj.isOf(Blocks.BARREL) && blockStateAdj.get(BarrelBlock.FACING) == directionOpposite) {
blockEntityAdj = world.getWorldChunk(posAdj).getBlockEntity(posAdj); // blockEntityAdj = world.getWorldChunk(posAdj).getBlockEntity(posAdj);
} // }
} // }
//
if (blockEntityAdj != null) { // if (blockEntityAdj != null) {
updateBlockEntity(player, blockEntityAdj); // updateBlockEntity(player, blockEntityAdj);
} // }
//
// 本来想判断一下 blockState 类型做个白名单的,考虑到 client 已经做了判断就不在服务端做判断了 // // 本来想判断一下 blockState 类型做个白名单的,考虑到 client 已经做了判断就不在服务端做判断了
// 就算被恶意攻击应该不会造成什么损失 // // 就算被恶意攻击应该不会造成什么损失
// 大不了 op 直接拉黑 // // 大不了 op 直接拉黑
// The method in World now checks that the caller is from the same thread... // // The method in World now checks that the caller is from the same thread...
BlockEntity blockEntity = world.getWorldChunk(pos).getBlockEntity(pos); // BlockEntity blockEntity = world.getWorldChunk(pos).getBlockEntity(pos);
if (blockEntity != null) { // if (blockEntity != null) {
updateBlockEntity(player, blockEntity); // updateBlockEntity(player, blockEntity);
} // }
//
Pair<Identifier, BlockPos> pair = new ImmutablePair<>(player.getEntityWorld().getRegistryKey().getValue(), pos); // Pair<Identifier, BlockPos> pair = new ImmutablePair<>(player.getEntityWorld().getRegistryKey().getValue(), pos);
lock.lock(); // lock.lock();
playerWatchBlockPos.put(player, pair); // playerWatchBlockPos.put(player, pair);
if (!blockPosWatchPlayerSet.containsKey(pair)) { // if (!blockPosWatchPlayerSet.containsKey(pair)) {
blockPosWatchPlayerSet.put(pair, new HashSet<>()); // blockPosWatchPlayerSet.put(pair, new HashSet<>());
} // }
blockPosWatchPlayerSet.get(pair).add(player); // blockPosWatchPlayerSet.get(pair).add(player);
lock.unlock(); // lock.unlock();
} // }
//
// 客户端请求同步 Entity // // 客户端请求同步 Entity
// 包内包含 entityId // // 包内包含 entityId
// 由于正常的场景一般不会跨世界请求数据,因此包内并不包含 World,以玩家所在的 World 为准 // // 由于正常的场景一般不会跨世界请求数据,因此包内并不包含 World,以玩家所在的 World 为准
private static void syncEntityHandler(MinecraftServer server, ServerPlayerEntity player, // private static void syncEntityHandler(MinecraftServer server, ServerPlayerEntity player,
ServerPlayNetworkHandler handler, PacketByteBuf buf, // ServerPlayNetworkHandler handler, PacketByteBuf buf,
PacketSender responseSender) { // PacketSender responseSender) {
if (!SLSCarpetSettings.pcaSyncProtocol) { // if (!SLSCarpetSettings.pcaSyncProtocol) {
return; // return;
} // }
int entityId = buf.readInt(); // int entityId = buf.readInt();
ServerWorld world = player.getServerWorld(); // ServerWorld world = player.getServerWorld();
Entity entity = world.getEntityById(entityId); // Entity entity = world.getEntityById(entityId);
if (entity == null) { // if (entity == null) {
ServerMain.LOGGER.debug("Can't find entity {}.", entityId); // ServerMain.LOGGER.debug("Can't find entity {}.", entityId);
} else { // } else {
clearPlayerWatchData(player); // clearPlayerWatchData(player);
if (entity instanceof PlayerEntity) { // if (entity instanceof PlayerEntity) {
if (SLSCarpetSettings.pcaSyncPlayerEntity == SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.NOBODY) { // if (SLSCarpetSettings.pcaSyncPlayerEntity == SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.NOBODY) {
return; // return;
} else if (SLSCarpetSettings.pcaSyncPlayerEntity == SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.BOT) { // } else if (SLSCarpetSettings.pcaSyncPlayerEntity == SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.BOT) {
if (!(entity instanceof EntityPlayerMPFake)) { // if (!(entity instanceof EntityPlayerMPFake)) {
return; // return;
} // }
} else if (SLSCarpetSettings.pcaSyncPlayerEntity == SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.OPS) { // } else if (SLSCarpetSettings.pcaSyncPlayerEntity == SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.OPS) {
if (!(entity instanceof EntityPlayerMPFake) && server.getPermissionLevel(player.getGameProfile()) < 2) { // if (!(entity instanceof EntityPlayerMPFake) && server.getPermissionLevel(player.getGameProfile()) < 2) {
return; // return;
} // }
} else if (SLSCarpetSettings.pcaSyncPlayerEntity == SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.OPS_AND_SELF) { // } else if (SLSCarpetSettings.pcaSyncPlayerEntity == SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.OPS_AND_SELF) {
if (!(entity instanceof EntityPlayerMPFake) && // if (!(entity instanceof EntityPlayerMPFake) &&
server.getPermissionLevel(player.getGameProfile()) < 2 && // server.getPermissionLevel(player.getGameProfile()) < 2 &&
entity != player) { // entity != player) {
return; // return;
} // }
} else if (SLSCarpetSettings.pcaSyncPlayerEntity != SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.EVERYONE) { // } else if (SLSCarpetSettings.pcaSyncPlayerEntity != SLSCarpetSettings.PCA_SYNC_PLAYER_ENTITY_OPTIONS.EVERYONE) {
// wtf???? // // wtf????
ServerMain.LOGGER.warn("syncEntityHandler wtf???"); // ServerMain.LOGGER.warn("syncEntityHandler wtf???");
return; // return;
} // }
} // }
ServerMain.LOGGER.debug("{} watch entity {}: {}", player.getName().getString(), entityId, entity); // ServerMain.LOGGER.debug("{} watch entity {}: {}", player.getName().getString(), entityId, entity);
updateEntity(player, entity); // updateEntity(player, entity);
//
Pair<Identifier, Entity> pair = new ImmutablePair<>(entity.getEntityWorld().getRegistryKey().getValue(), entity); // Pair<Identifier, Entity> pair = new ImmutablePair<>(entity.getEntityWorld().getRegistryKey().getValue(), entity);
lock.lock(); // lock.lock();
playerWatchEntity.put(player, pair); // playerWatchEntity.put(player, pair);
if (!entityWatchPlayerSet.containsKey(pair)) { // if (!entityWatchPlayerSet.containsKey(pair)) {
entityWatchPlayerSet.put(pair, new HashSet<>()); // entityWatchPlayerSet.put(pair, new HashSet<>());
} // }
entityWatchPlayerSet.get(pair).add(player); // entityWatchPlayerSet.get(pair).add(player);
lock.unlock(); // lock.unlock();
} // }
} // }
//
private static MutablePair<Identifier, Entity> getIdentifierEntityPair(Identifier identifier, Entity entity) { // private static MutablePair<Identifier, Entity> getIdentifierEntityPair(Identifier identifier, Entity entity) {
pairLock.lock(); // pairLock.lock();
identifierEntityPair.setLeft(identifier); // identifierEntityPair.setLeft(identifier);
identifierEntityPair.setRight(entity); // identifierEntityPair.setRight(entity);
pairLock.unlock(); // pairLock.unlock();
return identifierEntityPair; // return identifierEntityPair;
} // }
//
private static MutablePair<Identifier, BlockPos> getIdentifierBlockPosPair(Identifier identifier, BlockPos pos) { // private static MutablePair<Identifier, BlockPos> getIdentifierBlockPosPair(Identifier identifier, BlockPos pos) {
pairLock.lock(); // pairLock.lock();
identifierBlockPosPair.setLeft(identifier); // identifierBlockPosPair.setLeft(identifier);
identifierBlockPosPair.setRight(pos); // identifierBlockPosPair.setRight(pos);
pairLock.unlock(); // pairLock.unlock();
return identifierBlockPosPair; // return identifierBlockPosPair;
} // }
//
// 工具 // // 工具
private static @Nullable Set<ServerPlayerEntity> getWatchPlayerList(@NotNull Entity entity) { // private static @Nullable Set<ServerPlayerEntity> getWatchPlayerList(@NotNull Entity entity) {
return entityWatchPlayerSet.get(getIdentifierEntityPair(entity.getEntityWorld().getRegistryKey().getValue(), entity)); // return entityWatchPlayerSet.get(getIdentifierEntityPair(entity.getEntityWorld().getRegistryKey().getValue(), entity));
} // }
//
private static @Nullable Set<ServerPlayerEntity> getWatchPlayerList(@NotNull World world, @NotNull BlockPos blockPos) { // private static @Nullable Set<ServerPlayerEntity> getWatchPlayerList(@NotNull World world, @NotNull BlockPos blockPos) {
return blockPosWatchPlayerSet.get(getIdentifierBlockPosPair(world.getRegistryKey().getValue(), blockPos)); // return blockPosWatchPlayerSet.get(getIdentifierBlockPosPair(world.getRegistryKey().getValue(), blockPos));
} // }
//
public static boolean syncEntityToClient(@NotNull Entity entity) { // public static boolean syncEntityToClient(@NotNull Entity entity) {
if (entity.getEntityWorld().isClient()) { // if (entity.getEntityWorld().isClient()) {
return false; // return false;
} // }
lock.lock(); // lock.lock();
Set<ServerPlayerEntity> playerList = getWatchPlayerList(entity); // Set<ServerPlayerEntity> playerList = getWatchPlayerList(entity);
boolean ret = false; // boolean ret = false;
if (playerList != null) { // if (playerList != null) {
for (ServerPlayerEntity player : playerList) { // for (ServerPlayerEntity player : playerList) {
updateEntity(player, entity); // updateEntity(player, entity);
ret = true; // ret = true;
} // }
} // }
lock.unlock(); // lock.unlock();
return ret; // return ret;
} // }
//
public static boolean syncBlockEntityToClient(@NotNull BlockEntity blockEntity) { // public static boolean syncBlockEntityToClient(@NotNull BlockEntity blockEntity) {
boolean ret = false; // boolean ret = false;
World world = blockEntity.getWorld(); // World world = blockEntity.getWorld();
BlockPos pos = blockEntity.getPos(); // BlockPos pos = blockEntity.getPos();
// 在生成世界时可能会产生空指针 // // 在生成世界时可能会产生空指针
if (world != null) { // if (world != null) {
if (world.isClient()) { // if (world.isClient()) {
return false; // return false;
} // }
BlockState blockState = world.getBlockState(pos); // BlockState blockState = world.getBlockState(pos);
lock.lock(); // lock.lock();
Set<ServerPlayerEntity> playerList = getWatchPlayerList(world, blockEntity.getPos()); // Set<ServerPlayerEntity> playerList = getWatchPlayerList(world, blockEntity.getPos());
//
Set<ServerPlayerEntity> playerListAdj = null; // Set<ServerPlayerEntity> playerListAdj = null;
//
if (blockState.getBlock() instanceof ChestBlock) { // if (blockState.getBlock() instanceof ChestBlock) {
if (blockState.get(ChestBlock.CHEST_TYPE) != ChestType.SINGLE) { // if (blockState.get(ChestBlock.CHEST_TYPE) != ChestType.SINGLE) {
// 如果是一个大箱子需要特殊处理 // // 如果是一个大箱子需要特殊处理
// 上面不用 isOf 是为了考虑到陷阱箱的情况,陷阱箱继承自箱子 // // 上面不用 isOf 是为了考虑到陷阱箱的情况,陷阱箱继承自箱子
BlockPos posAdj = pos.offset(ChestBlock.getFacing(blockState)); // BlockPos posAdj = pos.offset(ChestBlock.getFacing(blockState));
playerListAdj = getWatchPlayerList(world, posAdj); // playerListAdj = getWatchPlayerList(world, posAdj);
} // }
} else if (ServerMain.tisCarpetLoaded && blockState.isOf(Blocks.BARREL) && RuleHelper.getBooleanValue(getCarpetRule("largeBarrel"))) { // } else if (ServerMain.tisCarpetLoaded && blockState.isOf(Blocks.BARREL) && RuleHelper.getBooleanValue(getCarpetRule("largeBarrel"))) {
Direction directionOpposite = blockState.get(BarrelBlock.FACING).getOpposite(); // Direction directionOpposite = blockState.get(BarrelBlock.FACING).getOpposite();
BlockPos posAdj = pos.offset(directionOpposite); // BlockPos posAdj = pos.offset(directionOpposite);
BlockState blockStateAdj = world.getBlockState(posAdj); // BlockState blockStateAdj = world.getBlockState(posAdj);
if (blockStateAdj.isOf(Blocks.BARREL) && blockStateAdj.get(BarrelBlock.FACING) == directionOpposite) { // if (blockStateAdj.isOf(Blocks.BARREL) && blockStateAdj.get(BarrelBlock.FACING) == directionOpposite) {
playerListAdj = getWatchPlayerList(world, posAdj); // playerListAdj = getWatchPlayerList(world, posAdj);
} // }
} // }
if (playerListAdj != null) { // if (playerListAdj != null) {
if (playerList == null) { // if (playerList == null) {
playerList = playerListAdj; // playerList = playerListAdj;
} else { // } else {
playerList.addAll(playerListAdj); // playerList.addAll(playerListAdj);
} // }
} // }
//
if (playerList != null) { // if (playerList != null) {
for (ServerPlayerEntity player : playerList) { // for (ServerPlayerEntity player : playerList) {
updateBlockEntity(player, blockEntity); // updateBlockEntity(player, blockEntity);
ret = true; // ret = true;
} // }
} // }
lock.unlock(); // lock.unlock();
} // }
return ret; // return ret;
} // }
//
private static void clearPlayerWatchEntity(ServerPlayerEntity player) { // private static void clearPlayerWatchEntity(ServerPlayerEntity player) {
lock.lock(); // lock.lock();
Pair<Identifier, Entity> pair = playerWatchEntity.get(player); // Pair<Identifier, Entity> pair = playerWatchEntity.get(player);
if (pair != null) { // if (pair != null) {
Set<ServerPlayerEntity> playerSet = entityWatchPlayerSet.get(pair); // Set<ServerPlayerEntity> playerSet = entityWatchPlayerSet.get(pair);
playerSet.remove(player); // playerSet.remove(player);
if (playerSet.isEmpty()) { // if (playerSet.isEmpty()) {
entityWatchPlayerSet.remove(pair); // entityWatchPlayerSet.remove(pair);
} // }
playerWatchEntity.remove(player); // playerWatchEntity.remove(player);
} // }
lock.unlock(); // lock.unlock();
} // }
//
private static void clearPlayerWatchBlock(ServerPlayerEntity player) { // private static void clearPlayerWatchBlock(ServerPlayerEntity player) {
lock.lock(); // lock.lock();
Pair<Identifier, BlockPos> pair = playerWatchBlockPos.get(player); // Pair<Identifier, BlockPos> pair = playerWatchBlockPos.get(player);
if (pair != null) { // if (pair != null) {
Set<ServerPlayerEntity> playerSet = blockPosWatchPlayerSet.get(pair); // Set<ServerPlayerEntity> playerSet = blockPosWatchPlayerSet.get(pair);
playerSet.remove(player); // playerSet.remove(player);
if (playerSet.isEmpty()) { // if (playerSet.isEmpty()) {
blockPosWatchPlayerSet.remove(pair); // blockPosWatchPlayerSet.remove(pair);
} // }
playerWatchBlockPos.remove(player); // playerWatchBlockPos.remove(player);
} // }
lock.unlock(); // lock.unlock();
} // }
//
// 停用 PcaSyncProtocol // // 停用 PcaSyncProtocol
public static void disablePcaSyncProtocolGlobal() { // public static void disablePcaSyncProtocolGlobal() {
lock.lock(); // lock.lock();
playerWatchBlockPos.clear(); // playerWatchBlockPos.clear();
playerWatchEntity.clear(); // playerWatchEntity.clear();
blockPosWatchPlayerSet.clear(); // blockPosWatchPlayerSet.clear();
entityWatchPlayerSet.clear(); // entityWatchPlayerSet.clear();
lock.unlock(); // lock.unlock();
if (ServerMain.server != null) { // if (ServerMain.server != null) {
for (ServerPlayerEntity player : ServerMain.server.getPlayerManager().getPlayerList()) { // for (ServerPlayerEntity player : ServerMain.server.getPlayerManager().getPlayerList()) {
disablePcaSyncProtocol(player); // disablePcaSyncProtocol(player);
} // }
} // }
} // }
//
// 启用 PcaSyncProtocol // // 启用 PcaSyncProtocol
public static void enablePcaSyncProtocolGlobal() { // public static void enablePcaSyncProtocolGlobal() {
if (ServerMain.server == null) { // if (ServerMain.server == null) {
return; // return;
} // }
for (ServerPlayerEntity player : ServerMain.server.getPlayerManager().getPlayerList()) { // for (ServerPlayerEntity player : ServerMain.server.getPlayerManager().getPlayerList()) {
enablePcaSyncProtocol(player); // enablePcaSyncProtocol(player);
} // }
} // }
//
//
// 删除玩家数据 // // 删除玩家数据
public static void clearPlayerWatchData(ServerPlayerEntity player) { // public static void clearPlayerWatchData(ServerPlayerEntity player) {
PcaSyncProtocol.clearPlayerWatchBlock(player); // PcaSyncProtocol.clearPlayerWatchBlock(player);
PcaSyncProtocol.clearPlayerWatchEntity(player); // PcaSyncProtocol.clearPlayerWatchEntity(player);
} // }
//
private static CarpetRule<?> getCarpetRule(String rule){ // private static CarpetRule<?> getCarpetRule(String rule){
return CarpetServer.settingsManager.getCarpetRule(rule); // return CarpetServer.settingsManager.getCarpetRule(rule);
} // }
//
@Contract(value = "_ -> new", pure = true) // @Contract(value = "_ -> new", pure = true)
private static @NotNull Identifier createId(String name) { // private static @NotNull Identifier createId(String name) {
return new Identifier("pca", name); // return new Identifier("pca", name);
} // }
} }
@@ -2,6 +2,9 @@ package com.github.zly2006.carpetslsaddition.util;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings; import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import net.minecraft.block.ShulkerBoxBlock; import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.component.ComponentType;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.NbtComponent;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
@@ -13,11 +16,10 @@ public class ShulkerBoxItemUtil {
public static boolean isEmptyShulkerBoxItem(ItemStack itemStack) { public static boolean isEmptyShulkerBoxItem(ItemStack itemStack) {
if (itemStack.getItem() instanceof BlockItem && if (itemStack.getItem() instanceof BlockItem &&
((BlockItem) itemStack.getItem()).getBlock() instanceof ShulkerBoxBlock) { ((BlockItem) itemStack.getItem()).getBlock() instanceof ShulkerBoxBlock) {
NbtCompound nbt = itemStack.getNbt(); NbtComponent tag = itemStack.getComponents().get(DataComponentTypes.BLOCK_ENTITY_DATA);
if (nbt != null && nbt.contains("BlockEntityTag", 10)) { if (tag != null) {
NbtCompound tag = nbt.getCompound("BlockEntityTag"); if (tag.contains("Items")) {
if (tag.contains("Items", 9)) { NbtList tagList = tag.getNbt().getList("Items", 10);
NbtList tagList = tag.getList("Items", 10);
return tagList.size() <= 0; return tagList.size() <= 0;
} }
} }
@@ -38,4 +40,4 @@ public class ShulkerBoxItemUtil {
public static boolean isStackable(ItemStack itemStack) { public static boolean isStackable(ItemStack itemStack) {
return getMaxCount(itemStack) > 1 && (!itemStack.isDamageable() || !itemStack.isDamaged()); return getMaxCount(itemStack) > 1 && (!itemStack.isDamageable() || !itemStack.isDamaged());
} }
} }
@@ -22,26 +22,9 @@
"entity.MixinPlayerEntity", "entity.MixinPlayerEntity",
"entity.MixinServerPlayerEntity", "entity.MixinServerPlayerEntity",
"entity.MixinVillagerEntity", "entity.MixinVillagerEntity",
"item.MixinDyeItem",
"item.MixinPotionItem",
"player.AccessorPlayerAbilities", "player.AccessorPlayerAbilities",
"player.MixinPlayerInventory",
"protocol.pcaSyncProtocol.block.MixinAbstractFurnaceBlockEntity",
"protocol.pcaSyncProtocol.block.MixinBarrelBlockEntity",
"protocol.pcaSyncProtocol.block.MixinBeehiveBlockEntity",
"protocol.pcaSyncProtocol.block.MixinBrewingStandBlockEntity",
"protocol.pcaSyncProtocol.block.MixinChestBlockEntity",
"protocol.pcaSyncProtocol.block.MixinComparatorBlockEntity",
"protocol.pcaSyncProtocol.block.MixinDispenserBlockEntity",
"protocol.pcaSyncProtocol.block.MixinHopperBlockEntity",
"protocol.pcaSyncProtocol.block.MixinShulkerBoxBlockEntity",
"protocol.pcaSyncProtocol.entity.MixinHorseBaseEntity",
"protocol.pcaSyncProtocol.entity.MixinMerchantEntity",
"protocol.pcaSyncProtocol.entity.MixinStorageMinecartEntity",
"screen.MixinScreenHandler",
"screen.MixinSlot", "screen.MixinSlot",
"server.MixinMinecraftServer", "server.MixinMinecraftServer",
"server.MixinPlayerManager",
"world.MixinSleepManager", "world.MixinSleepManager",
"world.MixinSpawnHelper", "world.MixinSpawnHelper",
"world.MixinWorld" "world.MixinWorld"