Update readme

This commit is contained in:
Melledy committed 2026-10-20 23:11:24 -07:00
1 parent 3878d1ff38
commit fcdca4f701
22 files changed
+90 -50

No files matched your search

+28 -16
View File
@@ -37,7 +37,9 @@ Nebula supports the global PC client by default. If you want to switch regions,
Current supported regions (PC): `GLOBAL`, `KR`, `JP`, `TW`, `CN` Current supported regions (PC): `GLOBAL`, `KR`, `JP`, `TW`, `CN`
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. ### Updating
You may need to change the data version when switching regions OR if your game updates. The `customDataVersion` field in the config should match 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 # Running the server and client
@@ -101,19 +103,29 @@ class Handlers
5. Login with your account email, the code field is ignored by the server and can be set to anything. 5. Login with your account email, the code field is ignored by the server and can be set to anything.
### Server commands ### Server commands
Server commands need to be run in the server console OR in the signature edit menu of your profile.
``` Server commands can be run from the server console or from the signature edit menu of your profile. You can prefix a command with either `!` or `/`.
!account {create | delete} [email] (reserved player uid) = Creates or deletes an account.
!battlepass [free | premium] lv(level) = Modifies the targeted player's battle pass Commands that modify a player need a target: run them in-game, or append `@<uid>` to target a player from the console.
!char [all | {characterId}] lv(level) a(ascension) s(skill level) t(talent level) f(affinity level) = Changes the properties of the targeted characters.
!clean [all | {id} ...] [items|resources] = Removes items/resources from the targeted player. | Command | Aliases | Description |
!disc [all | {discId}] lv(level) a(ascension) c(crescendo level) = Changes the properties of the targeted discs. | --- | --- | --- |
!give [item id] x[amount] = Gives the targeted player an item through the mail. | `!account` | | Create an account (optionally reserving a player UID), delete an account, or list all accounts.<br>`!account create <email> [reserved uid]`<br>`!account delete <email>`<br>`!account list` |
!giveall [characters | discs | materials] = Gives the targeted player items. | `!arena` | `setarena` | Set the Menace Arena floor and level for a player, or clear their progress. Run without arguments to view progress. Requires a relog.<br>`!arena <element> <floor> <level> [@uid]`<br>`!arena clear`<br>Elements: `generic`, `ignis`, `ventus`, `lux`, `aqua`, `terra`, `umbra` (or `1`-`7`). |
!help = Displays a list of available commands. (Very spammy in-game) | `!autobuild` | `ab` | Generate a record for a player, auto-filling characters, discs, potentials, and sub-note skills to reach a target record level or score. Uses record level 40 if none is given.<br>`!autobuild [ids...] lv(level) s(score) [-nn] [-np]`<br>`-nn` skips sub-note skills and `-np` skips potentials. |
!level (level) = Sets the player level | `!ban` | | Ban a player or IP address.<br>`!ban {all \| ip \| uid} <uid \| ip> [end timestamp] [reason]`<br>`all` bans both the UID and its IP, `uid` only the UID, and `ip` only the IP. The end timestamp is in milliseconds; omit it for a permanent ban. |
!mail "subject" "body" [itemId xQty | itemId:qty ...] = Sends the targeted player a system mail. | `!battlepass` | `bp` | Set a player's battle pass mode and level (maximum level 50).<br>`!battlepass [free \| premium] lv(level)` |
!reload = Reloads the server config. | `!build` | `b`, `record`, `r` | Create a record from item IDs. Requires exactly 3 characters and 3-6 discs; potential levels can be set with `id:level`, and a preset code can be used instead of IDs.<br>`!build [character ids...] [disc ids...] [potential ids...] [sub-note skill ids...]` |
!remote = Creates a player token for remote api usage | `!character` | `c`, `char` | Change a character's level, ascension, skill, talent, and affinity.<br>`!character [all \| character ids...] lv(level) a(ascension) s(skill level) t(talent level) f(affinity level)`<br>`all` applies the changes to every owned character. |
``` | `!clean` | `cl`, `clear` | Remove items and/or resources from a player.<br>`!clean [all \| item ids...] [items \| resources]`<br>`all` removes everything; `items` or `resources` limits the cleanup to one type. |
| `!disc` | `d` | Change a disc's level, ascension, and crescendo level.<br>`!disc [all \| disc ids...] lv(level) a(ascension) c(crescendo level)`<br>`all` applies the changes to every owned disc. |
| `!emblem` | `e`, `gem` | Set the four attributes of an emblem in a character's emblem slot, creating or replacing the gem as needed.<br>`!emblem <character id> <emblem slot> <attr id> <attr id> <attr id> <attr id>` |
| `!give` | `g`, `item` | Send items to a player through the mail.<br>`!give <item ids...> x(amount)`<br>Defaults to 1 of each item. |
| `!giveall` | `ga` | Give a player all materials, discs, characters, or paid skins.<br>`!giveall [materials \| discs \| characters \| skins] lv(level) a(ascension) s(skill level) t(talent/crescendo level)`<br>Property values are applied to newly added characters and discs. |
| `!help` | | List every command available to you.<br>`!help`<br>This is very spammy in-game. |
| `!level` | `setlevel`, `l` | Set a player's level.<br>`!level <level>` |
| `!mail` | `m` | Send a system mail with optional attachments. The subject and body must be wrapped in quotes.<br>`!mail "subject" "body" [itemId xQty \| itemId:qty ...]` |
| `!reload` | | Reload the server config and the game patch list.<br>`!reload` |
| `!remote` | | Generate a remote API token for a player, or clear it when remote services are disabled.<br>`!remote` |
| `!status` | | Show server runtime status: uptime, CPU, memory, disk, and player count.<br>`!status [@uid]`<br>Add `@uid` to verify that a player is online. |
| `!unban` | | Unban a player or IP address.<br>`!unban {all \| ip \| uid} <uid \| ip>`<br>`all` unbans both the UID and its IP, `uid` only the UID, and `ip` only the IP. |
+2 -2
View File
@@ -158,8 +158,8 @@ public class Config {
@Getter @Getter
public static class RemoteCommand { public static class RemoteCommand {
public boolean useRemoteServices = false; public boolean useRemoteServices = false; // Turned off by default
public String serverAdminKey = "HJHASDPIIQWEASDHHAN"; public String serverAdminKey = "HJHASDPIIQWEASDHHAN"; // Please change the admin key before turning it on
} }
@Getter @Getter
@@ -6,7 +6,11 @@ import emu.nebula.command.CommandHandler;
import emu.nebula.game.account.AccountHelper; import emu.nebula.game.account.AccountHelper;
import emu.nebula.util.Utils; import emu.nebula.util.Utils;
@Command(label = "account", permission = "admin.account", desc = "!account {create | delete} [email] (reserved player uid). Creates or deletes an account.") @Command(
label = "account",
permission = "admin.account",
desc = "!account create [email] (reserved player uid) | !account delete [email] | !account list = Creates an account, deletes an account, or lists all accounts."
)
public class AccountCommand implements CommandHandler { public class AccountCommand implements CommandHandler {
@Override @Override
@@ -8,7 +8,13 @@ import emu.nebula.data.GameData;
import emu.nebula.data.resources.InfinityTowerLevelDef; import emu.nebula.data.resources.InfinityTowerLevelDef;
import emu.nebula.util.Utils; import emu.nebula.util.Utils;
@Command(label = "arena", aliases = {"setarena"}, permission = "player.arena", requireTarget = false, desc = "!arena [element] [floor] [level] [@id] | !arena clear = Set menace arena progress") @Command(
label = "arena",
aliases = {"setarena"},
permission = "player.arena",
requireTarget = false,
desc = "!arena [element] [floor] [level] [@uid] | !arena clear = Sets the Menace Arena floor and level for the targeted player, or clears their progress. Elements: generic, ignis, ventus, lux, aqua, terra, umbra (or 1-7). Run without args to view progress. Requires a relog."
)
public class ArenaCommand implements CommandHandler { public class ArenaCommand implements CommandHandler {
private static final String RELOG_HINT = " Restart the game to see the change."; private static final String RELOG_HINT = " Restart the game to see the change.";
@@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
aliases = {"ab"}, aliases = {"ab"},
permission = "player.build", permission = "player.build",
requireTarget = true, requireTarget = true,
desc = "!autobuild [character/disc/potential/melody ids...] lv[target record level] s[target record score] = Generates a record for the player with the target score/record level" desc = "!autobuild [character/disc/potential/sub-note skill ids...] lv(record level) s(record score) [-nn] [-np] = Generates a record for the targeted player, auto-filling random characters, discs, potentials, and sub-note skills to reach the target record level (default 40) or score. -nn skips sub-note skills and -np skips potentials."
) )
public class AutoBuildCommand implements CommandHandler { public class AutoBuildCommand implements CommandHandler {
private static final int[] COMMON_SUB_NOTE_SKILLS = new int[] { private static final int[] COMMON_SUB_NOTE_SKILLS = new int[] {
@@ -12,13 +12,11 @@ import java.util.Locale;
@Command(label = "ban", @Command(label = "ban",
permission = "admin.ban", permission = "admin.ban",
desc = """ desc = """
!ban {all | ip | uid} [player uid | ip] (end timestamp) (reason) - Ban a player\ !ban {all | ip | uid} [player uid | ip] (end timestamp in ms) (reason) = Bans a player or IP address.
- all bans both the player and their IP by UID, so use a UID as the second argument
- all mode bans both the player object and their IP address by UID, so the next parameter should be UID instead of IP - uid bans only the UID, so use a UID as the second argument
- ip mode can only ban IP addresses, so the next parameter should be an IP - ip bans only the IP address, so use an IP as the second argument
- uid mode can only ban UIDs, so the next parameter should be a UID - Omit the end timestamp for a permanent ban""")
- If you don't fill in the end timestamp, it will be permanently banned by default\
""")
public class BanCommand implements CommandHandler { public class BanCommand implements CommandHandler {
@Override @Override
@@ -5,7 +5,12 @@ import emu.nebula.command.CommandArgs;
import emu.nebula.command.CommandHandler; import emu.nebula.command.CommandHandler;
import emu.nebula.net.NetMsgId; import emu.nebula.net.NetMsgId;
@Command(label = "battlepass", aliases = {"bp"}, permission = "player.battlepass", desc = "!battlepass [free | premium] lv(level) = Modifies the targeted player's battle pass") @Command(
label = "battlepass",
aliases = {"bp"},
permission = "player.battlepass",
desc = "!battlepass [free | premium] lv(level) = Sets the targeted player's battle pass mode and level (maximum level 50)."
)
public class BattlePassCommand implements CommandHandler { public class BattlePassCommand implements CommandHandler {
@Override @Override
@@ -21,7 +21,7 @@ import lombok.Getter;
aliases = {"b", "record", "r"}, aliases = {"b", "record", "r"},
permission = "player.build", permission = "player.build",
requireTarget = true, requireTarget = true,
desc = "!build [char ids...] [disc ids...] [potential ids...] [melody ids...]" desc = "!build [character ids...] [disc ids...] [potential ids...] [sub-note skill ids...] = Creates a record for the targeted player. Requires exactly 3 characters and 3-6 discs. Potential levels can be set with id:level, and a preset code can be used instead of item ids."
) )
public class BuildCommand implements CommandHandler { public class BuildCommand implements CommandHandler {
@@ -17,7 +17,7 @@ import emu.nebula.command.CommandHandler;
aliases = {"c", "char"}, aliases = {"c", "char"},
permission = "player.character", permission = "player.character",
requireTarget = true, requireTarget = true,
desc = "!c [all | {characterId}] lv(level) a(ascension) s(skill level) t(talent level) f(affinity level)" desc = "!char [all | character ids...] lv(level) a(ascension) s(skill level) t(talent level) f(affinity level) = Changes the targeted player's characters. Multiple character ids can be given, and 'all' applies the changes to every owned character."
) )
public class CharacterCommand implements CommandHandler { public class CharacterCommand implements CommandHandler {
@@ -18,7 +18,7 @@ import java.util.HashSet;
aliases = {"cl", "clear"}, aliases = {"cl", "clear"},
permission = "player.inventory", permission = "player.inventory",
requireTarget = true, requireTarget = true,
desc = "!clean [all | {id} ...] [items|resources] = Removes items/resources from the targeted player." desc = "!clean [all | item ids...] [items | resources] = Removes items and/or resources from the targeted player. Use 'all' to remove everything, or add 'items' or 'resources' to limit the cleanup to one type."
) )
public class CleanCommand implements CommandHandler { public class CleanCommand implements CommandHandler {
@@ -16,7 +16,7 @@ import emu.nebula.command.CommandHandler;
aliases = {"d"}, aliases = {"d"},
permission = "player.character", permission = "player.character",
requireTarget = true, requireTarget = true,
desc = "!d [all | {discId}] lv(level) a(ascension) c(crescendo level)" desc = "!disc [all | disc ids...] lv(level) a(ascension) c(crescendo level) = Changes the targeted player's discs. Multiple disc ids can be given, and 'all' applies the changes to every owned disc."
) )
public class DiscCommand implements CommandHandler { public class DiscCommand implements CommandHandler {
@@ -17,7 +17,7 @@ import emu.nebula.data.GameData;
aliases = {"e", "gem"}, aliases = {"e", "gem"},
permission = "player.emblem", permission = "player.emblem",
requireTarget = true, requireTarget = true,
desc = "!emblem [characterId] [emblem slot] [attribute value ids....]" desc = "!emblem [character id] [emblem slot] [attribute value id 1] [attribute value id 2] [attribute value id 3] [attribute value id 4] = Sets the four attribute values of an emblem in the targeted player's character emblem slot, creating or replacing the gem as needed."
) )
public class EmblemCommand implements CommandHandler { public class EmblemCommand implements CommandHandler {
@@ -20,7 +20,7 @@ import emu.nebula.proto.Public.Item;
aliases = {"ga"}, aliases = {"ga"},
permission = "player.give", permission = "player.give",
requireTarget = true, requireTarget = true,
desc = "!ga [characters | discs | materials] lv(level) t(talent/crescendo level) s(skill level). Gives the targeted player items." desc = "!giveall [materials | discs | characters | skins] lv(level) a(ascension) s(skill level) t(talent/crescendo level) = Gives the targeted player all materials, discs, characters, or paid skins. The level, ascension, skill, and talent values are applied to newly added characters and discs."
) )
public class GiveAllCommand implements CommandHandler { public class GiveAllCommand implements CommandHandler {
private static Set<ItemSubType> MATERIAL_ITEM_SUBTYPES = Set.of( private static Set<ItemSubType> MATERIAL_ITEM_SUBTYPES = Set.of(
@@ -12,7 +12,7 @@ import emu.nebula.command.CommandHandler;
aliases = {"g", "item"}, aliases = {"g", "item"},
permission = "player.give", permission = "player.give",
requireTarget = true, requireTarget = true,
desc = "!give [item id] x(amount). Gives the targeted player an item." desc = "!give [item ids...] x(amount) = Sends the targeted player the specified items through the mail. Defaults to 1 of each item."
) )
public class GiveCommand implements CommandHandler { public class GiveCommand implements CommandHandler {
@@ -5,7 +5,7 @@ import emu.nebula.command.Command;
import emu.nebula.command.CommandArgs; import emu.nebula.command.CommandArgs;
import emu.nebula.command.CommandHandler; import emu.nebula.command.CommandHandler;
@Command(label = "help", permission = "player.help", desc = "!help = Displays a list of available commands. (Very spammy in-game)") @Command(label = "help", permission = "player.help", desc = "!help = Displays a list of every command available to you. (Very spammy in-game)")
public class HelpCommand implements CommandHandler { public class HelpCommand implements CommandHandler {
@Override @Override
@@ -8,7 +8,7 @@ import emu.nebula.net.NetMsgId;
import emu.nebula.proto.NotifyGm.GmWorldClass; import emu.nebula.proto.NotifyGm.GmWorldClass;
import emu.nebula.util.Utils; import emu.nebula.util.Utils;
@Command(label = "setlevel", aliases = {"level", "l"}, permission = "player.level", requireTarget = true, desc = "!level [level] = Set's the targeted player's level") @Command(label = "setlevel", aliases = {"level", "l"}, permission = "player.level", requireTarget = true, desc = "!level [level] = Sets the targeted player's level.")
public class LevelCommand implements CommandHandler { public class LevelCommand implements CommandHandler {
@Override @Override
@@ -14,7 +14,7 @@ import emu.nebula.util.Utils;
aliases = {"m"}, aliases = {"m"},
permission = "player.mail", permission = "player.mail",
requireTarget = true, requireTarget = true,
desc = "!mail \"subject\" \"body\" [itemId xQty | itemId:qty ...] = Sends the targeted player a system mail." desc = "!mail \"subject\" \"body\" [itemId xQty | itemId:qty ...] = Sends the targeted player a system mail. The subject and body must be wrapped in quotes, and attachments are optional."
) )
public class MailCommand implements CommandHandler { public class MailCommand implements CommandHandler {
private static final String USAGE_TEXT = "Usage: /mail \"subject\" \"body\" [itemId xQty | itemId:qty ...]"; private static final String USAGE_TEXT = "Usage: /mail \"subject\" \"body\" [itemId xQty | itemId:qty ...]";
@@ -5,7 +5,7 @@ import emu.nebula.command.Command;
import emu.nebula.command.CommandArgs; import emu.nebula.command.CommandArgs;
import emu.nebula.command.CommandHandler; import emu.nebula.command.CommandHandler;
@Command(label = "reload", permission = "admin.reload", desc = "!reload = Reloads the server config.") @Command(label = "reload", permission = "admin.reload", desc = "!reload = Reloads the server config and the game patch list.")
public class ReloadCommand implements CommandHandler { public class ReloadCommand implements CommandHandler {
@Override @Override
@@ -7,7 +7,7 @@ import emu.nebula.command.CommandHandler;
import java.util.Random; import java.util.Random;
@Command(label = "remote", permission = "player.remote", requireTarget = true, desc = "!remote = Creates a player token for remote api usage") @Command(label = "remote", permission = "player.remote", requireTarget = true, desc = "!remote = Generates a remote API token for the targeted player, or clears it if remote services are disabled on the server.")
public class RemoteKeyCommand implements CommandHandler { public class RemoteKeyCommand implements CommandHandler {
private final String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; private final String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -9,7 +9,7 @@ import emu.nebula.command.CommandHandler;
import java.io.File; import java.io.File;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
@Command(label = "status", permission = "admin.status", desc = "!status = Displays server runtime status.") @Command(label = "status", permission = "admin.status", desc = "!status [@id] = Displays server runtime status, including uptime, CPU, memory, disk, and player count. Add @UID to verify that a player is online.")
public class StatusCommand implements CommandHandler { public class StatusCommand implements CommandHandler {
@Override @Override
@@ -10,12 +10,10 @@ import emu.nebula.game.player.Player;
import java.util.Locale; import java.util.Locale;
@Command(label = "unban", permission = "admin.ban", desc = """ @Command(label = "unban", permission = "admin.ban", desc = """
!unban {all | ip | uid} [player uid | ip]\ !unban {all | ip | uid} [player uid | ip] = Unbans a player or IP address.
- all unbans both the player and their IP by UID, so use a UID as the second argument
- all mode unbans both the player object and their IP address by UID, so the next parameter should be UID instead of IP - uid unbans only the UID, so use a UID as the second argument
- ip mode can only unban IP addresses, so the next parameter should be an IP - ip unbans only the IP address, so use an IP as the second argument""")
- uid mode can only unban UIDs, so the next parameter should be a UID\
""")
public class UnbanCommand implements CommandHandler { public class UnbanCommand implements CommandHandler {
@Override @Override
+19 -2
View File
@@ -163,6 +163,15 @@ public class GameSession {
// Packet encoding helper functions // Packet encoding helper functions
/**
* Encodes a message to be sent to the client, using the given proto as its payload.
* <p>
* Any pending next packages for the player are chained onto the proto before encoding.
*
* @param msgId the message id to encode
* @param proto the proto message to send as the payload
* @return the encoded packet (as a byte array)
*/
@SneakyThrows @SneakyThrows
public byte[] encodeMsg(int msgId, ProtoMessage<?> proto) { public byte[] encodeMsg(int msgId, ProtoMessage<?> proto) {
// Check if we have any packages to send to the client // Check if we have any packages to send to the client
@@ -176,10 +185,18 @@ public class GameSession {
} }
} }
// Encode to message like normal // Encodes a message with the proto as it's payload
return PacketHelper.encodeMsg(msgId, proto); return PacketHelper.encodeMsg(msgId, proto);
} }
/**
* Encodes a message with no payload to be sent to the client.
* <p>
* If the player has pending next packages, a {@link Nil} proto is created to carry them.
*
* @param msgId the message id to encode
* @return the encoded packet (as a byte array)
*/
public byte[] encodeMsg(int msgId) { public byte[] encodeMsg(int msgId) {
// Check if we have any packages to send to the client // Check if we have any packages to send to the client
if (this.getPlayer() != null) { if (this.getPlayer() != null) {
@@ -196,7 +213,7 @@ public class GameSession {
} }
} }
// Encode simple message // Encodes the message
return PacketHelper.encodeMsg(msgId); return PacketHelper.encodeMsg(msgId);
} }