sp614x / optifine

1.79k stars 418 forks source link

Issues with Chunk Pregenerator #2116

Closed Speiger closed 5 years ago

Speiger commented 5 years ago

Optifine is sadly incompatible to Chunk Pregenerators newest feature the "Seed/World Previewer". The moment you try to use it it will instantly crash.

The reason why that is happening is that optifine changes "How a Integrated Server is constructed". Sadly there is no way to me to find out how optifine changes the constructor of a server so i can not fix it.

Is there any way how to make that feature compatible? Mod: https://minecraft.curseforge.com/projects/chunkpregenerator Quick Preview of the feature that is incompatible with Optifine: https://youtu.be/R4QOuroYYZI

sp614x commented 5 years ago

When running with Forge, OptiFine constructs the integrated server exactly like Forge.

Speiger commented 5 years ago

Yes and no. Yes you use the Minecraft.launchIntegratedServer call, but you change the constructure of the IntegratedServer. To make the preview feature i have to run a server but i dont want the player to login into the server nor that the spawn chunks to generate. So i have to make a custom server class that extends IntegratedServer. And when optifine is installed i get a crash because it can not find the Vanilla IntegratedServer constructor. So yeah.

Speiger commented 5 years ago

What i am trying to say is optifine changes this constructor to something else:

    public IntegratedServer(Minecraft clientIn, String folderNameIn, String worldNameIn, WorldSettings worldSettingsIn, YggdrasilAuthenticationService authServiceIn, MinecraftSessionService sessionServiceIn, GameProfileRepository profileRepoIn, PlayerProfileCache profileCacheIn)

And this makes the Preview Feature 100% incompatible to Optifine because i need this exact vanilla constructor.

sp614x commented 5 years ago

OptiFine doesn't change the IntegratedServer constructor, it only adds the Forge hooks. For example in 1.12.2:

public class IntegratedServer extends MinecraftServer
{
    private static final Logger LOGGER = LogManager.getLogger();

    /** The Minecraft instance. */
    private final Minecraft mc;
    private final WorldSettings worldSettings;
    private boolean isGamePaused;
    private boolean isPublic;
    private ThreadLanServerPing lanServerPing;

    public IntegratedServer(Minecraft clientIn, String folderNameIn, String worldNameIn, WorldSettings worldSettingsIn, YggdrasilAuthenticationService authServiceIn, MinecraftSessionService sessionServiceIn, GameProfileRepository profileRepoIn, PlayerProfileCache profileCacheIn)
    {
        super(new File(clientIn.mcDataDir, "saves"), clientIn.getProxy(), clientIn.getDataFixer(), authServiceIn, sessionServiceIn, profileRepoIn, profileCacheIn);
        this.setServerOwner(clientIn.getSession().getUsername());
        this.setFolderName(folderNameIn);
        this.setWorldName(worldNameIn);
        this.setDemo(clientIn.isDemo());
        this.canCreateBonusChest(worldSettingsIn.isBonusChestEnabled());
        this.setBuildLimit(256);
        this.setPlayerList(new IntegratedPlayerList(this));
        this.mc = clientIn;
        this.worldSettings = this.isDemo() ? WorldServerDemo.DEMO_WORLD_SETTINGS : worldSettingsIn;
        // CHANGE Custom loading screen
        ISaveHandler isavehandler = this.getActiveAnvilConverter().getSaveLoader(folderNameIn, false);
        WorldInfo worldinfo = isavehandler.loadWorldInfo();
        NBTTagCompound nbt = worldinfo.getPlayerNBTTagCompound();        
        if(nbt != null && nbt.hasKey("Dimension"))
        {
            int dim = nbt.getInteger("Dimension");
            PacketThreadUtil.lastDimensionId = dim;
            mc.loadingScreen.setLoadingProgress(-1);
        }
        //
    }

Only the lines after // CHANGE ... have been added.

Speiger commented 5 years ago

This is the crash i am getting when installing optifine with chunkpregen and opening the preview gui.

java.lang.NullPointerException: Starting integrated server
    at net.minecraft.server.integrated.IntegratedServer.<init>(IntegratedServer.java:67)
    at pregenerator.impl.client.preview.CustomServer.<init>(CustomServer.java:21)
    at pregenerator.impl.client.preview.PreviewGui.createServer(PreviewGui.java:902)
    at pregenerator.impl.client.preview.PreviewGui.onGuiTick(PreviewGui.java:188)
    at pregenerator.impl.client.preview.PreviewGui.func_73863_a(PreviewGui.java:452)
    at net.minecraftforge.client.ForgeHooksClient.drawScreen(ForgeHooksClient.java:366)
    at sun.reflect.GeneratedMethodAccessor17.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at net.optifine.reflect.Reflector.callVoid(Reflector.java:654)
    at net.minecraft.client.renderer.EntityRenderer.func_181560_a(EntityRenderer.java:1456)
    at net.minecraft.client.Minecraft.func_71411_J(Minecraft.java:1117)
    at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:397)
    at net.minecraft.client.main.Main.main(SourceFile:123)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
    at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.multimc.onesix.OneSixLauncher.launchWithMainClass(OneSixLauncher.java:196)
    at org.multimc.onesix.OneSixLauncher.launch(OneSixLauncher.java:231)
    at org.multimc.EntryPoint.listen(EntryPoint.java:143)
    at org.multimc.EntryPoint.main(EntryPoint.java:34)

And this is how the custom server looks like:

public class CustomServer extends IntegratedServer
{
    boolean forcedShutdown = false;

    public CustomServer(Minecraft clientIn, String folderNameIn, String worldNameIn, WorldSettings worldSettingsIn, YggdrasilAuthenticationService authServiceIn, MinecraftSessionService sessionServiceIn, GameProfileRepository profileRepoIn, PlayerProfileCache profileCacheIn)
    {
        super(clientIn, folderNameIn, worldNameIn, worldSettingsIn, authServiceIn, sessionServiceIn, profileRepoIn, profileCacheIn);
    }

    @Override
    public void initialWorldChunkLoad()
    {
    }

    @Override
    public void initiateShutdown()
    {
        if(serverIsInRunLoop())
        {
            super.initiateShutdown();
        }
        else
        {
            forcedShutdown = true;
        }
    }
    @Override
    public boolean isServerStopped()
    {
        return super.isServerStopped() || forcedShutdown;
    }
}

If you want i can give you a dev jar where the "Optifine installed lock" is disabled so you can have it crash within your dev area to see what line it is.

sp614x commented 5 years ago

It crashes because the worldinfo is null.

    public IntegratedServer(Minecraft clientIn, String folderNameIn, String worldNameIn, WorldSettings worldSettingsIn, YggdrasilAuthenticationService authServiceIn, MinecraftSessionService sessionServiceIn, GameProfileRepository profileRepoIn, PlayerProfileCache profileCacheIn)
    {
        super(new File(clientIn.mcDataDir, "saves"), clientIn.getProxy(), clientIn.getDataFixer(), authServiceIn, sessionServiceIn, profileRepoIn, profileCacheIn);
        this.setServerOwner(clientIn.getSession().getUsername());
        this.setFolderName(folderNameIn);
        this.setWorldName(worldNameIn);
        this.setDemo(clientIn.isDemo());
        this.canCreateBonusChest(worldSettingsIn.isBonusChestEnabled());
        this.setBuildLimit(256);
        this.setPlayerList(new IntegratedPlayerList(this));
        this.mc = clientIn;
        this.worldSettings = this.isDemo() ? WorldServerDemo.DEMO_WORLD_SETTINGS : worldSettingsIn;
        // TODO Custom loading screen
        ISaveHandler isavehandler = this.getActiveAnvilConverter().getSaveLoader(folderNameIn, false);
        WorldInfo worldinfo = isavehandler.loadWorldInfo();
>>>>    NBTTagCompound nbt = worldinfo.getPlayerNBTTagCompound();        
        if(nbt != null && nbt.hasKey("Dimension"))
        {
            int dim = nbt.getInteger("Dimension");
            PacketThreadUtil.lastDimensionId = dim;
            mc.loadingScreen.setLoadingProgress(-1);
        }
        //
    }

The worldinfo comes from isavehandler.loadWorldInfo(). Maybe it looks for the level.dat file.

Speiger commented 5 years ago
@Nullable
public WorldInfo loadWorldInfo()
{
    File file1 = new File(this.worldDirectory, "level.dat");

    if (file1.exists())
    {
        WorldInfo worldinfo = SaveFormatOld.loadAndFix(file1, this.dataFixer, this);

        if (worldinfo != null)
        {
            return worldinfo;
        }
    }

    net.minecraftforge.fml.common.FMLCommonHandler.instance().confirmBackupLevelDatUse(this);
    file1 = new File(this.worldDirectory, "level.dat_old");
    return file1.exists() ? SaveFormatOld.loadAndFix(file1, this.dataFixer, this) : null;
}

I think this speaks a lot for whos issue that is. It can be null because it could be that a "saveFile" isnt present. My preview handler doesnt create the "WorldData" files out of the batch. (Neither does mc i think) so yeah would be nice if you could make sure if the "WorldInfo isnt null" because it can be.

Speiger commented 5 years ago

It would be really nice if you could fix that, since ChunkPregen & Optifine would be pretty powerful if they can work with each other. I do not know how far you back you guys support optifine (in minecraft versions) but i do support [1.4.7-1.7.2-1.7.10-1.8.9-1.10.2-1.11-1.12 (Soon 1.13 With rift)] But it would be nice if the issue exists also in older versions that if you can fix it there too, but it is not nessesary, as long 1.12+ gets compatible that would be really nice.

sp614x commented 5 years ago

OptiFine bugfixes get backported down to 1.7.2 if possible. This patch (custom loading screens) have been ported back to 1.9.x. Older versions (1.8.x, 1.7.x) should be OK.

Speiger commented 5 years ago

ok thank you very much ^^"

Speiger commented 5 years ago

just to ask because i want to announce it so people know, do you have an eta? (ruff one is enough)

sp614x commented 5 years ago

OptiFine 1.12.2_HD_U_E4_pre1

Speiger commented 5 years ago

i know this is closed and this is a bigger request. But chunkpregen 2.0 comes out this weekend and a lot of optifine users most likely will use it with the latest none preview version and will gain this bug.

Since its been 3 months since the last patch i would ask you to release the preview as patch. I know there was not much changed, but it might be that there will be a lot of people reporting this bug to me (without reading my "known issues section")

Speiger commented 5 years ago

but before you do that @sp614x make sure that when the "loadAllWorlds" is called that it recreates the WorldInfo it was not found because that was a seperate crash that i found (for now fixed in my mod but this is not safe)