diff --git a/README.md b/README.md index 239570e..b30ccf9 100644 --- a/README.md +++ b/README.md @@ -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` -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 @@ -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. ### Server commands -Server commands need to be run in the server console OR in the signature edit menu of your profile. -``` -!account {create | delete} [email] (reserved player uid) = Creates or deletes an account. -!battlepass [free | premium] lv(level) = Modifies the targeted player's battle pass -!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. -!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. -!giveall [characters | discs | materials] = Gives the targeted player items. -!help = Displays a list of available commands. (Very spammy in-game) -!level (level) = Sets the player level -!mail "subject" "body" [itemId xQty | itemId:qty ...] = Sends the targeted player a system mail. -!reload = Reloads the server config. -!remote = Creates a player token for remote api usage -``` +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 `/`. + +Commands that modify a player need a target: run them in-game, or append `@` to target a player from the console. + +| Command | Aliases | Description | +| --- | --- | --- | +| `!account` | | Create an account (optionally reserving a player UID), delete an account, or list all accounts.
`!account create [reserved uid]`
`!account delete `
`!account list` | +| `!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.
`!arena [@uid]`
`!arena clear`
Elements: `generic`, `ignis`, `ventus`, `lux`, `aqua`, `terra`, `umbra` (or `1`-`7`). | +| `!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.
`!autobuild [ids...] lv(level) s(score) [-nn] [-np]`
`-nn` skips sub-note skills and `-np` skips potentials. | +| `!ban` | | Ban a player or IP address.
`!ban {all \| ip \| uid} [end timestamp] [reason]`
`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. | +| `!battlepass` | `bp` | Set a player's battle pass mode and level (maximum level 50).
`!battlepass [free \| premium] lv(level)` | +| `!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.
`!build [character ids...] [disc ids...] [potential ids...] [sub-note skill ids...]` | +| `!character` | `c`, `char` | Change a character's level, ascension, skill, talent, and affinity.
`!character [all \| character ids...] lv(level) a(ascension) s(skill level) t(talent level) f(affinity level)`
`all` applies the changes to every owned character. | +| `!clean` | `cl`, `clear` | Remove items and/or resources from a player.
`!clean [all \| item ids...] [items \| resources]`
`all` removes everything; `items` or `resources` limits the cleanup to one type. | +| `!disc` | `d` | Change a disc's level, ascension, and crescendo level.
`!disc [all \| disc ids...] lv(level) a(ascension) c(crescendo level)`
`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.
`!emblem ` | +| `!give` | `g`, `item` | Send items to a player through the mail.
`!give x(amount)`
Defaults to 1 of each item. | +| `!giveall` | `ga` | Give a player all materials, discs, characters, or paid skins.
`!giveall [materials \| discs \| characters \| skins] lv(level) a(ascension) s(skill level) t(talent/crescendo level)`
Property values are applied to newly added characters and discs. | +| `!help` | | List every command available to you.
`!help`
This is very spammy in-game. | +| `!level` | `setlevel`, `l` | Set a player's level.
`!level ` | +| `!mail` | `m` | Send a system mail with optional attachments. The subject and body must be wrapped in quotes.
`!mail "subject" "body" [itemId xQty \| itemId:qty ...]` | +| `!reload` | | Reload the server config and the game patch list.
`!reload` | +| `!remote` | | Generate a remote API token for a player, or clear it when remote services are disabled.
`!remote` | +| `!status` | | Show server runtime status: uptime, CPU, memory, disk, and player count.
`!status [@uid]`
Add `@uid` to verify that a player is online. | +| `!unban` | | Unban a player or IP address.
`!unban {all \| ip \| uid} `
`all` unbans both the UID and its IP, `uid` only the UID, and `ip` only the IP. | diff --git a/src/main/java/emu/nebula/Config.java b/src/main/java/emu/nebula/Config.java index 26eddc5..4614743 100644 --- a/src/main/java/emu/nebula/Config.java +++ b/src/main/java/emu/nebula/Config.java @@ -158,8 +158,8 @@ public class Config { @Getter public static class RemoteCommand { - public boolean useRemoteServices = false; - public String serverAdminKey = "HJHASDPIIQWEASDHHAN"; + public boolean useRemoteServices = false; // Turned off by default + public String serverAdminKey = "HJHASDPIIQWEASDHHAN"; // Please change the admin key before turning it on } @Getter diff --git a/src/main/java/emu/nebula/command/commands/AccountCommand.java b/src/main/java/emu/nebula/command/commands/AccountCommand.java index 333f0e4..a9158c2 100644 --- a/src/main/java/emu/nebula/command/commands/AccountCommand.java +++ b/src/main/java/emu/nebula/command/commands/AccountCommand.java @@ -6,7 +6,11 @@ import emu.nebula.command.CommandHandler; import emu.nebula.game.account.AccountHelper; 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 { @Override diff --git a/src/main/java/emu/nebula/command/commands/ArenaCommand.java b/src/main/java/emu/nebula/command/commands/ArenaCommand.java index 268c748..1fafafb 100644 --- a/src/main/java/emu/nebula/command/commands/ArenaCommand.java +++ b/src/main/java/emu/nebula/command/commands/ArenaCommand.java @@ -8,7 +8,13 @@ import emu.nebula.data.GameData; import emu.nebula.data.resources.InfinityTowerLevelDef; 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 { private static final String RELOG_HINT = " Restart the game to see the change."; diff --git a/src/main/java/emu/nebula/command/commands/AutoBuildCommand.java b/src/main/java/emu/nebula/command/commands/AutoBuildCommand.java index 64d33de..8b20c53 100644 --- a/src/main/java/emu/nebula/command/commands/AutoBuildCommand.java +++ b/src/main/java/emu/nebula/command/commands/AutoBuildCommand.java @@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; aliases = {"ab"}, permission = "player.build", 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 { private static final int[] COMMON_SUB_NOTE_SKILLS = new int[] { diff --git a/src/main/java/emu/nebula/command/commands/BanCommand.java b/src/main/java/emu/nebula/command/commands/BanCommand.java index 2efb791..87ff8f8 100644 --- a/src/main/java/emu/nebula/command/commands/BanCommand.java +++ b/src/main/java/emu/nebula/command/commands/BanCommand.java @@ -12,13 +12,11 @@ import java.util.Locale; @Command(label = "ban", permission = "admin.ban", desc = """ - !ban {all | ip | uid} [player uid | ip] (end timestamp) (reason) - Ban a player\ - - - all mode bans both the player object and their IP address by UID, so the next parameter should be UID instead of IP - - ip mode can only ban IP addresses, so the next parameter should be an IP - - uid mode can only ban UIDs, so the next parameter should be a UID - - If you don't fill in the end timestamp, it will be permanently banned by default\ - """) + !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 + - uid bans only the UID, so use a UID as the second argument + - ip bans only the IP address, so use an IP as the second argument + - Omit the end timestamp for a permanent ban""") public class BanCommand implements CommandHandler { @Override diff --git a/src/main/java/emu/nebula/command/commands/BattlePassCommand.java b/src/main/java/emu/nebula/command/commands/BattlePassCommand.java index b8c635c..963d618 100644 --- a/src/main/java/emu/nebula/command/commands/BattlePassCommand.java +++ b/src/main/java/emu/nebula/command/commands/BattlePassCommand.java @@ -5,7 +5,12 @@ import emu.nebula.command.CommandArgs; import emu.nebula.command.CommandHandler; 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 { @Override diff --git a/src/main/java/emu/nebula/command/commands/BuildCommand.java b/src/main/java/emu/nebula/command/commands/BuildCommand.java index c6de893..ad8a4ce 100644 --- a/src/main/java/emu/nebula/command/commands/BuildCommand.java +++ b/src/main/java/emu/nebula/command/commands/BuildCommand.java @@ -21,7 +21,7 @@ import lombok.Getter; aliases = {"b", "record", "r"}, permission = "player.build", 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 { diff --git a/src/main/java/emu/nebula/command/commands/CharacterCommand.java b/src/main/java/emu/nebula/command/commands/CharacterCommand.java index 7b91d04..975fbcd 100644 --- a/src/main/java/emu/nebula/command/commands/CharacterCommand.java +++ b/src/main/java/emu/nebula/command/commands/CharacterCommand.java @@ -17,7 +17,7 @@ import emu.nebula.command.CommandHandler; aliases = {"c", "char"}, permission = "player.character", 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 { diff --git a/src/main/java/emu/nebula/command/commands/CleanCommand.java b/src/main/java/emu/nebula/command/commands/CleanCommand.java index 796055a..b49b2a2 100644 --- a/src/main/java/emu/nebula/command/commands/CleanCommand.java +++ b/src/main/java/emu/nebula/command/commands/CleanCommand.java @@ -18,7 +18,7 @@ import java.util.HashSet; aliases = {"cl", "clear"}, permission = "player.inventory", 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 { diff --git a/src/main/java/emu/nebula/command/commands/DiscCommand.java b/src/main/java/emu/nebula/command/commands/DiscCommand.java index 82a4b38..59be3f9 100644 --- a/src/main/java/emu/nebula/command/commands/DiscCommand.java +++ b/src/main/java/emu/nebula/command/commands/DiscCommand.java @@ -16,7 +16,7 @@ import emu.nebula.command.CommandHandler; aliases = {"d"}, permission = "player.character", 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 { diff --git a/src/main/java/emu/nebula/command/commands/EmblemCommand.java b/src/main/java/emu/nebula/command/commands/EmblemCommand.java index fc64a45..ea8a1b6 100644 --- a/src/main/java/emu/nebula/command/commands/EmblemCommand.java +++ b/src/main/java/emu/nebula/command/commands/EmblemCommand.java @@ -17,7 +17,7 @@ import emu.nebula.data.GameData; aliases = {"e", "gem"}, permission = "player.emblem", 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 { diff --git a/src/main/java/emu/nebula/command/commands/GiveAllCommand.java b/src/main/java/emu/nebula/command/commands/GiveAllCommand.java index e19ccbc..0808f11 100644 --- a/src/main/java/emu/nebula/command/commands/GiveAllCommand.java +++ b/src/main/java/emu/nebula/command/commands/GiveAllCommand.java @@ -20,7 +20,7 @@ import emu.nebula.proto.Public.Item; aliases = {"ga"}, permission = "player.give", 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 { private static Set MATERIAL_ITEM_SUBTYPES = Set.of( diff --git a/src/main/java/emu/nebula/command/commands/GiveCommand.java b/src/main/java/emu/nebula/command/commands/GiveCommand.java index 9c55f0a..7db07ce 100644 --- a/src/main/java/emu/nebula/command/commands/GiveCommand.java +++ b/src/main/java/emu/nebula/command/commands/GiveCommand.java @@ -12,7 +12,7 @@ import emu.nebula.command.CommandHandler; aliases = {"g", "item"}, permission = "player.give", 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 { diff --git a/src/main/java/emu/nebula/command/commands/HelpCommand.java b/src/main/java/emu/nebula/command/commands/HelpCommand.java index 83a8879..319c801 100644 --- a/src/main/java/emu/nebula/command/commands/HelpCommand.java +++ b/src/main/java/emu/nebula/command/commands/HelpCommand.java @@ -5,7 +5,7 @@ import emu.nebula.command.Command; import emu.nebula.command.CommandArgs; 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 { @Override diff --git a/src/main/java/emu/nebula/command/commands/LevelCommand.java b/src/main/java/emu/nebula/command/commands/LevelCommand.java index 0d8359e..5ae1257 100644 --- a/src/main/java/emu/nebula/command/commands/LevelCommand.java +++ b/src/main/java/emu/nebula/command/commands/LevelCommand.java @@ -8,7 +8,7 @@ import emu.nebula.net.NetMsgId; import emu.nebula.proto.NotifyGm.GmWorldClass; 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 { @Override diff --git a/src/main/java/emu/nebula/command/commands/MailCommand.java b/src/main/java/emu/nebula/command/commands/MailCommand.java index 9901458..f4908e2 100644 --- a/src/main/java/emu/nebula/command/commands/MailCommand.java +++ b/src/main/java/emu/nebula/command/commands/MailCommand.java @@ -14,7 +14,7 @@ import emu.nebula.util.Utils; aliases = {"m"}, permission = "player.mail", 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 { private static final String USAGE_TEXT = "Usage: /mail \"subject\" \"body\" [itemId xQty | itemId:qty ...]"; diff --git a/src/main/java/emu/nebula/command/commands/ReloadCommand.java b/src/main/java/emu/nebula/command/commands/ReloadCommand.java index 5a900bf..0e5b00f 100644 --- a/src/main/java/emu/nebula/command/commands/ReloadCommand.java +++ b/src/main/java/emu/nebula/command/commands/ReloadCommand.java @@ -5,7 +5,7 @@ import emu.nebula.command.Command; import emu.nebula.command.CommandArgs; 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 { @Override diff --git a/src/main/java/emu/nebula/command/commands/RemoteKeyCommand.java b/src/main/java/emu/nebula/command/commands/RemoteKeyCommand.java index e18ff59..1c4e70d 100644 --- a/src/main/java/emu/nebula/command/commands/RemoteKeyCommand.java +++ b/src/main/java/emu/nebula/command/commands/RemoteKeyCommand.java @@ -7,7 +7,7 @@ import emu.nebula.command.CommandHandler; 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 { private final String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; diff --git a/src/main/java/emu/nebula/command/commands/StatusCommand.java b/src/main/java/emu/nebula/command/commands/StatusCommand.java index 508c711..f00ca26 100644 --- a/src/main/java/emu/nebula/command/commands/StatusCommand.java +++ b/src/main/java/emu/nebula/command/commands/StatusCommand.java @@ -9,7 +9,7 @@ import emu.nebula.command.CommandHandler; import java.io.File; 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 { @Override diff --git a/src/main/java/emu/nebula/command/commands/UnbanCommand.java b/src/main/java/emu/nebula/command/commands/UnbanCommand.java index 228aee9..e1c39db 100644 --- a/src/main/java/emu/nebula/command/commands/UnbanCommand.java +++ b/src/main/java/emu/nebula/command/commands/UnbanCommand.java @@ -10,12 +10,10 @@ import emu.nebula.game.player.Player; import java.util.Locale; @Command(label = "unban", permission = "admin.ban", desc = """ - !unban {all | ip | uid} [player uid | ip]\ - - - all mode unbans both the player object and their IP address by UID, so the next parameter should be UID instead of IP - - ip mode can only unban IP addresses, so the next parameter should be an IP - - uid mode can only unban UIDs, so the next parameter should be a UID\ - """) + !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 + - uid unbans only the UID, so use a UID as the second argument + - ip unbans only the IP address, so use an IP as the second argument""") public class UnbanCommand implements CommandHandler { @Override diff --git a/src/main/java/emu/nebula/net/GameSession.java b/src/main/java/emu/nebula/net/GameSession.java index 3f6445f..bb5ada9 100644 --- a/src/main/java/emu/nebula/net/GameSession.java +++ b/src/main/java/emu/nebula/net/GameSession.java @@ -163,6 +163,15 @@ public class GameSession { // Packet encoding helper functions + /** + * Encodes a message to be sent to the client, using the given proto as its payload. + *

+ * 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 public byte[] encodeMsg(int msgId, ProtoMessage proto) { // 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); } + /** + * Encodes a message with no payload to be sent to the client. + *

+ * 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) { // Check if we have any packages to send to the client if (this.getPlayer() != null) { @@ -196,7 +213,7 @@ public class GameSession { } } - // Encode simple message + // Encodes the message return PacketHelper.encodeMsg(msgId); }