From 7ef7490c3710ff133a35ce3dea6c5f7af77431dd Mon Sep 17 00:00:00 2001 From: Melledy <121644117+Melledy@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:08:38 -0800 Subject: [PATCH] Support JP and TW clients --- README.md | 35 +++++++++------- src/main/java/emu/nebula/GameConstants.java | 28 +++++++++++-- src/main/java/emu/nebula/Nebula.java | 6 ++- src/main/java/emu/nebula/RegionConfig.java | 42 +++++++++++++++++++ src/main/java/emu/nebula/util/AeadHelper.java | 41 +++++++++--------- 5 files changed, 113 insertions(+), 39 deletions(-) create mode 100644 src/main/java/emu/nebula/RegionConfig.java diff --git a/README.md b/README.md index 2a8b60c..a430334 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,14 @@ For any extra support, questions, or discussions, check out our [Discord](https: ### Not implemented - Events +### Supported regions + +Nebula supports the global PC client by default. If you want to switch regions, you need to change the `region` field in the Nebula config. + +Current supported regions (PC): `GLOBAL`, `KR`, `JP`, `TW` + +You may need to change the data version when switching regions. The `customDataVersion` field should match the the data version of your client, which is usually the last number of your client's version string (top left of your login screen). Example: 1.0.0.42 = data version 42. + # Running the server and client ### Prerequisites @@ -49,17 +57,24 @@ For any extra support, questions, or discussions, check out our [Discord](https: 3. Copy and paste the following code into the Fiddlerscript tab of Fiddler Classic. Remember to save the fiddler script after you copy and paste it: ``` -import System; -import System.Windows.Forms; import Fiddler; -import System.Text.RegularExpressions; class Handlers { + static var list = [ + ".yostarplat.com", + ".stellasora.global", + ".stellasora.kr", + ".stellasora.jp", + ".stargazer-games.com" + ]; + static function OnBeforeRequest(oS: Session) { - if (oS.host.EndsWith(".yostarplat.com") || oS.host.EndsWith(".stellasora.global")) { - oS.oRequest.headers.UriScheme = "http"; - oS.host = "localhost"; // This can also be replaced with another IP address. + for (var i = 0; i < list.length; i++) { + if (oS.host.EndsWith(list[i])) { + oS.oRequest.headers.UriScheme = "http"; + oS.host = "localhost"; // This can also be replaced with another IP address + } } } }; @@ -68,14 +83,6 @@ class Handlers 4. If `autoCreateAccount` is set to true in the config, then you can skip this step. Otherwise, type `/account create [account email]` in the server console to create an account. 5. Login with your account email, the code field is ignored by the server and can be set to anything. -If you are not on the global client, `.stellasora.global` in the fiddlerscript may need to be changed to match the endpoint your client connects to. - -### Supported regions - -Nebula supports the global client by default. If you want to switch regions, you need to change the `customDataVersion` and `region` fields in the Nebula config. The `customDataVersion` field should match the the data version of your client, which is usually the last number of your client's version string (top left of your login screen). Example: 1.0.0.42 = data version 42. - -Current supported regions: `global`, `kr` - ### Server commands Server commands need to be run in the server console OR in the signature edit menu of your profile. diff --git a/src/main/java/emu/nebula/GameConstants.java b/src/main/java/emu/nebula/GameConstants.java index f0efca7..3e630b0 100644 --- a/src/main/java/emu/nebula/GameConstants.java +++ b/src/main/java/emu/nebula/GameConstants.java @@ -6,8 +6,23 @@ import emu.nebula.game.inventory.ItemParam; import emu.nebula.util.WeightedList; public class GameConstants { - private static final int DATA_VERSION = 60; - private static final String VERSION = "1.2.0"; + public static final String VERSION = "1.2.0"; + public static int DATA_VERSION = 0; + + // Set data versions for each region + static { + RegionConfig.getRegion("global") + .setDataVersion(60); + + RegionConfig.getRegion("kr") + .setDataVersion(67); + + RegionConfig.getRegion("jp") + .setDataVersion(63); + + RegionConfig.getRegion("tw") + .setDataVersion(61); + } public static final ZoneId UTC_ZONE = ZoneId.of("UTC"); @@ -57,7 +72,14 @@ public class GameConstants { // Helper functions public static String getGameVersion() { - return VERSION + "." + getDataVersion() + " (" + Nebula.getConfig().getRegion().toUpperCase() + ")"; + // Load data version + var region = RegionConfig.getRegion(Nebula.getConfig().getRegion()); + + // Set data version from region + GameConstants.DATA_VERSION = region.getDataVersion(); + + // Init game version string + return VERSION + "." + getDataVersion() + " (" + region.getName().toUpperCase() + ")"; } public static int getDataVersion() { diff --git a/src/main/java/emu/nebula/Nebula.java b/src/main/java/emu/nebula/Nebula.java index 91f70d9..4eb0061 100644 --- a/src/main/java/emu/nebula/Nebula.java +++ b/src/main/java/emu/nebula/Nebula.java @@ -43,9 +43,8 @@ public class Nebula { @Getter private static PluginManager pluginManager; public static void main(String[] args) { - // Load config + keys first + // Load config first Nebula.loadConfig(); - AeadHelper.loadKeys(); // Start Server Nebula.getLogger().info("Starting Nebula " + getJarVersion()); @@ -54,6 +53,9 @@ public class Nebula { boolean generateHandbook = true; + // Load keys + AeadHelper.loadKeys(); + // Load plugin manager Nebula.pluginManager = new PluginManager(); diff --git a/src/main/java/emu/nebula/RegionConfig.java b/src/main/java/emu/nebula/RegionConfig.java new file mode 100644 index 0000000..ef944f1 --- /dev/null +++ b/src/main/java/emu/nebula/RegionConfig.java @@ -0,0 +1,42 @@ +package emu.nebula; + +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter +public class RegionConfig { + private String name; + private int dataVersion; + private String serverMetaKey; + private String serverGarbleKey; + + private static Object2ObjectMap REGIONS = new Object2ObjectOpenHashMap<>(); + + public RegionConfig(String name) { + this.name = name; + this.serverMetaKey = ""; + this.serverGarbleKey = ""; + } + + public RegionConfig setDataVersion(int i) { + this.dataVersion = i; + return this; + } + + public RegionConfig setServerMetaKey(String key) { + this.serverMetaKey = key; + return this; + } + + public RegionConfig setServerGarbleKey(String key) { + this.serverGarbleKey = key; + return this; + } + + public static RegionConfig getRegion(String name) { + String regionName = name.toLowerCase(); + return REGIONS.computeIfAbsent(regionName, r -> new RegionConfig(regionName)); + } +} diff --git a/src/main/java/emu/nebula/util/AeadHelper.java b/src/main/java/emu/nebula/util/AeadHelper.java index 813d8b1..089bfaf 100644 --- a/src/main/java/emu/nebula/util/AeadHelper.java +++ b/src/main/java/emu/nebula/util/AeadHelper.java @@ -19,8 +19,7 @@ import org.bouncycastle.crypto.generators.HKDFBytesGenerator; import org.bouncycastle.crypto.params.*; import emu.nebula.Nebula; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import emu.nebula.RegionConfig; // Official Name: AeadTool public class AeadHelper { @@ -34,29 +33,31 @@ public class AeadHelper { public static byte[] serverGarbleKey = null; public static byte[] serverMetaKey = null; - private static final Object2ObjectMap keys = new Object2ObjectOpenHashMap<>(); + static { + RegionConfig.getRegion("global") + .setServerMetaKey("ma5Dn2FhC*Xhxy%c") + .setServerGarbleKey("xNdVF^XTa6T3HCUATMQ@sKMLzAw&%L!3"); + + RegionConfig.getRegion("kr") + .setServerMetaKey("U9cjHuwGDDx&$drn") + .setServerGarbleKey("25hdume9H#*6hHn@d9hSF7tekTwN#JYj"); + + RegionConfig.getRegion("jp") + .setServerMetaKey("ZnUFA@S9%4KyoryM") + .setServerGarbleKey("yX5Gt64PVvVH6$qwBXaPJC*LZKoK5mYh"); + + RegionConfig.getRegion("tw") + .setServerMetaKey("owGYVDmfHrxi^4pm") + .setServerGarbleKey("N&mfco452ZH5!nE3s&o5uxB57UGPENVo"); + } public static void loadKeys() { - // Load keys - keys.put("global", new String[] { - "ma5Dn2FhC*Xhxy%c", - "xNdVF^XTa6T3HCUATMQ@sKMLzAw&%L!3" - }); - keys.put("kr", new String[] { - "U9cjHuwGDDx&$drn", - "25hdume9H#*6hHn@d9hSF7tekTwN#JYj" - }); - // Get key data - var keyData = keys.get(Nebula.getConfig().getRegion().toLowerCase()); - - if (keyData == null) { - keyData = keys.get("global"); // Default region - } + var region = RegionConfig.getRegion(Nebula.getConfig().getRegion()); // Set keys - serverMetaKey = keyData[0].getBytes(StandardCharsets.US_ASCII); - serverGarbleKey = keyData[1].getBytes(StandardCharsets.US_ASCII); + serverMetaKey = region.getServerMetaKey().getBytes(StandardCharsets.US_ASCII); + serverGarbleKey = region.getServerGarbleKey().getBytes(StandardCharsets.US_ASCII); } public static byte[] generateBytes(int size) {