Files
Calen 616089ba8e CatServer 1.20.1 (#928)
* Some updates

修改一些小问题

FoxServerLauncher#main
        launchArgs = Arrays.copyOf(launchArgs, launchArgs.length + args.length);
        System.arraycopy(args, 0, launchArgs, launchArgs.length, args.length);
如果有自带启动参数 会ArrayIndexOutOfBoundsException

ShearsDispenseItemBehavior#tryShearLivingEntity
在循环里ShearsDispenseItemBehavior.catserver$shearBukkitBlock.getAndSet(null),下一轮循环读到的会是null
在if里ShearsDispenseItemBehavior.catserver$shearBukkitBlock.getAndSet(null),如果没有进入if则catserver$shearBukkitBlock无法被重置
同时改用CatServerCaptures

ServerLevel#tickPassenger
bukkit加的p_8664_.postTick()处理生物通过地狱门时的传送,应该和p_8664_.rideTick()同时受forge加入的if(p_8664_.canUpdate())控制

ServerGamePacketListenerImpl#onDisconnect
cat注释掉的
// this.server.getPlayerList().remove(this.player); // CatServer - fix dupe player logout
但bukkit并没有留这一行
少了bukkit留下的this.player.disconnect();
看起来像是留错了诶(?)

ServerHandshakePacketListenerImpl#handleIntention
spigot的bug
这些翻译key被spigot换成String后应该是TextComponent(ChatMessage)
spigot1.20.1已修复

Entity#changeDimension
return前pop profiler

调用ServerLevel.makeObsidianPlatform时增加bukkit的this参数
                  ServerLevel.makeObsidianPlatform(serverLevel, this);

ItemEntity#tick
似乎把bukkit的patch放错位置了

bukkit:
             if (!this.level.isClientSide && this.age >= 6000) {
+                // CraftBukkit start - fire ItemDespawnEvent
+                if (org.bukkit.craftbukkit.event.CraftEventFactory.callItemDespawnEvent(this).isCancelled()) {
+                    this.age = 0;
+                    return;
+                }
+                // CraftBukkit end
                 this.discard();
             }

LivingEntity#checkFallDamage
forge的.setPos(p_20993_)

LivingEntity#private void addEatEffect(ItemStack p_21064_, Level p_21065_, LivingEntity p_21066_)
重置cause为默认值UNKNOWN

LivingEntity#damageEntity0
改为bukkit的写法 用tag

LivingEntity#randomTeleport
flag和flag1写反辣

forge
      boolean flag = false;
      BlockPos blockpos = BlockPos.containing(p_20985_, p_20986_, p_20987_);
      Level level = this.level();
      if (level.hasChunkAt(blockpos)) {
         boolean flag1 = false;

         if (flag1) {
            this.teleportTo(p_20985_, d3, p_20987_);
bukkit
        boolean flag1 = false;
        BlockPosition blockposition = BlockPosition.containing(d0, d1, d2);
        World world = this.level();
        if (world.hasChunkAt(blockposition)) {
            boolean flag2 = false;

             if (flag2) {
-                this.teleportTo(d0, d6, d2);

+                this.setPos(d3, d4, d5);
+                if (flag1) {
+                    if (!(this instanceof EntityPlayer)) {

cat
      boolean flag = false;
      BlockPos blockpos = new BlockPos(p_20985_, p_20986_, p_20987_);
      Level level = this.level;
      if (level.hasChunkAt(blockpos)) {
         boolean flag1 = false;

         if (flag) {
            var cause = CatServerCaptures.getCatServerCaptures().getCaptureTeleportCause();
            // CraftBukkit start - Teleport event
            // this.teleportTo(p_20985_, d3, p_20987_);

            this.setPos(d0, d1, d2);
            if (flag1) {
               if (!(this instanceof ServerPlayer)) {

LivingEntity#heal
      this.resetRegainReason();
保证不进if也能重置
NaturalSpawner#spawnCategoryForPosition
p_47040_.addFreshEntityWithPassengers(mob);用capture传入的reason在ServerLevelAccessor#addFreshEntityWithPassengers未被接收
同时修改ServerLevelAccessor

Mob#convertTo
确保catserver$spawnReason重置
同时改用CatServerCaptures

ZombieVillager#tick
bukkit的
         super.tick();
+        this.lastTick = MinecraftServer.currentTick; // CraftBukkit
     }

net.minecraft.world.entity.player.Player#public void causeFoodExhaustion(float p_36400_)
this.catserver$causeFoodReason.getAndSet)在if里 如果没有进if的话catserver$causeFoodReason无法重置
同时改用CatServerCaptures

ThrownPotion#applySplash
bukkit的entity1

Raid#tick
似乎有一个bukkit的callRaidStopEvent的位置串了

AbstractMinecart#setDragAir
vanilla
this.setDeltaMovement(this.getDeltaMovement().scale(0.95D));
forge
this.setDeltaMovement(this.getDeltaMovement().scale(getDragAir()));
bukkit+cat
-            this.setDeltaMovement(this.getDeltaMovement().scale(0.95D));
+            // CraftBukkit start - replace magic numbers with our variables
+            this.setDeltaMovement(new Vec3D(this.getDeltaMovement().x * this.flyingX, this.getDeltaMovement().y * this.flyingY, this.getDeltaMovement().z * this.flyingZ));
+            // CraftBukkit end

这样的话 似乎forge的dragAir会失效
forge的xyz用同一个scale bukkit用3个 没法在保证各自正常功能的情况下用同一组scale来统一两边 所以用同相乘的关系
         this.setDeltaMovement(new Vec3(this.getDeltaMovement().x * this.flyingX, this.getDeltaMovement().y * this.flyingY, this.getDeltaMovement().z * this.flyingZ).scale(getDragAir()));

ChestMenu#getBukkitView
bukkit
      if (this.container instanceof PlayerInventory) { -> net.minecraft.world.entity.player.PlayerInventory(official:net.minecraft.world.entity.player.Inventory)

cat
      if (this.container instanceof PlayerInventory) { -> org.bukkit.inventory.PlayerInventory

EnchantmentMenu#slotsChanged
j用forge的float类型
改用独立的数组循环索引k

ArmorItem#dispenseArmor
bukkit
    public static boolean dispenseArmor(ISourceBlock isourceblock, ItemStack itemstack) {

            ItemStack itemstack1 = itemstack.split(1);

            if (event.isCancelled()) {
                itemstack.grow(1);
                return false;
            }

            if (!event.getItem().equals(craftItem)) {
                itemstack.grow(1);

cat
         ItemStack itemstack = p_40400_.split(1);

         if (event.isCancelled()) {
            itemstack.grow(1);
            return false;
         }
         if (!event.getItem().equals(craftItem)) {
            itemstack.grow(1);
            // Chain to handler for new item

应该是p_40400_

BaseSpawner/MobSpawnerAbstract#serverTick+CraftEventFactory#callSpawnerSpawnEvent
补充spigot patch(这个在1.20.1转为craftbukkit patch)
spigot1182

                        // Spigot Start
                        if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) {
                            Entity vehicle = entity.getVehicle();
                            if (vehicle != null) {
                                vehicle.discard();
                            }
                            for (Entity passenger : entity.getIndirectPassengers()) {
                                passenger.discard();
                            }
                            continue;
                        }
                        // Spigot End

CraftEventFactory
    public static SpawnerSpawnEvent callSpawnerSpawnEvent(Entity spawnee, BlockPos pos) {
        org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity entity = spawnee.getBukkitEntity();
        BlockState state = entity.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()).getState();
        if (!(state instanceof org.bukkit.block.CreatureSpawner)) {
            state = null;
        }

        SpawnerSpawnEvent event = new SpawnerSpawnEvent(entity, (org.bukkit.block.CreatureSpawner) state);
        entity.getServer().getPluginManager().callEvent(event);
        return event;
    }

BigDripleafBlock#private static void setTilt(BlockState p_152278_, Level p_152279_, BlockPos p_152280_, Tilt p_152281_)
循环调用了 似乎应该调用下面那个
顺便加个强转

CommandBlock#neighborChanged
flag和flag1

bukkit
                boolean flag1 = world.hasNeighborSignal(blockposition);
                boolean flag2 = tileentitycommand.isPowered();
                // CraftBukkit start
                org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
                int old = flag2 ? 15 : 0;
                int current = flag1 ? 15 : 0;

                BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bukkitBlock, old, current);
                world.getCraftServer().getPluginManager().callEvent(eventRedstone);
                flag1 = eventRedstone.getNewCurrent() > 0;
                // CraftBukkit end

cat
            boolean flag = p_51839_.hasNeighborSignal(p_51840_);
            boolean flag1 = commandblockentity.isPowered();
            // CraftBukkit start
            org.bukkit.block.Block bukkitBlock = p_51839_.getWorld().getBlockAt(p_51840_.getX(), p_51840_.getY(), p_51840_.getZ());
            int old = flag1 ? 15 : 0;
            int current = flag1 ? 15 : 0;
            BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bukkitBlock, old, current);
            p_51839_.getCraftServer().getPluginManager().callEvent(eventRedstone);
            flag1 = eventRedstone.getNewCurrent() > 0;
            // CraftBukkit end

AbstractFurnaceBlockEntity#getTotalCookTime
bukkit的patch

BeaconBlockEntity
#applyEffect
#applyEffects
, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);

BeehiveBlockEntity
#releaseOccupant
#releaseAllOccupants
确保重置catserver$isForceReleaseAllOccupants catserver$isForceReleaseOccupant

BrewingStandBlockEntity#doBrew
确保catserver$captureBrewBlockEntity重置
同时改用CatServerCaptures

实现// CatServer TODO: missing BrewEvent result

HopperBlockEntity#ejectItems
bukkit
+                        ItemStack itemstack1 = addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
cat
                  ItemStack itemstack1 = addItem(p_155566_, p_155566_, CraftItemStack.asNMSCopy(event.getItem()), direction);

iinventory是method传入的漏斗p_155566_
iinventory1是getAttachedContainer返回的目标tileentity

HopperBlockEntity#private static boolean tryTakeInItemFromSlot(Hopper p_59355_, Container p_59356_, int p_59357_, Direction p_59358_)
考虑mod里implements Hopper的其他BlockEntity/Entity

FireBlock#updateShape
bukkit
+            if (!(generatoraccess instanceof World)) { -> net.minecraft.world.level.Level
cat
         if (!(p_53461_ instanceof World)) { -> org.bukkit.World

MushroomBlock#growMushroom
bukkit1201+1182
+        BlockSapling.treeType = (this == Blocks.BROWN_MUSHROOM) ? TreeType.BROWN_MUSHROOM : TreeType.BROWN_MUSHROOM; // CraftBukkit
cat1182
      SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? TreeType.BROWN_MUSHROOM : TreeType.BROWN_MUSHROOM; // CraftBukkit
bukkit12110
            BlockSapling.treeType = (this == Blocks.BROWN_MUSHROOM) ? TreeType.BROWN_MUSHROOM : TreeType.RED_MUSHROOM; // CraftBukkit

bukkit的bug

PistonBaseBlock#moveBlocks
BlockPos和Direction

bukkit
    private boolean moveBlocks(World world, BlockPosition blockposition, EnumDirection enumdirection, boolean flag) {
        BlockPosition blockposition1 = blockposition.relative(enumdirection);

            EnumDirection enumdirection1 = flag ? enumdirection : enumdirection.getOpposite();

+            final org.bukkit.block.Block bblock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());

+                event = new BlockPistonExtendEvent(bblock, blocks, CraftBlock.notchToBlockFace(enumdirection1));
+            } else {
+                event = new BlockPistonRetractEvent(bblock, blocks, CraftBlock.notchToBlockFace(enumdirection1));

cat
   private boolean moveBlocks(Level p_60182_, BlockPos p_60183_, Direction p_60184_, boolean p_60185_) {
      BlockPos blockpos = p_60183_.relative(p_60184_);

         Direction direction = p_60185_ ? p_60184_ : p_60184_.getOpposite();

         final org.bukkit.block.Block bblock = p_60182_.getWorld().getBlockAt(blockpos.getX(), blockpos.getY(), blockpos.getZ());

            event = new BlockPistonExtendEvent(bblock, blocks, CraftBlock.notchToBlockFace(p_60184_));
         } else {
            event = new BlockPistonRetractEvent(bblock, blocks, CraftBlock.notchToBlockFace(p_60184_));

RedStoneOreBlock#private static void interact(BlockState p_55493_, Level p_55494_, BlockPos p_55495_)
setBlock保留if (!p_55493_.getValue(LIT))判断

* [1.18.2] Update capture value name

* CatServer 1.20.1

* Simple cleanups
2026-02-13 23:30:28 +08:00
..
2026-02-13 23:30:28 +08:00
2023-03-11 14:12:09 +08:00