Skip to content

Commit 673a8ee

Browse files
committed
Add initial Hypertale Plus support!
1 parent c27da3e commit 673a8ee

16 files changed

Lines changed: 146 additions & 9 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This mod improves performance and reduces memory pressure on the Hytale server!
1515
Memory pressure is how much memory is allocated per second.
1616
When high, this makes the java garbage collector slow the server down a lot!
1717

18-
Used spark a lot to help with performance profiling.
18+
Spark was used extensively a lot to help with performance profiling.
1919

2020
Hypertale should be compatible with existing performance mods for Hytale!
2121

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ org.gradle.parallel=true
44
org.gradle.jvmargs=-Xmx1024m -XX:-UseGCOverheadLimit -Dfile.encoding=UTF-8
55
org.gradle.java.installations.auto-download=true
66
# Hypertale properties
7-
hypertale.version=0.0.7
7+
hypertale.version=1.0.0-dev
88
hypertale.init=1
99

1010
# https://plugins.gradle.org/plugin/net.ltgt.errorprone

launcher/src/main/java/com/fox2code/hypertale/commands/HypertalePyroCommand.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ final class HypertalePyroCommand extends AbstractCommand {
5454
protected @Nullable CompletableFuture<Void> execute(@NonNull CommandContext commandContext) {
5555
if (commandContext.isPlayer()) {
5656
commandContext.sendMessage(PYRO_MESSAGE);
57+
} else {
58+
commandContext.sendMessage(PYRO_MESSAGE_ALT);
5759
}
5860
return null;
5961
}

launcher/src/main/java/com/fox2code/hypertale/commands/HypertaleVersionCommand.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636

3737
final class HypertaleVersionCommand extends AbstractCommand {
3838
static final Message VERSION_MESSAGE = Message.join(HypertalePlugin.HYPERTALE,
39-
Message.raw(": Hypertale version -> " + BuildConfig.HYPERTALE_VERSION));
39+
Message.raw(": Hypertale version -> " + BuildConfig.HYPERTALE_VERSION +
40+
" (" + HypertalePlugin.EDITION + ")"));
4041

4142
HypertaleVersionCommand() {
4243
super("version", "Show Hypertale version!");

launcher/src/main/java/com/fox2code/hypertale/launcher/HypertaleAgent.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,8 @@ static void tryLoadEarlyAgent() {
6464
.getMethod("getInstrumentation").invoke(null);
6565
} catch (Exception _) {}
6666
}
67+
if (instrumentation == null) {
68+
instrumentation = MainPlus.tryGetInstrumentationFallback();
69+
}
6770
}
6871
}

launcher/src/main/java/com/fox2code/hypertale/launcher/Main.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static void main(String[] args) throws IOException, InterruptedException {
6565
} else if (!Boolean.getBoolean("hypertale.useInitWrapper")) {
6666
System.setProperty("hypertale.initMethod", "direct");
6767
}
68+
MainPlus.setEditionProperties();
6869
if (args.length == 0 && !isRunningFromTerminal()) {
6970
// Avoid running a server from a double click.
7071
System.out.println("[Hypertale] File double click detected! Skipping running!");
@@ -164,6 +165,14 @@ static void main(String[] args) throws IOException, InterruptedException {
164165
EarlyLogger.log("Version " + BuildConfig.HYPERTALE_VERSION);
165166
launchGame(EmptyArrays.EMPTY_STRING_ARRAY, true);
166167
return;
168+
} else if (args.length == 1 && "--patch-class-path".equals(args[0])) {
169+
if (Boolean.getBoolean("hypertale.premium")) {
170+
EarlyLogger.start(false);
171+
MainPlus.patchAsClassPath();
172+
} else {
173+
System.out.println("This feature is only available on premium builds of Hypertale!");
174+
}
175+
return;
167176
}
168177
EarlyLogger.start(false);
169178
EarlyLogger.log("Version " + BuildConfig.HYPERTALE_VERSION);
@@ -201,6 +210,12 @@ static void main(String[] args) throws IOException, InterruptedException {
201210
if (args.length == 1 && "--noop".equals(args[0])) {
202211
return;
203212
}
213+
if (HypertaleConfig.hyperOptimizeClassPath()) {
214+
MainPlus.launchPatchedAsClassPath(args);
215+
return;
216+
} else if (HypertaleConfig.premiumHyperOptimizeClassPath) {
217+
EarlyLogger.log("HyperOptimizeClassPath is only supported on premium builds of Hypertale!");
218+
}
204219
try {
205220
launchGame(args, false);
206221
} catch (LinkageError e) {
@@ -263,6 +278,15 @@ private static void launchGame(String[] args, boolean dev) throws IOException {
263278

264279
private static void runPatcher(HypertaleData actualData) throws IOException, InterruptedException {
265280
EarlyLogger.log("Patching HytaleServer...");
281+
execSelf("--run-patcher");
282+
actualData.modifiedJarSize = HypertalePaths.hypertaleCacheJar.length();
283+
actualData.writeTo(HypertalePaths.hypertaleCacheData);
284+
}
285+
286+
public static void execSelf(String arg) throws IOException, InterruptedException {
287+
if (!EarlyLogger.isDirectLogging()) {
288+
throw new IllegalStateException("Invalid state!");
289+
}
266290
EarlyLogger.stop();
267291
ArrayList<String> command = new ArrayList<>();
268292
if (System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("win")) {
@@ -272,14 +296,12 @@ private static void runPatcher(HypertaleData actualData) throws IOException, Int
272296
}
273297
command.add("-jar");
274298
command.add(HypertalePaths.getHypertaleExecJar().getAbsolutePath());
275-
command.add("--run-patcher");
299+
command.add(arg);
276300
int returnCode = new ProcessBuilder(command).inheritIO().start().waitFor();
277301
if (returnCode != 0 || !HypertalePaths.hypertaleCacheJar.exists()) {
278302
throw new IOException("Patch failed with return code is " + returnCode);
279303
}
280304
EarlyLogger.start(true);
281-
actualData.modifiedJarSize = HypertalePaths.hypertaleCacheJar.length();
282-
actualData.writeTo(HypertalePaths.hypertaleCacheData);
283305
}
284306

285307
// https://errorprone.info/bugpattern/SystemConsoleNull
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2026 Fox2Code
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package com.fox2code.hypertale.launcher;
25+
26+
import java.io.IOException;
27+
import java.lang.instrument.Instrumentation;
28+
29+
/**
30+
* This class is overwritten by Hypertale Plus
31+
*/
32+
final class MainPlus {
33+
static void setEditionProperties() {
34+
System.setProperty("hypertale.edition", "OSS");
35+
System.setProperty("hypertale.premium", "false");
36+
}
37+
38+
static Instrumentation tryGetInstrumentationFallback() {
39+
return null;
40+
}
41+
42+
@SuppressWarnings("DoNotCallSuggester")
43+
static void patchAsClassPath() throws IOException {
44+
throw new IOException("Only premium versions of Hypertale can use this feature!");
45+
}
46+
47+
@SuppressWarnings("DoNotCallSuggester")
48+
static void launchPatchedAsClassPath(String[] args) throws IOException {
49+
throw new IOException("Only premium versions of Hypertale can use this feature!");
50+
}
51+
}

launcher/src/main/java/com/fox2code/hypertale/launcher/PatchHelper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,18 @@
3636
import java.util.function.Consumer;
3737

3838
final class PatchHelper {
39+
private static boolean installed = false;
40+
41+
private PatchHelper() {}
42+
3943
@SuppressWarnings("unchecked")
4044
private static final Consumer<BiFunction<String, byte[], byte[]>> initCLSetClassTransformer =
4145
(Consumer<BiFunction<String, byte[], byte[]>>)
4246
System.getProperties().get("hypertale.initCLSetClassTransformer");
4347

4448
static void install() {
49+
if (installed) return;
50+
installed = true;
4551
Instrumentation instrumentation = HypertaleAgent.getInstrumentation();
4652
if (instrumentation != null) {
4753
EarlyLogger.log("Using agent transformer for patching!");

launcher/src/main/java/com/fox2code/hypertale/loader/HypertaleModLoader.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ public static void loadHypertaleMods(
7575
HypertaleModGatherer modGatherer, boolean libraries,
7676
LinkedHashMap<File, JsonObject> loadedModsEarly) throws IOException {
7777
for (File file : (libraries ? modGatherer.getLibraries() : modGatherer.getHypertaleMods())) {
78+
if (loadedModsEarly.containsKey(file)) {
79+
continue;
80+
}
7881
try (JarFile jarFile = new JarFile(file)) {
7982
JarEntry hypertaleModInfo = jarFile.getJarEntry("manifest.json");
8083
if (hypertaleModInfo == null) continue;

launcher/src/main/java/com/fox2code/hypertale/loader/HypertalePlugin.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import java.util.Objects;
4545

4646
public final class HypertalePlugin extends JavaPlugin {
47+
public static final String EDITION = System.getProperty("hypertale.edition", "OSS");
48+
public static final boolean PREMIUM = Boolean.getBoolean("hypertale.premium");
4749
private static final boolean INVALID_INSTALLATION =
4850
HypertalePlugin.class.getClassLoader() != JavaPlugin.class.getClassLoader();
4951
private static final boolean USE_HYPERTALE_INIT = Boolean.getBoolean("hypertale.useInitWrapper");
@@ -88,6 +90,9 @@ protected void start() {
8890
if (INVALID_INSTALLATION) return;
8991
HypertaleModLoader.loadModsLate();
9092
this.getLogger().atInfo().log("Successfully loaded!");
93+
if (PREMIUM) {
94+
this.getLogger().atInfo().log("Thank you for supporting Hypertale!");
95+
}
9196
}
9297

9398
private void tryInstallHypertaleFromModFolder() throws IOException {

0 commit comments

Comments
 (0)