Skip to content

Commit 32bac21

Browse files
committed
Fix MC-128953
1 parent 774084b commit 32bac21

File tree

4 files changed

+101
-42
lines changed

4 files changed

+101
-42
lines changed

src/main/java/org/dimdev/vanillafix/GuiCrashScreen.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.dimdev.vanillafix;
22

3+
import net.minecraft.client.Minecraft;
34
import net.minecraft.client.gui.*;
45
import net.minecraft.client.resources.I18n;
56
import net.minecraft.crash.CrashReport;
@@ -9,6 +10,8 @@
910
import org.apache.logging.log4j.LogManager;
1011
import org.apache.logging.log4j.Logger;
1112
import org.dimdev.ddutils.HasteUpload;
13+
import org.dimdev.vanillafix.mixins.client.IFixedMinecraft;
14+
import org.dimdev.vanillafix.mixins.client.MixinMinecraft;
1215

1316
import java.io.File;
1417
import java.net.URI;
@@ -39,6 +42,7 @@ protected void actionPerformed(GuiButton button) {
3942
try {
4043
if (button.id == 0) {
4144
mc.displayGuiScreen(new GuiMainMenu());
45+
((IFixedMinecraft) mc).clearCurrentReport();
4246
} else if (button.id == 1) {
4347
if (hasteLink == null) {
4448
hasteLink = HasteUpload.uploadToHaste(HASTE_BASE_URL, "txt", report.getCompleteReport());

src/main/java/org/dimdev/vanillafix/mixins/MixinNetHandlerPlayServer.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import net.minecraft.network.play.client.CPacketConfirmTeleport;
1010
import net.minecraft.network.play.client.CPacketPlayer;
1111
import net.minecraft.server.MinecraftServer;
12-
import net.minecraft.util.math.BlockPos;
1312
import net.minecraft.util.math.Vec3d;
1413
import net.minecraft.util.text.ITextComponent;
1514
import net.minecraft.util.text.TextComponentTranslation;
@@ -117,9 +116,7 @@ public void processPlayer(CPacketPlayer packet) {
117116
// Instead, we will send another packet both here and in processConfirmTeleport if the position the client
118117
// was sent is no longer good (exceeds tolerance):
119118

120-
LOGGER.info("Player sent move packets before confirming");
121119
if (targetPos.squareDistanceTo(player.posX, player.posY, player.posZ) > 1.0D) {
122-
LOGGER.info("Distance became too big: " + targetPos + " vs. " + new Vec3d(player.posX, player.posY, player.posY));
123120
setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
124121
}
125122

@@ -199,7 +196,6 @@ public void processPlayer(CPacketPlayer packet) {
199196
// Entity.move already made sure that the player didn't cheat, and reverting the move would be wrong because
200197
// the prevX/Y/Z is no longer good in the new dimension. This fixes MC-123364.
201198
if (player.isInvulnerableDimensionChange()) {
202-
LOGGER.info("Doing teleport");
203199
// A better name for invulnerableDimensionChange would be "lastBlockCollisionCausedPlayerMove". See
204200
// https://github.com/ModCoderPack/MCPBot-Issues/issues/624. This happens when the move caused a
205201
// collision that teleported the player elsewhere.
@@ -283,11 +279,9 @@ public void processConfirmTeleport(CPacketConfirmTeleport packet) {
283279

284280
if (packet.getTeleportId() == teleportId) {
285281
if (targetPos.squareDistanceTo(player.posX, player.posY, player.posZ) > 1.0D) {
286-
LOGGER.info("Position accepted no longer good");
287282
// The client accepted the position change, but it's too late, something moved the player. Sync it again.
288283
setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
289284
} else {
290-
LOGGER.info("Teleport accepted");
291285
targetPos = null;
292286
}
293287
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.dimdev.vanillafix.mixins.client;
2+
3+
public interface IFixedMinecraft {
4+
public void clearCurrentReport();
5+
}

src/main/java/org/dimdev/vanillafix/mixins/client/MixinMinecraft.java

Lines changed: 92 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import net.minecraft.client.Minecraft;
44
import net.minecraft.client.gui.GuiMemoryErrorScreen;
55
import net.minecraft.client.gui.GuiScreen;
6+
import net.minecraft.client.multiplayer.WorldClient;
7+
import net.minecraft.client.renderer.RenderGlobal;
68
import net.minecraft.crash.CrashReport;
79
import net.minecraft.init.Bootstrap;
810
import net.minecraft.profiler.ISnooperInfo;
@@ -14,10 +16,7 @@
1416
import org.apache.logging.log4j.Logger;
1517
import org.dimdev.vanillafix.GuiCrashScreen;
1618
import org.lwjgl.LWJGLException;
17-
import org.spongepowered.asm.mixin.Final;
18-
import org.spongepowered.asm.mixin.Mixin;
19-
import org.spongepowered.asm.mixin.Overwrite;
20-
import org.spongepowered.asm.mixin.Shadow;
19+
import org.spongepowered.asm.mixin.*;
2120

2221
import javax.annotation.Nullable;
2322
import java.io.File;
@@ -28,18 +27,18 @@
2827
@SuppressWarnings({"unused", "NonConstantFieldWithUpperCaseName", "RedundantThrows"}) // Shadow
2928
@SideOnly(Side.CLIENT)
3029
@Mixin(Minecraft.class)
31-
public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo {
30+
@Implements(@Interface(iface = IFixedMinecraft.class, prefix = "minecraft$"))
31+
public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo, IFixedMinecraft {
3232

3333
@Shadow volatile boolean running;
3434
@Shadow private boolean hasCrashed;
3535
@Shadow private CrashReport crashReporter;
36+
@Shadow private long debugCrashKeyPressTime;
3637

3738
@Shadow private void init() throws LWJGLException, IOException {}
3839

3940
@Shadow private void runGameLoop() throws IOException {}
4041

41-
@Shadow public void freeMemory() {}
42-
4342
@Shadow public void displayGuiScreen(@Nullable GuiScreen guiScreenIn) {}
4443

4544
@Shadow public CrashReport addGraphicsAndWorldToCrashReport(CrashReport theCrash) { return null; }
@@ -50,6 +49,20 @@ public abstract class MixinMinecraft implements IThreadListener, ISnooperInfo {
5049

5150
@Shadow public void displayCrashReport(CrashReport crashReportIn) {}
5251

52+
@Shadow public abstract void loadWorld(@Nullable WorldClient worldClientIn);
53+
54+
@Shadow public WorldClient world;
55+
56+
@Shadow public static byte[] memoryReserve;
57+
58+
@Shadow public RenderGlobal renderGlobal;
59+
60+
private CrashReport currentReport = null;
61+
62+
/**
63+
* Allows the player to choose to return to the title screen after a crash, or get
64+
* a pasteable link to the crash report on paste.dimdev.org.
65+
*/
5366
@SuppressWarnings("CallToSystemGC")
5467
@Overwrite
5568
public void run() {
@@ -58,9 +71,9 @@ public void run() {
5871
try {
5972
init();
6073
} catch (Throwable throwable) {
61-
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Initializing game");
62-
crashreport.makeCategory("Initialization");
63-
displayCrashReport(addGraphicsAndWorldToCrashReport(crashreport)); // TODO: GUI for this too
74+
CrashReport report = CrashReport.makeCrashReport(throwable, "Initializing game");
75+
report.makeCategory("Initialization");
76+
displayCrashReport(addGraphicsAndWorldToCrashReport(report)); // TODO: GUI for this too
6477
return;
6578
}
6679

@@ -71,8 +84,8 @@ public void run() {
7184
runGameLoop();
7285
} catch (OutOfMemoryError e) {
7386
freeMemory();
87+
// TODO: Use displayCrashScreen?
7488
displayGuiScreen(new GuiMemoryErrorScreen());
75-
System.gc();
7689
} catch (ReportedException e) {
7790
addGraphicsAndWorldToCrashReport(e.getCrashReport());
7891
freeMemory();
@@ -95,35 +108,78 @@ public void run() {
95108
}
96109

97110
public void displayCrashScreen(CrashReport report) {
111+
if (currentReport != null) {
112+
// There was already a crash being reported, the crash screen might have
113+
// crashed. Report it normally instead.
114+
LOGGER.error("An uncaught exception occured while displaying the crash screen, making normal report instead", report.getCrashCause());
115+
displayCrashReport(report);
116+
return;
117+
}
118+
119+
currentReport = report;
120+
121+
File crashReportsDir = new File(Minecraft.getMinecraft().mcDataDir, "crash-reports");
122+
File crashReportSaveFile = new File(crashReportsDir, "crash-" + new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss").format(new Date()) + "-client.txt");
123+
124+
// Print the report in bootstrap
125+
Bootstrap.printToSYSOUT(report.getCompleteReport());
126+
127+
// Save the report and print file in bootstrap
128+
File reportFile = null;
129+
if (report.getFile() != null) {
130+
reportFile = report.getFile();
131+
} else if (report.saveToFile(crashReportSaveFile)) {
132+
reportFile = crashReportSaveFile;
133+
}
134+
135+
if (reportFile != null) {
136+
Bootstrap.printToSYSOUT("Recoverable game crash! Crash report saved to: " + reportFile);
137+
} else {
138+
Bootstrap.printToSYSOUT("Recoverable game crash! Crash report could not be saved.");
139+
}
140+
141+
// Reset hasCrashed and debugCrashKeyPressTime
142+
hasCrashed = false;
143+
debugCrashKeyPressTime = -1;
144+
145+
// Display the crash screen
146+
displayGuiScreen(new GuiCrashScreen(reportFile, report));
147+
}
148+
149+
/**
150+
* Disconnect from the current world and free memory, using a memory reserve
151+
* to make sure that an OutOfMemory doesn't happen while doing this.
152+
* <p>
153+
* Bugs Fixed:
154+
* - https://bugs.mojang.com/browse/MC-128953
155+
* - Memory reserve not recreated after out-of memory
156+
*/
157+
@SuppressWarnings("CallToSystemGC")
158+
@Overwrite
159+
public void freeMemory() {
98160
try {
99-
File crashReportsDir = new File(Minecraft.getMinecraft().mcDataDir, "crash-reports");
100-
File crashReportSaveFile = new File(crashReportsDir, "crash-" + new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss").format(new Date()) + "-client.txt");
101-
102-
// Print the report in bootstrap
103-
Bootstrap.printToSYSOUT(report.getCompleteReport());
104-
105-
// Save the report and print file in bootstrap
106-
File reportFile = null;
107-
if (report.getFile() != null) {
108-
reportFile = report.getFile();
109-
} else if (report.saveToFile(crashReportSaveFile)) {
110-
reportFile = crashReportSaveFile;
111-
}
161+
memoryReserve = new byte[0];
162+
renderGlobal.deleteAllDisplayLists();
163+
} catch (Throwable ignored) {}
112164

113-
if (reportFile != null) {
114-
Bootstrap.printToSYSOUT("Recoverable game crash! Crash report saved to: " + reportFile);
115-
} else {
116-
Bootstrap.printToSYSOUT("Recoverable game crash! Crash report could not be saved.");
165+
try {
166+
System.gc();
167+
// Fix: Close the connection to avoid receiving packets from old server
168+
// when playing in another world (MC-128953)
169+
if (world != null) {
170+
world.sendQuittingDisconnectingPacket();
117171
}
172+
loadWorld(null);
173+
} catch (Throwable ignored) {}
118174

119-
// Display the crash screen
120-
displayGuiScreen(new GuiCrashScreen(reportFile, report));
175+
System.gc();
121176

122-
// Keep running
123-
hasCrashed = false;
124-
} catch (Throwable e) {
125-
LOGGER.error("The crash screen threw an error, reverting to default crash report", e);
126-
displayCrashReport(report);
127-
}
177+
// Fix: Re-create memory reserve so that future crashes work well too
178+
memoryReserve = new byte[10485760];
179+
}
180+
181+
@Override
182+
public void clearCurrentReport() {
183+
currentReport = null;
128184
}
129185
}

0 commit comments

Comments
 (0)