object cleanup

This commit is contained in:
Brian Neumann-Fopiano
2026-08-22 11:29:37 -04:00
parent 770240e4f7
commit dce7af1955
12 changed files with 1257 additions and 647 deletions
@@ -96,7 +96,6 @@ import art.arcane.volmlib.util.collection.KMap;
import art.arcane.volmlib.util.exceptions.IrisException;
import art.arcane.iris.util.common.format.C;
import art.arcane.volmlib.util.function.NastyRunnable;
import art.arcane.volmlib.util.hotload.ConfigHotloadEngine;
import art.arcane.volmlib.util.hud.HudActionBar;
import art.arcane.volmlib.util.hud.HudBossBarLane;
import art.arcane.volmlib.util.io.IO;
@@ -165,7 +164,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
public static Bindings.Adventure audiences;
public static MultiverseCoreLink linkMultiverseCore;
public static IrisCompat compat;
public static ConfigHotloadEngine configHotloadEngine;
public static ChunkTickets tickets;
private static VolmitSender sender;
private static Thread shutdownHook;
@@ -663,13 +661,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
IrisServices.register(ManagedWorldLoader.class, (ManagedWorldLoader) this::loadManagedWorld);
SettingsHotloadWatch watch = new SettingsHotloadWatch(getDataFile("settings.json"));
settingsHotloadWatch = watch;
configHotloadEngine = new ConfigHotloadEngine(
watch::isSettingsFile,
watch::knownSettingsFiles,
watch::readSettingsContent,
watch::normalizeSettingsContent
);
configHotloadEngine.configure(500L, 3_000L, List.of(watch.settingsFile()), List.of());
// Stale-temp cleanup must complete before services enable: StudioSVC.onEnable downloads
// packs through cache/temp on an async thread, and a concurrent delete of that folder
// truncated pack imports mid-copy (partial packs/<key> without dimensions/).
@@ -714,7 +705,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
pendingWorldReplacements.captureVanillaLevelContext();
pendingWorldReplacements.verifyLoadedPublishedWorlds();
J.a(this::bstats);
J.ar(() -> settingsHotloadWatch.checkConfigHotload(configHotloadEngine), 10);
J.ar(watch::checkConfigHotload, 10);
J.sr(this::tickQueue, 0);
J.s(this::setupPapi);
if (IrisStartupValidation.isReady()) {
@@ -883,9 +874,10 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
BukkitPlatform.hudBar().shutdown();
BukkitPlatform.hudLanes().shutdown();
}
if (configHotloadEngine != null) {
configHotloadEngine.clear();
configHotloadEngine = null;
SettingsHotloadWatch activeSettingsHotloadWatch = settingsHotloadWatch;
settingsHotloadWatch = null;
if (activeSettingsHotloadWatch != null) {
activeSettingsHotloadWatch.close();
}
// super.onDisable() cancels plugin tasks and unregisters every listener.
super.onDisable();
@@ -1,126 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2026 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package art.arcane.iris.core;
import art.arcane.iris.Iris;
import art.arcane.iris.core.localization.IrisLanguage;
import art.arcane.volmlib.util.hotload.ConfigHotloadEngine;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
/**
* Identity and hotload handling for settings.json. Supplies the predicates the
* {@link ConfigHotloadEngine} is built from and drains the touched-file queue.
*/
public final class SettingsHotloadWatch {
private static final int MAX_SETTINGS_BYTES = 2 * 1024 * 1024;
private final File settingsFile;
public SettingsHotloadWatch(File settingsFile) {
this.settingsFile = settingsFile;
}
public File settingsFile() {
return settingsFile;
}
public void checkConfigHotload(ConfigHotloadEngine engine) {
if (engine == null) {
return;
}
for (ConfigHotloadEngine.StableContentSnapshot snapshot : engine.pollTouchedSnapshots()) {
if ("missing".equals(snapshot.signature())) {
engine.processSnapshotChange(snapshot, ignored -> true, null);
Iris.warn("settings.json was removed; retaining the last valid runtime settings.");
continue;
}
engine.processSnapshotChange(
snapshot,
stable -> applySettingsSnapshot(stable.file(), stable.normalizedContent()),
ignored -> Iris.info("Hotloaded settings.json ")
);
}
IrisLanguage.update();
}
public boolean isSettingsFile(File file) {
if (file == null || settingsFile == null) {
return false;
}
return settingsFile.getAbsoluteFile().equals(file.getAbsoluteFile());
}
public List<File> knownSettingsFiles() {
if (settingsFile == null) {
return List.of();
}
return List.of(settingsFile);
}
public String readSettingsContent(File file) {
if (file == null || !file.exists() || !file.isFile()) {
return null;
}
try (InputStream input = Files.newInputStream(file.toPath())) {
byte[] content = input.readNBytes(MAX_SETTINGS_BYTES + 1);
if (content.length > MAX_SETTINGS_BYTES) {
throw new IOException("Settings exceed " + MAX_SETTINGS_BYTES + " bytes: " + file);
}
return new String(content, StandardCharsets.UTF_8);
} catch (Throwable ex) {
Iris.warn("Failed to read settings file %s: %s%s",
file.getAbsolutePath(),
ex.getClass().getSimpleName(),
ex.getMessage() == null ? "" : " - " + ex.getMessage());
Iris.reportError(ex);
return null;
}
}
public String normalizeSettingsContent(String text) {
if (text == null) {
return null;
}
return text.replace("\r\n", "\n").trim();
}
private boolean applySettingsSnapshot(File file, String content) {
if (content == null) {
return false;
}
try {
return IrisSettings.applyHotloadSnapshot(content, IrisLanguage::reload);
} catch (RuntimeException failure) {
Iris.warn("Rejected invalid settings hotload from %s: %s",
file.getAbsolutePath(),
failure.getMessage() == null ? failure.getClass().getSimpleName() : failure.getMessage());
Iris.reportError(failure);
return false;
}
}
}