fix: shut down co-processes on dedicated servers even if the server failed to start

This commit is contained in:
Johannes Frohnmeyer 2024-09-20 11:50:35 +02:00
parent ed442168e5
commit d8e15bdb34
Signed by: Johannes
GPG Key ID: E76429612C2929F4
5 changed files with 67 additions and 11 deletions

View File

@ -2,31 +2,34 @@ package io.gitlab.jfronny.libjf.coprocess;
import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.LibJf;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class CoProcessManager implements ModInitializer { public class CoProcessManager {
private final List<CoProcess> coProcesses = new ArrayList<>(); private static final List<CoProcess> coProcesses = new ArrayList<>();
@Override
public void onInitialize() { static {
coProcesses.addAll(FabricLoader.getInstance().getEntrypoints(LibJf.MOD_ID + ":coprocess", CoProcess.class)); coProcesses.addAll(FabricLoader.getInstance().getEntrypoints(LibJf.MOD_ID + ":coprocess", CoProcess.class));
Runtime.getRuntime().addShutdownHook(new Thread(this::stop)); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) ServerLifecycleEvents.SERVER_STOPPED.register(server -> CoProcessManager.stop());
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) ServerLifecycleEvents.SERVER_STOPPED.register(server -> this.stop()); Runtime.getRuntime().addShutdownHook(new Thread(CoProcessManager::stop));
start();
} }
private void start() { private static final AtomicBoolean started = new AtomicBoolean(false);
public static void start() {
if (started.getAndSet(true)) return;
for (CoProcess coProcess : coProcesses) { for (CoProcess coProcess : coProcesses) {
coProcess.start(); coProcess.start();
} }
} }
private void stop() { public static void stop() {
if (!started.getAndSet(false)) return;
for (Iterator<CoProcess> iter = coProcesses.iterator(); iter.hasNext(); ) { for (Iterator<CoProcess> iter = coProcesses.iterator(); iter.hasNext(); ) {
CoProcess coProcess = iter.next(); CoProcess coProcess = iter.next();
coProcess.stop(); coProcess.stop();

View File

@ -1,13 +1,24 @@
package io.gitlab.jfronny.libjf.coprocess; package io.gitlab.jfronny.libjf.coprocess;
public abstract class ThreadCoProcess implements CoProcess, Runnable { public abstract class ThreadCoProcess implements CoProcess, Runnable {
private final boolean isDaemon;
private Thread th = null; private Thread th = null;
private boolean closed = true; private boolean closed = true;
protected ThreadCoProcess() {
this(false);
}
protected ThreadCoProcess(boolean isDaemon) {
this.isDaemon = isDaemon;
}
@Override @Override
public void start() { public void start() {
if (th != null) stop(); if (th != null) stop();
closed = false; closed = false;
th = new Thread(this, getClass().getSimpleName()); th = new Thread(this, getClass().getSimpleName());
th.setDaemon(isDaemon);
th.start(); th.start();
} }

View File

@ -0,0 +1,27 @@
package io.gitlab.jfronny.libjf.mixin;
import io.gitlab.jfronny.libjf.coprocess.CoProcessManager;
import net.fabricmc.api.DedicatedServerModInitializer;
import net.minecraft.server.Main;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.MinecraftDedicatedServer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Main.class)
public class MainMixin {
@Unique private static boolean libjf$started = false;
@Inject(method = "main", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/server/MinecraftServer;startServer(Ljava/util/function/Function;)Lnet/minecraft/server/MinecraftServer;"))
private static void onStartServer(String[] args, CallbackInfo ci) {
libjf$started = true;
}
@Inject(method = "main", at = @At("RETURN"))
private static void onMain(String[] args, CallbackInfo ci) {
if (!libjf$started) CoProcessManager.stop();
}
}

View File

@ -18,9 +18,10 @@
"fabric-lifecycle-events-v1": "*" "fabric-lifecycle-events-v1": "*"
}, },
"entrypoints": { "entrypoints": {
"main": ["io.gitlab.jfronny.libjf.coprocess.CoProcessManager"], "main": ["io.gitlab.jfronny.libjf.coprocess.CoProcessManager::start"],
"preLaunch": ["io.gitlab.jfronny.libjf.LibJf"] "preLaunch": ["io.gitlab.jfronny.libjf.LibJf"]
}, },
"mixins": ["libjf-base.mixins.json"],
"custom": { "custom": {
"modmenu": { "modmenu": {
"parent": "libjf", "parent": "libjf",

View File

@ -0,0 +1,14 @@
{
"required": true,
"minVersion": "0.8",
"package": "io.gitlab.jfronny.libjf.mixin",
"compatibilityLevel": "JAVA_16",
"mixins": [
],
"server": [
"MainMixin"
],
"injectors": {
"defaultRequire": 1
}
}