Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
cfd5c33
initial design
Tektonikal Oct 30, 2026
ed1bab6
adjustments
Tektonikal Oct 30, 2026
31be14f
Merge branch 'v1' into hotwire-compat
Wyvest Oct 30, 2026
ff630b4
fix stuff
Wyvest Oct 31, 2026
5661953
fixes
Wyvest Oct 31, 2026
ff536fd
fix stuff
Wyvest Oct 31, 2026
85cfea3
a
Wyvest Oct 31, 2026
9e4a7b3
Update HotwireBridge.kt
Wyvest Oct 31, 2026
9cb0969
fa
Wyvest Oct 31, 2026
8723489
a
Wyvest Oct 31, 2026
ba0da5d
Update HotwireBridge.kt
Wyvest Oct 31, 2026
8d251ee
aaaaaaaa
Wyvest Oct 31, 2026
c00e940
fix
Wyvest Oct 31, 2026
96bd052
a
Wyvest Oct 31, 2026
a7fa3e8
a
Wyvest Oct 31, 2026
7923090
fixes
Wyvest Oct 31, 2026
d1c58f8
fixe moreeee
Wyvest Oct 31, 2026
80096d5
aaaa
Wyvest Oct 31, 2026
a07f57d
ughhhhhh
Wyvest Oct 31, 2026
2014676
fix more more more more more stupid shit
Wyvest Oct 31, 2026
8bf844b
aaa
Wyvest Oct 31, 2026
f037fe8
Bruhhh
Wyvest Nov 2, 2026
e0a5c39
fix even more stupid shit
Wyvest Nov 2, 2026
434f21d
a
Wyvest Nov 2, 2026
d5d1908
gadg
Wyvest Nov 2, 2026
6710cf6
Merge branch 'v1' into pr/1282
Wyvest Nov 2, 2026
ef6b93c
Merge branch 'v1' into pr/1282
Wyvest Nov 2, 2026
5b35417
fix build issues and add 5 mod limit
Tektonikal Nov 2, 2026
5fd01a4
Merge branch 'v1' into pr/1282
Wyvest Nov 2, 2026
abd2e64
Merge branch 'v1' into hotwire-compat
lunaynx Nov 3, 2026
c566d48
Merge branch 'v1' into hotwire-compat
lunaynx Nov 3, 2026
b959e1c
update to use latest hotwire API
Tektonikal Nov 3, 2026
5f7d5f8
Merge remote-tracking branch 'origin/hotwire-compat' into hotwire-compat
Tektonikal Nov 3, 2026
dbacf14
Support Hotwire 0.6.1 API and overlay the switch bar
Tektonikal Nov 3, 2026
8732fa5
Merge branch 'v1' into hotwire-compat
lunaynx Nov 3, 2026
b9ff64e
fix review issues, improve UI
Tektonikal Nov 5, 2026
1b970e7
Merge branch 'v1' into hotwire-compat
lunaynx Nov 5, 2026
7ea8e31
more tests and improvements for hotwire
Tektonikal Nov 6, 2026
e7670a0
Merge remote-tracking branch 'origin/hotwire-compat' into hotwire-compat
Tektonikal Nov 6, 2026
ac1c1b0
fix: stop offering to queue store adds Hotwire refused
lunaynx Nov 6, 2026
917811c
fix: report updates queued for mods with other pending tasks
lunaynx Nov 6, 2026
c114e8a
fix: keep late configs alive until their window claims them
lunaynx Nov 6, 2026
3d0db03
fix: run config entrypoints an update adds to a decided mod
lunaynx Nov 6, 2026
e8fedf7
fix: let an updated mod's entrypoint replace its config instance
lunaynx Nov 6, 2026
83ae468
fix: suspend config keybinds while their mod is turned off
lunaynx Nov 6, 2026
877f393
fix: skip profile rebinds for configs of turned off mods
lunaynx Nov 6, 2026
8e5fac8
fix: keep the older config when saving it for a replacement fails
lunaynx Nov 6, 2026
ce04a5b
fix: restore the tracked config after a failed replacement
lunaynx Nov 6, 2026
305f70f
fix: honor explicit ownership when replacing library configs
lunaynx Nov 6, 2026
5b9d588
fix: refresh the icon of a mod turned on after starting off
lunaynx Nov 6, 2026
0f3d4c1
fix: leave unrelated downloads alone when controlling a plan's
lunaynx Nov 6, 2026
3b0c72f
fix: stop a late config's preload overwriting saved values
lunaynx Nov 6, 2026
66360b1
fix: start profiles created while a mod is off from its defaults
lunaynx Nov 6, 2026
87ae329
fix: keep the older defaults backup when a replacement fails
lunaynx Nov 6, 2026
335ca0b
fix: let a config's explicit owner decide over its class's mod
lunaynx Nov 6, 2026
2fc9524
fix: keep a config with its mod when an update removes its class
lunaynx Nov 6, 2026
bf1c716
fix: note the owners of configs created after startup
lunaynx Nov 6, 2026
ea42d1f
fix: unregister the keybinds a scan actually registered
lunaynx Nov 6, 2026
6da975a
docs: note the limit of a plan's download controls
lunaynx Nov 6, 2026
27a217d
docs: update changelog
lunaynx Nov 6, 2026
698a2b0
fix: keep a defaults backup that could not be read
lunaynx Nov 6, 2026
9fa77fb
fix: hold back duplicate configs made while Hotwire starts a mod
lunaynx Nov 6, 2026
9c770fb
fix: leave compat trees alone while their mod is off
lunaynx Nov 6, 2026
c90a295
fix: note the owners of trees extracted under other ids
lunaynx Nov 6, 2026
8b49ffb
fix: hand configs over to the copies of live updates
lunaynx Nov 6, 2026
4e86a47
fix: let a config waiting for its window read its saved values
lunaynx Nov 6, 2026
dd0ea16
fix: recognize replacements built on an entrypoint's worker
lunaynx Nov 6, 2026
5cc77cf
fix: hold the saves of turned off mods until they are back
lunaynx Nov 6, 2026
f1a67b8
fix: leave directly registered trees alone while their mod is off
lunaynx Nov 6, 2026
3da6482
fix: drop extracted trees under the ids they were noted under
lunaynx Nov 6, 2026
8e48b2f
fix: release scanned trees once nothing else holds them
lunaynx Nov 6, 2026
4959169
fix: recognize updates running from relocated copies
lunaynx Nov 6, 2026
c3dd671
Merge branch 'v1' into hotwire-compat
lunaynx Nov 6, 2026
52aa224
docs: update changelog
lunaynx Nov 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
## 1.6.2
- Fix emoji rendering
- Fix rare Vulkan crash
- Add an API for detecting when HUDs are moved externally
- Fix FPS regression with 3DSkinLayers
- Fix FPS regression with HUDs
- Dropped compatibility with Hypixel SkyBlock mods (Apec, Firmament, Odin, Skyblocker, SkyHanni and other MoulConfig-based mods) on Minecraft versions below 26.1, which can no longer be used to play SkyBlock
## Unreleased changes
- Added integration with the Hotwire mod (0.7.3 and above) for turning mods on and off, updating them and adding new ones without restarting the game

### For mod developers
- Added `ModInfo.parentId`, `ModInfo.seenMods` and `ModInfo.refreshLoadedMods()`, along with a `ModInfo` constructor that takes the parent mod's ID
- `ConfigEntrypoint`s now also run for mods added or updated via Hotwire while the game is running
5 changes: 5 additions & 0 deletions buildSrc/src/main/kotlin/oneconfig-setup.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.gradle.api.publish.PublishingExtension
import org.gradle.authentication.http.BasicAuthentication
import org.gradle.plugins.signing.SigningExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import gg.essential.gradle.util.RelocationTransform.Companion.registerRelocationAttribute
import gg.essential.gradle.util.prebundle
import java.lang.Boolean.TRUE
Expand Down Expand Up @@ -358,6 +359,10 @@ if (enableMoulRelocatorKsp) {
tasks.matching { it.name.startsWith("ksp") }.configureEach {
enabled = false
}
// the ksp plugin still registers its output dir, so stale output from builds where ksp ran would compile
val kspOutput = layout.buildDirectory.dir("generated/ksp").get().asFile
tasks.withType<KotlinCompile>().configureEach { exclude { it.file.startsWith(kspOutput) } }
tasks.withType<JavaCompile>().configureEach { exclude { it.file.startsWith(kspOutput) } }
}

group = rootProject.group
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package org.polyfrost.oneconfig.api.platform.v1.internal;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.metadata.CustomValue;
import net.fabricmc.loader.api.metadata.ModMetadata;
import net.kyori.adventure.text.Component;
import net.minecraft.client.Minecraft;
import org.polyfrost.oneconfig.api.platform.v1.CompatibilityPlatform;
Expand All @@ -25,6 +29,11 @@
public class CompatibilityPlatformImpl implements CompatibilityPlatform {
Options options = new OptionsImpl();
Keys keys = new KeysImpl();
//? fabric || ornithe {
// compat asks for the mods on every lookup, and building them reads all their metadata
private List<ModContainer> modsFrom = List.of();
private Set<ModInfo> mods = Set.of();
//? }

@Override
public void displayChatMessage(Component text) {
Expand All @@ -44,32 +53,62 @@ public void displayChatMessage(Component text) {
public Set<ModInfo> getMods() {
//? fabric || ornithe {

return FabricLoader.getInstance().getAllMods().stream()
.map(mod -> {
var metadata = mod.getMetadata();
return new ModInfo(
metadata.getId(),
metadata.getName(),
metadata.getVersion().getFriendlyString(),
mod.getRootPaths().getFirst(),
metadata.getIconPath(Integer.MAX_VALUE).orElse(null),
metadata.getAuthors().stream()
.map(person -> person.getName())
.filter(name -> !name.isBlank())
.collect(Collectors.joining(", ")),
metadata.getContributors().stream()
.map(person -> person.getName())
.filter(name -> !name.isBlank())
.collect(Collectors.joining(", ")),
metadata.getDescription()
);
}).collect(Collectors.toSet());
FabricLoader loader = FabricLoader.getInstance();
synchronized (loader) {
List<ModContainer> containers = List.copyOf(loader.getAllMods());
if (containers.equals(modsFrom)) return mods;
mods = containers.stream()
.map(mod -> {
var metadata = mod.getMetadata();
return new ModInfo(
metadata.getId(),
metadata.getName(),
metadata.getVersion().getFriendlyString(),
mod.getRootPaths().getFirst(),
metadata.getIconPath(Integer.MAX_VALUE).orElse(null),
metadata.getAuthors().stream()
.map(person -> person.getName())
.filter(name -> !name.isBlank())
.collect(Collectors.joining(", ")),
metadata.getContributors().stream()
.map(person -> person.getName())
.filter(name -> !name.isBlank())
.collect(Collectors.joining(", ")),
metadata.getDescription(),
mod.getContainingMod().map(parent -> parent.getMetadata().getId()).orElseGet(() -> modMenuParent(metadata))
);
}).collect(Collectors.toSet());
modsFrom = containers;
return mods;
}
//? }

//? neoforge {
//? }
}

//? fabric || ornithe {
/** The parent Mod Menu lists a separately shipped mod under: its "parent" custom value, a bare id or an object with an id, or Fabric API for its modules */
private static String modMenuParent(ModMetadata metadata) {
try {
CustomValue parent = metadata.containsCustomValue("modmenu")
? metadata.getCustomValue("modmenu").getAsObject().get("parent")
: null;
if (parent != null && parent.getType() == CustomValue.CvType.OBJECT) parent = parent.getAsObject().get("id");
if (parent != null && parent.getType() == CustomValue.CvType.STRING) return parent.getAsString();
} catch (ClassCastException ignored) {
// malformed metadata from another mod should not break the mod list
}
// Mod Menu files Fabric API modules under Fabric API itself even when they ship as separate jars
if (metadata.containsCustomValue("fabric-api:module-lifecycle")) {
FabricLoader loader = FabricLoader.getInstance();
String parent = loader.isModLoaded("fabric-api") || !loader.isModLoaded("fabric") ? "fabric-api" : "fabric";
return parent.equals(metadata.getId()) ? null : parent;
}
return null;
}
//? }

@Override
public boolean isDevelopment() {
return FabricLoader.getInstance().isDevelopmentEnvironment();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.polyfrost.oneconfig.api.event.v1.events.ResourceFinishedLoading;
import org.polyfrost.oneconfig.api.event.v1.events.ScreenOpenEvent;
import org.polyfrost.oneconfig.api.event.v1.events.ShutdownEvent;
import org.polyfrost.oneconfig.api.event.v1.events.TickEvent;
import org.polyfrost.oneconfig.api.event.v1.events.WorldEvent;
import org.polyfrost.oneconfig.api.hud.v1.HudManager;
import org.polyfrost.oneconfig.api.hud.v1.events.HudEditorToggleEvent;
Expand Down Expand Up @@ -349,6 +350,7 @@ private static void registerEventHandlers() {
WWaypointsCompat.register();
ThemeRegistry.INSTANCE.loadFromConfig();
});
EventManager.register(TickEvent.End.class, ConfigEntrypoints::registerAdded);
EventManager.register(WorldEvent.Load.class, e -> {
showFirstLaunchNotification();
ItemCatalog.INSTANCE.markIconsAvailable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ public List<String> getMixins() {
mixins.add("compat.skyhanni.Mixin_SkyHanniRenderData");
mixins.add("compat.firmament.Mixin_FirmamentHudMeta");
//?}
// the tick listener can run too late on every version Hotwire supports, as a world can open before the next tick
//? if > 1.8.9
mixins.add("compat.Mixin_RegisterAddedConfigs");
// Firmament has no stable release for 26.2 yet
//? skyblock && < 26.2
//mixins.add("compat.firmament.Mixin_FirmamentContentCapture");
Expand Down
Loading
Loading