= 创作分享 =
技术讨论
【崩溃解决新思路】运用AI来解决Blur与Somnia的崩溃问题 ...
滑机

【崩溃解决新思路】运用AI来解决Blur与Somnia的崩溃问题!

滑机 于 2025-2-1 18:20 ( 5天前 ) [讨论] [复制链接] [显示全部楼层] [打印]
本贴模组名片
梦醒时分 (Somnia Awoken)
[h1=梦醒时分]梦醒时分是一个模拟玩家睡觉时经过时间的模组。它是梦短人生长/真实睡眠,一个最早于 2011 年发布的模组的移植 / 重写模组。[h2=起步]所有信息都可以在梦醒时分的 Wiki 参阅。[h2=它如何工作]把丢掉的睡觉时间找回来,当你睡觉时,这个世界会加速运行,而非直接跳..
Blur与Somnia Awoken同时安装后。当玩家点击上床,进入睡觉状态后,屏幕上可出现正常的“经验进度条”界面。
但是,当进度条满后,也就是睡觉结束,该起床的时候,会发生一个问题。
对于Cleanroom+Fugue端(1.12.2),游戏会发生崩溃。censoredASM不会弹出提醒。就直接崩溃。
而对于普通Forge端,会发生“连接中断”问题。如下图:



换用[url=]Somnia Refreshed也不行。[/url]
问了DeepSeek一整天后,利用DeepSeek做了一个修复版:
UID-503058116/Refreshed-Somnia-Refreshed: Yet another solution for the crash caused by Somnia and Blur
Refreshed Somnia Refreshed(XD
修改的代码全都是它写的。


DeepSeek用一种 极 其 迂 回 的办法解决了。关于详情,可以自己拿崩溃报告去问DeepSeek(记得开深度思考R1哦)。

现在把修复版挂在这里。
跟AI聊了一下午。但是我没有截图这个过程...
后面再补充。
Snipaste_2025-02-01_17-58-29.png
Snipaste_2025-02-01_17-58-56.png
Snipaste_2025-02-01_17-48-53.png
Snipaste_2025-02-01_17-59-00.png
Snipaste_2025-02-01_18-05-57.png
Snipaste_2025-02-01_18-05-57.png
Snipaste_2025-02-01_18-07-29.png
Snipaste_2025-02-01_18-09-06.png
Snipaste_2025-02-01_18-09-11.png
Snipaste_2025-02-01_18-16-23.png
发表于 6 天前 | 显示全部楼层 |阅读模式

回复 | 举报

该帖共收到 3 条回复!
滑机
[url=][/url]三个关键的修改:1.ClientProxy.java:
-------------------------------------------------
package com.kingrunes.somnia.setup;

import com.kingrunes.somnia.client.ClientTickHandler;
import com.kingrunes.somnia.client.gui.GuiSelectWakeTime;
import com.kingrunes.somnia.common.SomniaConfig;
import com.kingrunes.somnia.common.util.SomniaUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import java.io.DataInputStream;
import java.io.IOException;

@SideOnly(Side.CLIENT)
public class ClientProxy implements IProxy {
    public static double playerFatigue = -1;
    public static final ClientTickHandler clientTickHandler = new ClientTickHandler();
    // 统一使用volatile保证可见性,并修正类型为long
    public static volatile long clientAutoWakeTime = -1;

    @Override
    public void register() {
        MinecraftForge.EVENT_BUS.register(this);
        MinecraftForge.EVENT_BUS.register(clientTickHandler);
    }

    @Override
    public void handleGUIOpenPacket() {
        final Minecraft mc = Minecraft.getMinecraft();
        if (SomniaConfig.OPTIONS.enableWakeTimeSelectMenu) {
            mc.addScheduledTask(() -> mc.displayGuiScreen(new GuiSelectWakeTime(
                mc.player.inventory.getCurrentItem().getItem() == Items.CLOCK
            )));
        }
    }

    @Override
    public void handlePropUpdatePacket(DataInputStream in) throws IOException {
        byte target = in.readByte();
        EntityPlayer player = Minecraft.getMinecraft().player;

        switch (target) {
            case 0x00:
                if (player.isPlayerSleeping()) {
                    int b = in.readInt();
                    for (int a = 0; a < b; a++) {
                        clientTickHandler.readField(in);
                    }
                }
                break;
            case 0x01:
                int b = in.readInt();
                for (int a = 0; a < b; a++) {
                    byte val = in.readByte();
                    if (val == 0x00) {
                        playerFatigue = in.readDouble();
                    }
                }
                break;
            default:
                break;
        }
    }

    @Override
    public void handleWakePacket(EntityPlayerMP player) {
        // 确保在主线程执行
        Minecraft.getMinecraft().addScheduledTask(() -> {
            if (player != null) {
                player.wakeUpPlayer(true, true, true);
            }
            Minecraft.getMinecraft().displayGuiScreen(null);
        });
    }

    @Override
    public void updateWakeTime(EntityPlayer player) {
        if (clientAutoWakeTime != -1) return;

        long worldTime = player.world.getWorldTime();
        clientAutoWakeTime = SomniaUtil.calculateWakeTime(
            worldTime,
            (worldTime % 24000) > 12000 ? 0 : 12000
        );
    }
}
Snipaste_2025-02-01_18-31-53.png
发表于 6 天前 | 显示全部楼层

回复 | 举报

滑机
2.ServerTickHandler.java
————————————————————
package com.kingrunes.somnia.server;

import com.kingrunes.somnia.Somnia;
import com.kingrunes.somnia.common.PacketHandler;
import com.kingrunes.somnia.common.SomniaConfig;
import com.kingrunes.somnia.common.util.SomniaState;
import com.kingrunes.somnia.common.util.SomniaUtil;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.play.server.SPacketTimeUpdate;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;

import javax.annotation.Nullable;
import java.util.Iterator;

import static com.kingrunes.somnia.common.util.SomniaState.*;

public class ServerTickHandler
{
        public static final String TRANSLATION_FORMAT = "somnia.status.%s";
                       
        private static int activeTickHandlers = 0;
       
        public WorldServer worldServer;
        public SomniaState currentState;
       
        public long         lastSleepStart,
                                        currentSleepPeriod;                         // Incremented while mbCheck is true, reset when state is changed
        public long                checkTimer                         = 0,                 // Used to schedule GUI update packets and sleep state checks
                                        lastTpsMillis                = 0,
                                        liTps                                 = 0,                 // Counts ticks
                                        tps                                        = 0;                // Set per second to liTPS, used to work out actual multiplier to send to clients
       
        private double         multiplier                         = SomniaConfig.LOGIC.baseMultiplier;
        private double         worldTimeMultiplier = SomniaConfig.PERFORMANCE.fasterWorldTimeMultiplier;
       
        public ServerTickHandler(WorldServer worldServer)
        {
                this.worldServer = worldServer;
        }       
       
        public void tickStart()
        {
                if (++checkTimer == 10)
                {
                        checkTimer = 0;
                       
                        SomniaState prevState = currentState;
                        currentState = SomniaState.getState(this);
                       
                        if (prevState != currentState)
                        {
                                currentSleepPeriod = 0;
                                if (currentState == ACTIVE) // acceleration started
                                {
                                        lastSleepStart = worldServer.getWorldTime();
                                        activeTickHandlers++;
                                }
                                else if (prevState == ACTIVE) // acceleration stopped
                                {
                                        activeTickHandlers--;
                                       
                                        if (currentState == EXPIRED || currentState == NOT_NOW)
                                                closeGuiWithMessage(currentState.toString());
                                }
                        }
                       
                        if (currentState == ACTIVE || currentState == WAITING_PLAYERS || currentState == COOLDOWN)
                        {
                                FMLProxyPacket packet = PacketHandler.buildPropUpdatePacket(
                                        0x00,
                                        0x00, currentState == ACTIVE ? (double)tps/20d : .0d,
                                        0x01, currentState == ACTIVE ? SomniaUtil.timeStringForWorldTime(worldServer.getWorldTime()) : "f:"+currentState.toString()
                                );
                               
                                Somnia.eventChannel.sendToDimension(packet, worldServer.provider.getDimension());
                        }
                }
               
                if (currentState == ACTIVE)
                        doMultipliedTicking();
        }
       
        private void closeGuiWithMessage(@Nullable String key)
        {
                FMLProxyPacket packet = PacketHandler.buildWakePacket();

                Iterator<EntityPlayer> iter = worldServer.playerEntities.iterator();
                EntityPlayer ep;
                while (iter.hasNext())
                {
                        ep = iter.next();
                        if (ep.isPlayerSleeping())
                        {
                                Somnia.eventChannel.sendTo(packet, (EntityPlayerMP) ep);
                                if (ep.isPlayerSleeping()) // this if might stop random teleporting when players have already woken
                                {
                                        ep.wakeUpPlayer(false, true, true); // Stop clients ignoring GUI close packets (major hax)
                                }
                                if (key != null)
                                        ep.sendMessage(new TextComponentTranslation(String.format(TRANSLATION_FORMAT, key.toLowerCase())));
                        }
                }
        }
       
        private void incrementCounters()
        {
                liTps++;
                currentSleepPeriod++;
        }
       
        private double overflow = .0d;
        private double worldTimeOverflow = .0d;
        private void doMultipliedTicking()
        {
                /*
                 * We can't run 0.5 of a tick,
                 * so we floor the multiplier and store the difference as overflow to be ran on the next tick
                 */
                double target = multiplier + overflow;
                int liTarget = (int) Math.floor(target);
                overflow = target - liTarget;
               
                long delta = System.currentTimeMillis();
                for (int i=0; i<liTarget; i++)
                        doMultipliedServerTicking();
                delta = System.currentTimeMillis() - delta;

                MinecraftServer server = worldServer.getMinecraftServer();
                if (server == null) return;
                server.getPlayerList().sendPacketToAllPlayersInDimension(new SPacketTimeUpdate(worldServer.getTotalWorldTime(), worldServer.getWorldTime(), worldServer.getGameRules().getBoolean("doDaylightCycle")), worldServer.provider.getDimension());
               
                if (delta > (SomniaConfig.LOGIC.delta/activeTickHandlers))
                        multiplier -= .1d;
                else
                        multiplier += .1d;
               
                if (multiplier > SomniaConfig.LOGIC.multiplierCap)
                        multiplier = SomniaConfig.LOGIC.multiplierCap;
               
                if (multiplier < SomniaConfig.LOGIC.baseMultiplier)
                        multiplier = SomniaConfig.LOGIC.baseMultiplier;
               
                long currentTimeMillis = System.currentTimeMillis();
                if (currentTimeMillis-lastTpsMillis > 1000)
                {
                        tps = liTps;
                        liTps = 0;
                        lastTpsMillis = currentTimeMillis;
                }
        }
       
        private void doMultipliedServerTicking()
        {
                FMLCommonHandler.instance().onPreWorldTick(worldServer);
                worldServer.tick();
                worldServer.updateEntities();
                worldServer.getEntityTracker().tick();
                FMLCommonHandler.instance().onPostWorldTick(worldServer);
               
                /*
                 * Work around for making sure fatigue is updated with every tick (including Somnia ticks)
                 */
                for (Object obj : worldServer.playerEntities)
                        Somnia.forgeEventHandler.onPlayerTick(new TickEvent.PlayerTickEvent(Phase.START, (EntityPlayer) obj));
               
                if (SomniaConfig.PERFORMANCE.fasterWorldTime)
                {
                        double target = worldTimeMultiplier + worldTimeOverflow;
                        int liTarget = (int) Math.floor(target);
                        worldTimeOverflow = target - liTarget;
                       
                        worldServer.setWorldTime(worldServer.getWorldTime() + liTarget);
                }
               
                incrementCounters();
        }
}
发表于 6 天前 | 显示全部楼层

回复 | 举报

滑机
3.PacketHandler.java:
————————————
package com.kingrunes.somnia.common;

import com.kingrunes.somnia.Somnia;
import com.kingrunes.somnia.api.capability.CapabilityFatigue;
import com.kingrunes.somnia.api.capability.IFatigue;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.Unpooled;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientCustomPacketEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ServerCustomPacketEvent;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;

import javax.annotation.Nullable;
import java.io.DataInputStream;
import java.io.IOException;

public class PacketHandler
{
        /*
         * Handling
         */
        @SubscribeEvent
        public void onServerPacket(ServerCustomPacketEvent event)
        {
                if (event.getPacket().channel().equals(Somnia.MOD_ID))
                        onPacket(event.getPacket(), ((NetHandlerPlayServer)event.getHandler()).player);
        }
       
        @SubscribeEvent
        public void onClientPacket(ClientCustomPacketEvent event)
        {
                if (event.getPacket().channel().equals(Somnia.MOD_ID))
                        onPacket(event.getPacket(), null);
        }
       
        public void onPacket(FMLProxyPacket packet, EntityPlayerMP player)
        {
                DataInputStream in = new DataInputStream(new ByteBufInputStream(packet.payload()));
                try
                {
                        byte id = in.readByte();
                       
                        switch (id)
                        {
                        case 0x00:
                                handleGUIOpenPacket();
                                break;
                        case 0x01:
                                handleWakePacket(player, in);
                                break;
                        case 0x02:
                                handlePropUpdatePacket(in, player);
                                break;
                        case 0x03:
                                handleRightClickBlockPacket(player, in);
                                break;
                        case 0x04:
                                handleRideEntityPacket(player, in);
                                break;
                        }
                }
                catch (IOException e)
                {
                        Somnia.logger.error("Packet handling error", e);
                }
        }

        // CLIENT
        private void handleGUIOpenPacket() {
                Minecraft.getMinecraft().addScheduledTask(() ->
                        Somnia.proxy.handleGUIOpenPacket()
                );
        }
       
        private void handlePropUpdatePacket(DataInputStream in, @Nullable EntityPlayerMP player) throws IOException
        {
                if (player == null || player.world.isRemote) {
                        Minecraft.getMinecraft().addScheduledTask(() -> {
                                try {
                                        Somnia.proxy.handlePropUpdatePacket(in);
                                } catch (IOException e) {
                                        Somnia.logger.error("Prop update error", e);
                                }
                        });
                        return;
                }

                byte target = in.readByte();
                IFatigue props = player.getCapability(CapabilityFatigue.FATIGUE_CAPABILITY, null);

                if (target == 0x01 && props != null) {
                        int b = in.readInt();
                        for (int a=0; a<b; a++)
                        {
                                int val = in.readByte();
                                if (val == 0x00) {
                                        props.setFatigue(in.readDouble());
                                }
                                else if (val == 0x01) {
                                        props.setResetSpawn(in.readBoolean());
                                }
                                else if (val == 0x02) {
                                        props.setSleepNormally(in.readBoolean());
                                }
                        }
                }
        }
       
        private void handleWakePacket(EntityPlayerMP player, DataInputStream in)
        {
                Minecraft.getMinecraft().addScheduledTask(() ->
                        Somnia.proxy.handleWakePacket(player)
                );
        }

        private void handleRightClickBlockPacket(EntityPlayerMP player, DataInputStream in) throws IOException {
                BlockPos pos = new BlockPos(in.readInt(), in.readInt(), in.readInt());
                EnumFacing side = EnumFacing.values()[in.readByte()];
                float hitX = in.readFloat();
                float hitY = in.readFloat();
                float hitZ = in.readFloat();
                player.world.getBlockState(pos).getBlock().onBlockActivated(
                                player.world, pos, player.world.getBlockState(pos), player, EnumHand.MAIN_HAND,
                                side, hitX, hitY, hitZ
                );
        }

        private void handleRideEntityPacket(EntityPlayerMP player, DataInputStream in) throws IOException {
                int entityId = in.readInt();
                Entity entity = player.world.getEntityByID(entityId);
                if (entity != null) {
                        player.startRiding(entity);
                }
        }

        /*
         * Building
         */
        private static PacketBuffer unpooled() {
                return new PacketBuffer(Unpooled.buffer());
        }

        public static FMLProxyPacket buildGUIOpenPacket() {
                PacketBuffer buffer = unpooled();
                buffer.writeByte(0x00);
                return new FMLProxyPacket(buffer, Somnia.MOD_ID);
        }

        public static FMLProxyPacket buildWakePacket() {
                PacketBuffer buffer = unpooled();
                buffer.writeByte(0x01);
                return new FMLProxyPacket(buffer, Somnia.MOD_ID);
        }

        public static FMLProxyPacket buildPropUpdatePacket(int target, int prop, boolean value) {
                PacketBuffer buffer = unpooled();
                buffer.writeByte(0x02);
                buffer.writeByte(target);
                buffer.writeInt(1); // Number of properties
                buffer.writeByte(prop);
                buffer.writeBoolean(value);
                return new FMLProxyPacket(buffer, Somnia.MOD_ID);
        }

        public static FMLProxyPacket buildPropUpdatePacket(int target, int prop, double value) {
                PacketBuffer buffer = unpooled();
                buffer.writeByte(0x02);
                buffer.writeByte(target);
                buffer.writeInt(1);
                buffer.writeByte(prop);
                buffer.writeDouble(value);
                return new FMLProxyPacket(buffer, Somnia.MOD_ID);
        }

        public static FMLProxyPacket buildPropUpdatePacket(int target, int prop, double value, int prop2, String value2) {
                PacketBuffer buffer = unpooled();
                buffer.writeByte(0x02);
                buffer.writeByte(target);
                buffer.writeInt(2); // Number of properties
                buffer.writeByte(prop);
                buffer.writeDouble(value);
                buffer.writeByte(prop2);
                buffer.writeString(value2);
                return new FMLProxyPacket(buffer, Somnia.MOD_ID);
        }

        public static FMLProxyPacket buildRightClickBlockPacket(BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ) {
                PacketBuffer buffer = unpooled();
                buffer.writeByte(0x03);
                buffer.writeInt(pos.getX());
                buffer.writeInt(pos.getY());
                buffer.writeInt(pos.getZ());
                buffer.writeByte(side.ordinal());
                buffer.writeFloat(hitX);
                buffer.writeFloat(hitY);
                buffer.writeFloat(hitZ);
                return new FMLProxyPacket(buffer, Somnia.MOD_ID);
        }

        public static FMLProxyPacket buildRideEntityPacket(Entity entity) {
                PacketBuffer buffer = unpooled();
                buffer.writeByte(0x04);
                buffer.writeInt(entity.getEntityId());
                return new FMLProxyPacket(buffer, Somnia.MOD_ID);
        }
}
发表于 6 天前 | 显示全部楼层

回复 | 举报

百科目前不允许匿名发帖哦~ 请先 [ 登陆 ][ 注册 ] 吧~

本版积分规则

发新帖
  • 回复
  • 点评
  • 评分

[ MC百科(mcmod.cn) 除另有声明,所有开放公共编辑的内容均使用 BY-NC-SA 3.0 协议 ]

Minecraft百科CC协议
快速回复 返回顶部 返回列表