Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fbd43d9
chore: also cleanup TickThrottled entities on LegacyCleanup
KabanFriends Mar 3, 2026
4a171b2
feat: use official Hytale API for ActiveChunkUnloader with configurab…
Xytronix Mar 25, 2026
0eab048
fix: edge case in AiTickThrottler legacycleanup and added exclusion s…
Xytronix Mar 25, 2026
c8633b0
fix: replace per-block logging with summary and iterate by section sk…
Xytronix Mar 25, 2026
571975c
fix: authentication check logic during external auth (#19)
Xytronix Mar 25, 2026
850b030
feat: hytale update 4 (#21)
KabanFriends Mar 26, 2026
de87680
chore: bump mod version (0.3.0)
KabanFriends Mar 26, 2026
df4e031
feat: pre-release bundle (compat, mixin gating, crashfixes, AiThrottl…
Xytronix May 7, 2026
b6adf97
fix: persist rotated OAuth refresh tokens
Xytronix May 8, 2026
17500de
feat: surface /pedit roots in prefab list (Server, WorldGen, AssetRoot)
Xytronix May 9, 2026
dfb7768
feat: pin prefab list to top level and unify hooks under @WrapMethod
Xytronix May 9, 2026
3e5d11e
feat: gate prefab-list extra roots under Mixins.Helpers.PrefabListExt…
Xytronix May 9, 2026
34922f5
fix: cap WatchdogService auto-restart retries and skip removeWorld wh…
Xytronix May 9, 2026
85f3e7b
fix: catch ChunkLightData octree overflow and write neutral chain fal…
Xytronix May 12, 2026
3c3748a
feat: add /copychunks and /pastechunks for chunk-blob clipboard (Phas…
Xytronix May 12, 2026
47ab0aa
fix: declare MixinBuilderToolsPlugin#getCommandRegistry shadow as pub…
Xytronix May 12, 2026
624a2a7
feat: phase 1.5+2+3 - force-unload chunks, world= arg, --here mode fo…
Xytronix May 12, 2026
f16d40a
fix: drain in-flight chunk saves via SAVE_RESOURCE.waitForSavingChunk…
Xytronix May 12, 2026
ba40fcd
style: drop comments from copychunks files
Xytronix May 12, 2026
79104be
fix: cast to PluginBase for getCommandRegistry instead of @Shadow (Mi…
Xytronix May 12, 2026
c2b3ea0
refactor: move /copychunks and /pastechunks from early mixin to plugi…
Xytronix May 12, 2026
f4a2a3b
fix: --here mode honors /pos1 specifically via reflection on BuilderS…
Xytronix May 12, 2026
d443b73
fix: harden chunk light saves and version range
Xytronix May 14, 2026
70bcd68
build: use semver server version for manifests
Xytronix May 14, 2026
dda6b01
fix: handle legacy semver crash and auth executor shutdown
Xytronix May 17, 2026
8b2986f
fix(MixinTeleportToPlayerCommand): guard against mid-lambda ref inval…
Xytronix May 18, 2026
22288b1
fix(MixinPageManager): swallow IllegalArgumentException on unexpected…
Xytronix May 22, 2026
226dfa4
fix: suppress watchdog auto-restart on manual world removal; skip voi…
Xytronix May 22, 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
2 changes: 1 addition & 1 deletion build-logic/src/main/kotlin/java.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ repositories {

tasks {
processResources {
val hytaleVersion = libs.findVersion("hytale").get().toString()
val hytaleVersion = rootProject.property("hytale_server_version") as String

inputs.property("version", version)
inputs.property("hytaleVersion", hytaleVersion)
Expand Down
50 changes: 49 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
/* Project Properties */
val modGroup = project.property("mod_group") as String
val modVersion = project.property("mod_version") as String
val hytaleServerVersion = project.property("hytale_server_version") as String

allprojects {
group = modGroup
Expand All @@ -14,10 +15,13 @@ allprojects {
tasks {
register<Delete>("cleanBundle") {
delete(layout.buildDirectory.dir("bundle"))
delete(layout.buildDirectory.dir("singlejar"))
}

register<Copy>("copyBundleManifest") {
dependsOn("cleanBundle")
inputs.property("version", modVersion)
inputs.property("hytaleVersion", hytaleServerVersion)
from("bundle") {
include(
"manifest.json",
Expand All @@ -28,7 +32,7 @@ tasks {
into(layout.buildDirectory.dir("bundle"))
expand(
"version" to modVersion,
"hytaleVersion" to libs.versions.hytale.get()
"hytaleVersion" to hytaleServerVersion
)
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
Expand All @@ -53,4 +57,48 @@ tasks {
destinationDirectory.set(file("bundle"))
from(layout.buildDirectory.dir("bundle"))
}

// Hyinit single-jar: one archive containing both Main plugin classes and Mixin
// configs, declared via `manifest-singlejar.json` (Main + Mixins). Drops in
// `earlyplugins/` and Hyinit auto-discovers both the runtime plugin and Mixins.
register<Copy>("copySingleJarManifest") {
dependsOn("cleanBundle")
inputs.property("modVersion", modVersion)
inputs.property("hytaleVersion", hytaleServerVersion)
from("bundle") {
include("manifest-singlejar.json")
rename("manifest-singlejar.json", "manifest.json")
}
into(layout.buildDirectory.dir("singlejar"))
expand(
"modVersion" to modVersion,
"hytaleVersion" to hytaleServerVersion
)
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

register<Jar>("singleJar") {
val earlyShadow = project(":early").tasks.named<Jar>("shadowJar")
val pluginShadow = project(":plugin").tasks.named<Jar>("shadowJar")
dependsOn(
"copySingleJarManifest",
earlyShadow,
pluginShadow,
project(":early").tasks.named("jar"),
project(":plugin").tasks.named("jar"))
archiveFileName.set("${project.name}-${version}.jar")
destinationDirectory.set(layout.buildDirectory.dir("bundle"))
// Per-module manifest.json is dropped; the merged manifest from copySingleJarManifest
// is added last and wins via DuplicatesStrategy.EXCLUDE (first-source-wins).
from(layout.buildDirectory.dir("singlejar")) {
include("manifest.json")
}
from(earlyShadow.flatMap { it.archiveFile }.map { zipTree(it) }) {
exclude("manifest.json", "META-INF/MANIFEST.MF")
}
from(pluginShadow.flatMap { it.archiveFile }.map { zipTree(it) }) {
exclude("manifest.json", "META-INF/MANIFEST.MF")
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
20 changes: 20 additions & 0 deletions bundle/manifest-singlejar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"Group": "IroriPowered",
"Name": "Refixes",
"Version": "${modVersion}",
"Website": "https://www.irori.cc/",
"Description": "Patches and optimizations for Hytale server (single-jar build).",
"Main": "cc.irori.refixes.Refixes",
"Authors": [
{
"Name": "KabanFriends",
"Url": "https://github.com/KabanFriends"
}
],
"ServerVersion": ">=${hytaleVersion}",
"Dependencies": {},
"OptionalDependencies": {},
"Mixins": [
"refixes.mixins.json"
]
}
2 changes: 1 addition & 1 deletion bundle/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"Url": "https://github.com/KabanFriends"
}
],
"ServerVersion": "${hytaleVersion}",
"ServerVersion": ">=${hytaleVersion}",
"Dependencies": {},
"OptionalDependencies": {},
"SubPlugins": {
Expand Down
60 changes: 28 additions & 32 deletions early/src/main/java/cc/irori/refixes/early/EarlyOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,37 @@ public final class EarlyOptions {
private static boolean available = false;

/* Force Skip Mod Validation */
public static final Value<Boolean> FORCE_SKIP_MOD_VALIDATION = new Value<>();

/* Fluid Pre-processing */
public static final Value<Boolean> DISABLE_FLUID_PRE_PROCESS = new Value<>();

/* Block Pre-processing */
public static final Value<Boolean> ASYNC_BLOCK_PRE_PROCESS = new Value<>();
public static final Value<Boolean> FORCE_SKIP_MOD_VALIDATION = new Value<>(false);

/* Cylinder Visibility */
public static final Value<Boolean> CYLINDER_VISIBILITY_ENABLED = new Value<>();
public static final Value<Double> CYLINDER_VISIBILITY_HEIGHT_MULTIPLIER = new Value<>();

/* Parallel Entity Ticking */
public static final Value<Boolean> PARALLEL_ENTITY_TICKING = new Value<>();
public static final Value<Double> CYLINDER_VISIBILITY_HEIGHT_MULTIPLIER = new Value<>(2.0);

/* ChunkTracker Rate Limits */
public static final Value<Integer> MAX_CHUNKS_PER_SECOND = new Value<>();
public static final Value<Integer> MAX_CHUNKS_PER_TICK = new Value<>();
public static final Value<Integer> MAX_CHUNKS_PER_SECOND = new Value<>(36);
public static final Value<Integer> MAX_CHUNKS_PER_TICK = new Value<>(4);
public static final Value<Integer> CHUNK_UNLOAD_OFFSET = new Value<>(4);
public static final Value<Boolean> VANILLA_KEEP_SPAWN_LOADED = new Value<>(true);

/* KDTree Optimization */
public static final Value<Boolean> KDTREE_OPTIMIZATION_OPTIMIZE_SORT = new Value<>();
public static final Value<Integer> KDTREE_OPTIMIZATION_THRESHOLD = new Value<>();
public static final Value<Integer> KDTREE_OPTIMIZATION_THRESHOLD = new Value<>(64);

/* Shared Instances */
public static final Value<Boolean> SHARED_INSTANCES_ENABLED = new Value<>();
public static final Value<String[]> SHARED_INSTANCES_EXCLUDED_PREFIXES = new Value<>();
public static final Value<String[]> SHARED_INSTANCES_EXCLUDED_PREFIXES = new Value<>(new String[0]);

/* Block Entity Sleep */
public static final Value<Boolean> BLOCK_ENTITY_SLEEP_ENABLED = new Value<>();
public static final Value<Integer> BLOCK_ENTITY_SLEEP_INTERVAL = new Value<>();
public static final Value<Integer> BLOCK_ENTITY_SLEEP_INTERVAL = new Value<>(4);

/* Stat Recalculation Throttle */
public static final Value<Boolean> STAT_RECALC_THROTTLE_ENABLED = new Value<>();
public static final Value<Integer> STAT_RECALC_INTERVAL = new Value<>();
public static final Value<Integer> STAT_RECALC_INTERVAL = new Value<>(4);

/* Block Section Cache */
public static final Value<Boolean> SECTION_CACHE_ENABLED = new Value<>();
/* Pathfinding */
public static final Value<Integer> PATHFINDING_MAX_PATH_LENGTH = new Value<>(200);
public static final Value<Integer> PATHFINDING_OPEN_NODES_LIMIT = new Value<>(80);
public static final Value<Integer> PATHFINDING_TOTAL_NODES_LIMIT = new Value<>(400);

/* Skip Empty Light Sections */
public static final Value<Boolean> SKIP_EMPTY_LIGHT_SECTIONS = new Value<>();
/* Parallel Steering Threshold */
public static final Value<Integer> PARALLEL_STEERING_THRESHOLD = new Value<>(64);

// Private constructor to prevent instantiation
private EarlyOptions() {}

public static void setAvailable(boolean available) {
Expand All @@ -61,19 +50,26 @@ public static boolean isAvailable() {

public static final class Value<T> {

private final T defaultValue;
private Supplier<T> supplier = null;

private Value() {}
private Value(T defaultValue) {
this.defaultValue = defaultValue;
}

public void setSupplier(Supplier<T> supplier) {
this.supplier = supplier;
}

public boolean isSet() {
return supplier != null;
}

// Falls back to the default when no supplier was wired (e.g. classloader split
// between the early and main plugin halves means the main plugin's setSupplier
// wrote to a different copy of this class).
public T get() {
if (supplier == null) {
throw new IllegalStateException("Value supplier has not been set");
}
return supplier.get();
return supplier != null ? supplier.get() : defaultValue;
}
}
}
Loading