1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-29 16:47:56 +00:00

Fix: Release monitor buffers on *client* thread

These buffers were being released on the server thread, causing the
logical server in a single player session to crash just before shutting
down. It seems the crash happened late enough to not cause world
corruption issues, and so went unnoticed. It was however causing a
memory leak when quitting/rejoining worlds, and it left the save file
lock in limbo.
This commit is contained in:
ToadDev
2021-05-22 12:43:22 -07:00
parent 01d7aaf062
commit c820e051b3
4 changed files with 37 additions and 21 deletions

View File

@@ -20,6 +20,7 @@ import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtleModelLoader; import dan200.computercraft.client.render.TurtleModelLoader;
import dan200.computercraft.client.render.TurtlePlayerRenderer; import dan200.computercraft.client.render.TurtlePlayerRenderer;
import dan200.computercraft.events.ClientUnloadWorldEvent;
import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.common.IColouredItem;
@@ -47,14 +48,13 @@ import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegi
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry;
import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.fabricmc.fabric.mixin.object.builder.ModelPredicateProviderRegistrySpecificAccessor; import net.fabricmc.fabric.mixin.object.builder.ModelPredicateProviderRegistrySpecificAccessor;
@Environment (EnvType.CLIENT) @Environment (EnvType.CLIENT)
public final class ComputerCraftProxyClient implements ClientModInitializer { public final class ComputerCraftProxyClient implements ClientModInitializer {
public static void initEvents() { private static void initEvents() {
ClientUnloadWorldEvent.EVENT.register( () -> ClientMonitor.destroyAll() );
} }
@Override @Override
@@ -96,13 +96,9 @@ public final class ComputerCraftProxyClient implements ClientModInitializer {
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED); () -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED);
ClientRegistry.onItemColours(); ClientRegistry.onItemColours();
// TODO Verify this does things properly initEvents();
ServerWorldEvents.UNLOAD.register(((minecraftServer, serverWorld) -> {
ClientMonitor.destroyAll();
}));
} }
// My IDE doesn't think so, but we do actually need these generics. // My IDE doesn't think so, but we do actually need these generics.
private static void registerContainers() { private static void registerContainers() {
ScreenRegistry.<ContainerComputer, GuiComputer<ContainerComputer>>register(ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create); ScreenRegistry.<ContainerComputer, GuiComputer<ContainerComputer>>register(ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create);
@@ -125,15 +121,4 @@ public final class ComputerCraftProxyClient implements ClientModInitializer {
ModelPredicateProviderRegistrySpecificAccessor.callRegister(item.get(), id, getter); ModelPredicateProviderRegistrySpecificAccessor.callRegister(item.get(), id, getter);
} }
} }
// @Mod.EventBusSubscriber (modid = ComputerCraft.MOD_ID, value = Dist.CLIENT)
// public static final class ForgeHandlers {
// @SubscribeEvent
// public static void onWorldUnload(WorldEvent.Unload event) {
// if (event.getWorld()
// .isClient()) {
// ClientMonitor.destroyAll();
// }
// }
// }
} }

View File

@@ -0,0 +1,17 @@
package dan200.computercraft.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
@FunctionalInterface
public interface ClientUnloadWorldEvent
{
Event<ClientUnloadWorldEvent> EVENT = EventFactory.createArrayBacked( ClientUnloadWorldEvent.class,
callbacks -> () -> {
for( ClientUnloadWorldEvent callback : callbacks) {
callback.onClientUnloadWorld();
}
});
void onClientUnloadWorld();
}

View File

@@ -7,6 +7,9 @@
package dan200.computercraft.mixin; package dan200.computercraft.mixin;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.events.ClientUnloadWorldEvent;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.world.ClientWorld;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@@ -15,9 +18,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@Mixin (MinecraftClient.class) @Mixin (MinecraftClient.class)
public abstract class MixinMinecraftGame { public abstract class MixinMinecraftClient
{
@Inject (method = "render", at = @At ("HEAD")) @Inject (method = "render", at = @At ("HEAD"))
private void onRender(CallbackInfo info) { private void onRender(CallbackInfo info) {
FrameInfo.onRenderFrame(); FrameInfo.onRenderFrame();
} }
@Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At ("RETURN"))
private void disconnectAfter(Screen screen, CallbackInfo info) {
ClientUnloadWorldEvent.EVENT.invoker().onClientUnloadWorld();
}
@Inject(method = "joinWorld", at = @At("RETURN"))
private void joinWorldAfter(ClientWorld world, CallbackInfo info) {
ClientUnloadWorldEvent.EVENT.invoker().onClientUnloadWorld();
}
} }

View File

@@ -20,7 +20,7 @@
"HeldItemRendererAccess", "HeldItemRendererAccess",
"MixinHeldItemRenderer", "MixinHeldItemRenderer",
"MixinItemFrameEntityRenderer", "MixinItemFrameEntityRenderer",
"MixinMinecraftGame", "MixinMinecraftClient",
"MixinScreen", "MixinScreen",
"MixinWorldRenderer" "MixinWorldRenderer"
], ],