Fix MC-128953
This commit is contained in:
parent
774084be35
commit
32bac210ff
4 changed files with 104 additions and 45 deletions
|
@ -1,5 +1,6 @@
|
||||||
package org.dimdev.vanillafix;
|
package org.dimdev.vanillafix;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.*;
|
import net.minecraft.client.gui.*;
|
||||||
import net.minecraft.client.resources.I18n;
|
import net.minecraft.client.resources.I18n;
|
||||||
import net.minecraft.crash.CrashReport;
|
import net.minecraft.crash.CrashReport;
|
||||||
|
@ -9,6 +10,8 @@ import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dimdev.ddutils.HasteUpload;
|
import org.dimdev.ddutils.HasteUpload;
|
||||||
|
import org.dimdev.vanillafix.mixins.client.IFixedMinecraft;
|
||||||
|
import org.dimdev.vanillafix.mixins.client.MixinMinecraft;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -39,6 +42,7 @@ public class GuiCrashScreen extends GuiScreen {
|
||||||
try {
|
try {
|
||||||
if (button.id == 0) {
|
if (button.id == 0) {
|
||||||
mc.displayGuiScreen(new GuiMainMenu());
|
mc.displayGuiScreen(new GuiMainMenu());
|
||||||
|
((IFixedMinecraft) mc).clearCurrentReport();
|
||||||
} else if (button.id == 1) {
|
} else if (button.id == 1) {
|
||||||
if (hasteLink == null) {
|
if (hasteLink == null) {
|
||||||
hasteLink = HasteUpload.uploadToHaste(HASTE_BASE_URL, "txt", report.getCompleteReport());
|
hasteLink = HasteUpload.uploadToHaste(HASTE_BASE_URL, "txt", report.getCompleteReport());
|
||||||
|
|
|
@ -9,7 +9,6 @@ import net.minecraft.network.play.INetHandlerPlayServer;
|
||||||
import net.minecraft.network.play.client.CPacketConfirmTeleport;
|
import net.minecraft.network.play.client.CPacketConfirmTeleport;
|
||||||
import net.minecraft.network.play.client.CPacketPlayer;
|
import net.minecraft.network.play.client.CPacketPlayer;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.text.ITextComponent;
|
import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.util.text.TextComponentTranslation;
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
|
@ -117,9 +116,7 @@ public abstract class MixinNetHandlerPlayServer implements INetHandlerPlayServer
|
||||||
// Instead, we will send another packet both here and in processConfirmTeleport if the position the client
|
// Instead, we will send another packet both here and in processConfirmTeleport if the position the client
|
||||||
// was sent is no longer good (exceeds tolerance):
|
// was sent is no longer good (exceeds tolerance):
|
||||||
|
|
||||||
LOGGER.info("Player sent move packets before confirming");
|
|
||||||
if (targetPos.squareDistanceTo(player.posX, player.posY, player.posZ) > 1.0D) {
|
if (targetPos.squareDistanceTo(player.posX, player.posY, player.posZ) > 1.0D) {
|
||||||
LOGGER.info("Distance became too big: " + targetPos + " vs. " + new Vec3d(player.posX, player.posY, player.posY));
|
|
||||||
setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
|
setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +196,6 @@ public abstract class MixinNetHandlerPlayServer implements INetHandlerPlayServer
|
||||||
// Entity.move already made sure that the player didn't cheat, and reverting the move would be wrong because
|
// Entity.move already made sure that the player didn't cheat, and reverting the move would be wrong because
|
||||||
// the prevX/Y/Z is no longer good in the new dimension. This fixes MC-123364.
|
// the prevX/Y/Z is no longer good in the new dimension. This fixes MC-123364.
|
||||||
if (player.isInvulnerableDimensionChange()) {
|
if (player.isInvulnerableDimensionChange()) {
|
||||||
LOGGER.info("Doing teleport");
|
|
||||||
// A better name for invulnerableDimensionChange would be "lastBlockCollisionCausedPlayerMove". See
|
// A better name for invulnerableDimensionChange would be "lastBlockCollisionCausedPlayerMove". See
|
||||||
// https://github.com/ModCoderPack/MCPBot-Issues/issues/624. This happens when the move caused a
|
// https://github.com/ModCoderPack/MCPBot-Issues/issues/624. This happens when the move caused a
|
||||||
// collision that teleported the player elsewhere.
|
// collision that teleported the player elsewhere.
|
||||||
|
@ -283,11 +279,9 @@ public abstract class MixinNetHandlerPlayServer implements INetHandlerPlayServer
|
||||||
|
|
||||||
if (packet.getTeleportId() == teleportId) {
|
if (packet.getTeleportId() == teleportId) {
|
||||||
if (targetPos.squareDistanceTo(player.posX, player.posY, player.posZ) > 1.0D) {
|
if (targetPos.squareDistanceTo(player.posX, player.posY, player.posZ) > 1.0D) {
|
||||||
LOGGER.info("Position accepted no longer good");
|
|
||||||
// The client accepted the position change, but it's too late, something moved the player. Sync it again.
|
// The client accepted the position change, but it's too late, something moved the player. Sync it again.
|
||||||
setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
|
setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Teleport accepted");
|
|
||||||
targetPos = null;
|
targetPos = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package org.dimdev.vanillafix.mixins.client;
|
||||||
|
|
||||||
|
public interface IFixedMinecraft {
|
||||||
|
public void clearCurrentReport();
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ package org.dimdev.vanillafix.mixins.client;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiMemoryErrorScreen;
|
import net.minecraft.client.gui.GuiMemoryErrorScreen;
|
||||||
import net.minecraft.client.gui.GuiScreen;
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
|
import net.minecraft.client.multiplayer.WorldClient;
|
||||||
|
import net.minecraft.client.renderer.RenderGlobal;
|
||||||
import net.minecraft.crash.CrashReport;
|
import net.minecraft.crash.CrashReport;
|
||||||
import net.minecraft.init.Bootstrap;
|
import net.minecraft.init.Bootstrap;
|
||||||
import net.minecraft.profiler.ISnooperInfo;
|
import net.minecraft.profiler.ISnooperInfo;
|
||||||
|
@ -14,10 +16,7 @@ import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dimdev.vanillafix.GuiCrashScreen;
|
import org.dimdev.vanillafix.GuiCrashScreen;
|
||||||
import org.lwjgl.LWJGLException;
|
import org.lwjgl.LWJGLException;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.*;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -28,18 +27,18 @@ import java.util.Date;
|
||||||
@SuppressWarnings({"unused", "NonConstantFieldWithUpperCaseName", "RedundantThrows"}) // Shadow
|
@SuppressWarnings({"unused", "NonConstantFieldWithUpperCaseName", "RedundantThrows"}) // Shadow
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
@Mixin(Minecraft.class)
|
@Mixin(Minecraft.class)
|
||||||
public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo {
|
@Implements(@Interface(iface = IFixedMinecraft.class, prefix = "minecraft$"))
|
||||||
|
public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo, IFixedMinecraft {
|
||||||
|
|
||||||
@Shadow volatile boolean running;
|
@Shadow volatile boolean running;
|
||||||
@Shadow private boolean hasCrashed;
|
@Shadow private boolean hasCrashed;
|
||||||
@Shadow private CrashReport crashReporter;
|
@Shadow private CrashReport crashReporter;
|
||||||
|
@Shadow private long debugCrashKeyPressTime;
|
||||||
|
|
||||||
@Shadow private void init() throws LWJGLException, IOException {}
|
@Shadow private void init() throws LWJGLException, IOException {}
|
||||||
|
|
||||||
@Shadow private void runGameLoop() throws IOException {}
|
@Shadow private void runGameLoop() throws IOException {}
|
||||||
|
|
||||||
@Shadow public void freeMemory() {}
|
|
||||||
|
|
||||||
@Shadow public void displayGuiScreen(@Nullable GuiScreen guiScreenIn) {}
|
@Shadow public void displayGuiScreen(@Nullable GuiScreen guiScreenIn) {}
|
||||||
|
|
||||||
@Shadow public CrashReport addGraphicsAndWorldToCrashReport(CrashReport theCrash) { return null; }
|
@Shadow public CrashReport addGraphicsAndWorldToCrashReport(CrashReport theCrash) { return null; }
|
||||||
|
@ -50,6 +49,20 @@ public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo {
|
||||||
|
|
||||||
@Shadow public void displayCrashReport(CrashReport crashReportIn) {}
|
@Shadow public void displayCrashReport(CrashReport crashReportIn) {}
|
||||||
|
|
||||||
|
@Shadow public abstract void loadWorld(@Nullable WorldClient worldClientIn);
|
||||||
|
|
||||||
|
@Shadow public WorldClient world;
|
||||||
|
|
||||||
|
@Shadow public static byte[] memoryReserve;
|
||||||
|
|
||||||
|
@Shadow public RenderGlobal renderGlobal;
|
||||||
|
|
||||||
|
private CrashReport currentReport = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the player to choose to return to the title screen after a crash, or get
|
||||||
|
* a pasteable link to the crash report on paste.dimdev.org.
|
||||||
|
*/
|
||||||
@SuppressWarnings("CallToSystemGC")
|
@SuppressWarnings("CallToSystemGC")
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -58,9 +71,9 @@ public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo {
|
||||||
try {
|
try {
|
||||||
init();
|
init();
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Initializing game");
|
CrashReport report = CrashReport.makeCrashReport(throwable, "Initializing game");
|
||||||
crashreport.makeCategory("Initialization");
|
report.makeCategory("Initialization");
|
||||||
displayCrashReport(addGraphicsAndWorldToCrashReport(crashreport)); // TODO: GUI for this too
|
displayCrashReport(addGraphicsAndWorldToCrashReport(report)); // TODO: GUI for this too
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,8 +84,8 @@ public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo {
|
||||||
runGameLoop();
|
runGameLoop();
|
||||||
} catch (OutOfMemoryError e) {
|
} catch (OutOfMemoryError e) {
|
||||||
freeMemory();
|
freeMemory();
|
||||||
|
// TODO: Use displayCrashScreen?
|
||||||
displayGuiScreen(new GuiMemoryErrorScreen());
|
displayGuiScreen(new GuiMemoryErrorScreen());
|
||||||
System.gc();
|
|
||||||
} catch (ReportedException e) {
|
} catch (ReportedException e) {
|
||||||
addGraphicsAndWorldToCrashReport(e.getCrashReport());
|
addGraphicsAndWorldToCrashReport(e.getCrashReport());
|
||||||
freeMemory();
|
freeMemory();
|
||||||
|
@ -95,7 +108,16 @@ public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void displayCrashScreen(CrashReport report) {
|
public void displayCrashScreen(CrashReport report) {
|
||||||
try {
|
if (currentReport != null) {
|
||||||
|
// There was already a crash being reported, the crash screen might have
|
||||||
|
// crashed. Report it normally instead.
|
||||||
|
LOGGER.error("An uncaught exception occured while displaying the crash screen, making normal report instead", report.getCrashCause());
|
||||||
|
displayCrashReport(report);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentReport = report;
|
||||||
|
|
||||||
File crashReportsDir = new File(Minecraft.getMinecraft().mcDataDir, "crash-reports");
|
File crashReportsDir = new File(Minecraft.getMinecraft().mcDataDir, "crash-reports");
|
||||||
File crashReportSaveFile = new File(crashReportsDir, "crash-" + new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss").format(new Date()) + "-client.txt");
|
File crashReportSaveFile = new File(crashReportsDir, "crash-" + new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss").format(new Date()) + "-client.txt");
|
||||||
|
|
||||||
|
@ -116,14 +138,48 @@ public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo {
|
||||||
Bootstrap.printToSYSOUT("Recoverable game crash! Crash report could not be saved.");
|
Bootstrap.printToSYSOUT("Recoverable game crash! Crash report could not be saved.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset hasCrashed and debugCrashKeyPressTime
|
||||||
|
hasCrashed = false;
|
||||||
|
debugCrashKeyPressTime = -1;
|
||||||
|
|
||||||
// Display the crash screen
|
// Display the crash screen
|
||||||
displayGuiScreen(new GuiCrashScreen(reportFile, report));
|
displayGuiScreen(new GuiCrashScreen(reportFile, report));
|
||||||
|
}
|
||||||
|
|
||||||
// Keep running
|
/**
|
||||||
hasCrashed = false;
|
* Disconnect from the current world and free memory, using a memory reserve
|
||||||
} catch (Throwable e) {
|
* to make sure that an OutOfMemory doesn't happen while doing this.
|
||||||
LOGGER.error("The crash screen threw an error, reverting to default crash report", e);
|
* <p>
|
||||||
displayCrashReport(report);
|
* Bugs Fixed:
|
||||||
}
|
* - https://bugs.mojang.com/browse/MC-128953
|
||||||
|
* - Memory reserve not recreated after out-of memory
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("CallToSystemGC")
|
||||||
|
@Overwrite
|
||||||
|
public void freeMemory() {
|
||||||
|
try {
|
||||||
|
memoryReserve = new byte[0];
|
||||||
|
renderGlobal.deleteAllDisplayLists();
|
||||||
|
} catch (Throwable ignored) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
System.gc();
|
||||||
|
// Fix: Close the connection to avoid receiving packets from old server
|
||||||
|
// when playing in another world (MC-128953)
|
||||||
|
if (world != null) {
|
||||||
|
world.sendQuittingDisconnectingPacket();
|
||||||
|
}
|
||||||
|
loadWorld(null);
|
||||||
|
} catch (Throwable ignored) {}
|
||||||
|
|
||||||
|
System.gc();
|
||||||
|
|
||||||
|
// Fix: Re-create memory reserve so that future crashes work well too
|
||||||
|
memoryReserve = new byte[10485760];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearCurrentReport() {
|
||||||
|
currentReport = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue