Allow commands to target offline players (#1022)

* Add targetRequirement annotation for Command

* Added MTL lines for other langs

* Fix TargetRequirement enum scoping

* Adjust commands to targetRequirement system

* Add translation message sugar to prevent future messages from being translated for wrong player

* Temporarily disable offline targeting on /permission and /clear

* Preliminary README cleanup

* Readme commands cleanup

* Clean up command table in README, including column shuffle

Co-authored-by: AnimeGitB <AnimeGitB@bigblueball.in>
This commit is contained in:
Luke H-W 2022-05-22 17:32:11 +09:30 committed by GitHub
parent 33a6826a3f
commit afbeaf300c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 123 additions and 217 deletions

View File

@ -106,43 +106,50 @@ You may want to use this command (`java -jar grasscutter.jar -gachamap`) to gene
There is a dummy user named "Server" in every player's friends list that you can message to use commands. Commands also work in other chat rooms, such as private/team chats. to run commands ingame, you need to add prefix `/` or `!` such as `/pos`
| Commands | Usage | Permission node | Availability | description | Alias |
| -------------- | ------------------------------------------------- | ------------------------- |--------------| ------------------------------------------------------------ | ----------------------------------------------- |
| account | account <create\|delete> \<username> [UID] | | Server only | Creates an account with the specified username and the in-game UID for that account. The UID will be auto generated if not set. | |
| broadcast | broadcast \<message> | server.broadcast | Both side | Sends a message to all the players. | b |
| coop | coop \<playerId> \<target playerId> | server.coop | Both side | Forces someone to join the world of others. | |
| changescene | changescene \<scene id> | player.changescene | Client only | Switch scenes by scene ID. | scene |
| clear | clear <all\|wp\| art\ |mat> [UID] | player.clearinv | Client only | Deletes all unequipped and unlocked level 0 artifacts(art)/weapons(wp)/material(all) or all, including 5-star rarity ones from your inventory. | clear |
| drop | drop <itemID\|itemName> [amount] | server.drop | Client only | Drops an item around you. | `d` `dropitem` |
| enterdungeon | enterdungeon \<dungeon id> | player.enterdungeon | Client only | Enter a dungeon by dungeon ID | |
| give | give [player] <itemId\|itemName> [amount] [level] [finement] | player.give | Both side | Gives item(s) to you or the specified player. (finement option only weapon.) | `g` `item` `giveitem` |
| givechar | givechar \<uid> \<avatarId> | player.givechar | Both side | Gives the player a specified character. | givec |
| giveart | giveart [player] \<artifactId> \<mainPropId> [\<appendPropId>[,\<times>]]... [level] | player.giveart | Both side | Gives the player a specified artifact. | gart |
| giveall | giveall [uid] [amount] | player.giveall | Both side | Gives all items. | givea |
| godmode | godmode [uid] | player.godmode | Client only | Prevents you from taking damage. | |
| heal | heal | player.heal | Client only | Heals all characters in your current team. | h |
| help | help [command] | | Both side | Sends the help message or shows information about a specified command. | |
| join | join [avatarIds] | player.join | Client only | Force let avatars to join into your current team. Such as `join 10000020 10000021`. | |
| kick | kick \<player> | server.kick | Both side | Kicks the specified player from the server. (WIP) | k |
| killall | killall [playerUid] [sceneId] | server.killall | Both side | Kills all entities in the current scene or specified scene of the corresponding player. | |
| list | list | | Both side | Lists online players. | |
| permission | permission <add\|remove> \<UID> \<permission> | permission | Both side | Grants or removes a permission for a user. | |
| position | position | | Client only | Sends your current coordinates. | pos |
| reload | reload | server.reload | Both side | Reloads the server config | |
| remove | remove [avatarIndexInYourTeams] | player.remove | Client only | Force remove avatar in your current team. Index start from 1.Such as `remove 1 2`. | |
| resetconst | resetconst [all] | player.resetconstellation | Client only | Resets the constellation level on your currently selected character, will need to relog after using the command to see any changes. | resetconstellation |
| restart | | | Both side | Restarts the current session | |
| say | say \<player> \<message> | server.sendmessage | Both side | Sends a message to a player as the server | `sendservmsg` `sendservermessage` `sendmessage` |
| setfetterlevel | setfetterlevel \<level> | player.setfetterlevel | Client only | Sets the friendship level for your currently selected character | setfetterlvl |
| setstats | setstats \<stat> \<value> | player.setstats | Client only | Sets a stat for your currently selected character | stats |
| setworldlevel | setworldlevel \<level> | player.setworldlevel | Client only | Sets your world level (Relog to see proper effects) | setworldlvl |
| spawn | spawn \<entityId> [amount] [level(monster only)] | server.spawn | Client only | Spawns some entities around you | |
| stop | stop | server.stop | Both side | Stops the server | |
| talent | talent \<talentID> \<value> | player.settalent | Client only | Sets talent level for your currently selected character | |
| teleport | teleport [@playerUid] \<x> \<y> \<z> [sceneId] | player.teleport | Both side | Change the player's position. | tp |
| tpall | | player.tpall | Client only | Teleports all players in your world to your position | |
| unlocktower | | player.tower | Client only | Unlock the all floors of abyss | ut |
| weather | weather \<weatherID> \<climateID> | player.weather | Client only | Changes the weather | w |
### Targeting
1. For commands that target a Player, you can specify a target UID with `@UID` as an argument in any position to the command.
2. If you message a valid command at another player (instead of at the "Server" virtual player), they will be the target for that command if you didn't set one above.
3. If none of the above, it will default to a persistent target player you previously set using the command `/target <UID>`.
4. If none of the above, you will be the target of the command. If you are entering the command from the Server console, **it will not work!**
Note that performing commands on other players will usually require different a permission to the base permission node. e.g. `player.give` becomes `player.give.others` if used on another player.
| Commands | Description | Alias | Targeting | Usage | Permission node |
| -------------- | ------------------------------------------------------------------------------------------------- | ------------------ | ------------- | --------------------------------------------------------------------------- | ------------------------- |
| account | Creates an account with the specified username, and the in-game UID if specified. | | Server only | account \<create\|delete> \<username> [UID] | |
| broadcast | Sends a message to all the players. | b | None | broadcast \<message> | server.broadcast |
| coop | Forces someone to join the world of others. | | Online Player | coop [host UID (default self)] | server.coop |
| changescene | Switch scenes by scene ID. | scene | Online Player | changescene \<scene id> | player.changescene |
| clear | Deletes all unequipped and unlocked lvl0 artifacts(art)/weapons(wp)/material(mat) from inventory. | | Online Player | clear \<all\|wp\|art\|mat> | player.clearinv |
| drop | Drops an item around you. | d dropitem | Online Player | drop \<itemID\|itemName> [amount] | server.drop |
| enterdungeon | Enter a dungeon by dungeon ID. | | Online Player | enterdungeon \<dungeon id> | player.enterdungeon |
| give | Gives item(s) to you or the specified player. | g item giveitem | Online Player | give \<itemId\|itemName> [amount] [level] [refinement] | player.give |
| giveall | Gives all items. | givea | Online Player | giveall [amount] | player.giveall |
| giveart | Gives the player a specified artifact. | gart | Online Player | giveart \<artifactId> \<mainPropId> [\<appendPropId>[,\<times>]]... [level] | player.giveart |
| givechar | Gives the player a specified character. | givec | Online Player | givechar \<avatarId> | player.givechar |
| godmode | Prevents you from taking damage. | | Online Player | godmode | player.godmode |
| heal | Heals all characters in your current team. | h | Online Player | heal | player.heal |
| help | Sends the help message or shows information about a specified command. | | None | help [command] | |
| kick | Kicks the specified player from the server. | k | Online Player | kick | server.kick |
| killall | Kills all entities in the current scene or specified scene of the corresponding player. | | Online Player | killall [sceneId] | server.killall |
| list | Lists online players. | | None | list | |
| permission | Grants or removes a permission for a user. | | Online Player | permission \<add\|remove> \<permission> | permission |
| position | Sends your current coordinates. | pos | Online Player | position | |
| reload | Reloads the server config. | | None | reload | server.reload |
| resetconst | Resets currently selected (or all) character(s) to C0. Relog to see proper effects. | resetconstellation | Online Player | resetconst [all] | player.resetconstellation |
| restart | Restarts the current session. | | None | restart | |
| sendmessage | Sends a message to a player as the server. | say | Online Player | say \<message> | server.sendmessage |
| setfetterlevel | Sets the friendship level for your currently selected character. | setfetterlvl | Online Player | setfetterlevel \<level> | player.setfetterlevel |
| setstats | Sets a stat for your currently selected character. | stats | Online Player | setstats \<stat> \<value> | player.setstats |
| setworldlevel | Sets your world level. Relog to see proper effects. | setworldlvl | Online Player | setworldlevel \<level> | player.setworldlevel |
| spawn | Spawns some entities around you. | | Online Player | spawn \<entityId> [amount] [level(monster only)] | server.spawn |
| stop | Stops the server. | | None | stop | server.stop |
| talent | Sets talent level for your currently selected character | | Online Player | talent \<talentID> \<value> | player.settalent |
| team | Add, remove, or swap avatars in your current team. Index start from 1. | | Online Player | team \<add\|remove\|set> [avatarId,...] [index|first|last|index-index,...] | player.team |
| teleport | Change the player's position. | tp | Online Player | teleport \<x> \<y> \<z> [sceneId] | player.teleport |
| tpall | Teleports all players in your world to your position. | | Online Player | tpall | player.tpall |
| unlocktower | Unlock the all floors of abyss. | ut | Online Player | ut | player.tower |
| weather | Changes the weather. | w | Online Player | weather \<weatherID> \<climateID> | player.weather |
### Bonus

View File

@ -17,5 +17,13 @@ public @interface Command {
String permissionTargeted() default "";
public enum TargetRequirement {
NONE, // targetPlayer is not required
OFFLINE, // targetPlayer must be offline
PLAYER, // targetPlayer can be online or offline
ONLINE // targetPlayer must be online
}
TargetRequirement targetRequirement() default TargetRequirement.ONLINE;
boolean threading() default false;
}

View File

@ -4,6 +4,7 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.game.CommandResponseEvent;
import emu.grasscutter.server.event.types.ServerEvent;
import static emu.grasscutter.utils.Language.translate;
import java.util.List;
@ -24,6 +25,10 @@ public interface CommandHandler {
CommandResponseEvent event = new CommandResponseEvent(ServerEvent.Type.GAME,player, message);
event.call();
}
static void sendTranslatedMessage(Player player, String messageKey, Object... args) {
sendMessage(player, translate(player, messageKey, args));
}
/**
* Called when a player/console invokes a command.

View File

@ -8,8 +8,6 @@ import org.reflections.Reflections;
import java.util.*;
import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings({"UnusedReturnValue", "unused"})
public final class CommandMap {
private final Map<String, CommandHandler> commands = new HashMap<>();
@ -117,7 +115,7 @@ public final class CommandMap {
public void invoke(Player player, Player targetPlayer, String rawMessage) {
rawMessage = rawMessage.trim();
if (rawMessage.length() == 0) {
CommandHandler.sendMessage(player, translate("commands.generic.not_specified"));
CommandHandler.sendTranslatedMessage(player, "commands.generic.not_specified");
return;
}
@ -144,19 +142,20 @@ public final class CommandMap {
if (targetUidStr != null) {
if (targetUidStr.equals("")) { // Clears the default targetPlayer.
targetPlayerIds.remove(playerId);
CommandHandler.sendMessage(player, translate("commands.execution.clear_target"));
CommandHandler.sendTranslatedMessage(player, "commands.execution.clear_target");
} else { // Sets default targetPlayer to the UID provided.
try {
int uid = Integer.parseInt(targetUidStr);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendMessage(player, translate("commands.execution.player_exist_offline_error"));
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
} else {
targetPlayerIds.put(playerId, uid);
CommandHandler.sendMessage(player, translate("commands.execution.set_target", targetUidStr));
CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", targetUidStr);
CommandHandler.sendTranslatedMessage(player, targetPlayer.isOnline()? "commands.execution.set_target_online" : "commands.execution.set_target_offline", targetUidStr);
}
} catch (NumberFormatException e) {
CommandHandler.sendMessage(player, translate("commands.execution.uid_error"));
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
}
}
return;
@ -165,7 +164,7 @@ public final class CommandMap {
// Get command handler.
CommandHandler handler = this.commands.get(label);
if (handler == null) {
CommandHandler.sendMessage(player, translate("commands.generic.unknown_command", label));
CommandHandler.sendTranslatedMessage(player, "commands.generic.unknown_command", label);
return;
}
@ -176,14 +175,14 @@ public final class CommandMap {
arg = args.remove(i).substring(1);
try {
int uid = Integer.parseInt(arg);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendMessage(player, translate("commands.execution.player_exist_offline_error"));
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return;
}
break;
} catch (NumberFormatException e) {
CommandHandler.sendMessage(player, translate("commands.execution.uid_error"));
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
return;
}
}
@ -192,9 +191,9 @@ public final class CommandMap {
// If there's still no targetPlayer at this point, use previously-set target
if (targetPlayer == null) {
if (targetPlayerIds.containsKey(playerId)) {
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(targetPlayerIds.get(playerId)); // We check every time in case the target goes offline after being targeted
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(targetPlayerIds.get(playerId), true); // We check every time in case the target is deleted after being targeted
if (targetPlayer == null) {
CommandHandler.sendMessage(player, translate("commands.execution.player_exist_offline_error"));
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return;
}
} else {
@ -210,12 +209,29 @@ public final class CommandMap {
Account account = player.getAccount();
if (player != targetPlayer) { // Additional permission required for targeting another player
if (!permissionNodeTargeted.isEmpty() && !account.hasPermission(permissionNodeTargeted)) {
CommandHandler.sendMessage(player, translate("commands.generic.permission_error"));
CommandHandler.sendTranslatedMessage(player, "commands.generic.permission_error");
return;
}
}
if (!permissionNode.isEmpty() && !account.hasPermission(permissionNode)) {
CommandHandler.sendMessage(player, translate("commands.generic.permission_error"));
CommandHandler.sendTranslatedMessage(player, "commands.generic.permission_error");
return;
}
}
// Check if command has unfulfilled constraints on targetPlayer
Command.TargetRequirement targetRequirement = this.annotations.get(label).targetRequirement();
if (targetRequirement != Command.TargetRequirement.NONE) {
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.need_target");
return;
}
if ((targetRequirement == Command.TargetRequirement.ONLINE) && !targetPlayer.isOnline()) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.need_target_online");
return;
}
if ((targetRequirement == Command.TargetRequirement.OFFLINE) && targetPlayer.isOnline()) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.need_target_offline");
return;
}
}

View File

@ -11,7 +11,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "account", usage = "account <create|delete> <username> [uid]", description = "commands.account.description")
@Command(label = "account", usage = "account <create|delete> <username> [uid]", description = "commands.account.description", targetRequirement = Command.TargetRequirement.NONE)
public final class AccountCommand implements CommandHandler {
@Override

View File

@ -9,7 +9,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "broadcast", usage = "broadcast <message>", aliases = {"b"}, permission = "server.broadcast", description = "commands.broadcast.description")
@Command(label = "broadcast", usage = "broadcast <message>", aliases = {"b"}, permission = "server.broadcast", description = "commands.broadcast.description", targetRequirement = Command.TargetRequirement.NONE)
public final class BroadcastCommand implements CommandHandler {
@Override

View File

@ -13,11 +13,6 @@ public final class ChangeSceneCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() != 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.usage"));
return;

View File

@ -20,10 +20,6 @@ public final class ClearCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.command_usage"));
return;

View File

@ -14,11 +14,6 @@ public final class CoopCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
Player host = sender;
switch (args.size()) {
case 0: // Summon target to self

View File

@ -18,11 +18,6 @@ public final class DropCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(null, translate(sender, "commands.execution.need_target"));
return;
}
int item = 0;
int amount = 1;

View File

@ -13,11 +13,6 @@ public final class EnterDungeonCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(null, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.usage"));
return;

View File

@ -20,10 +20,6 @@ public final class GiveAllCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
int amount = 99999;
switch (args.size()) {

View File

@ -113,11 +113,7 @@ public final class GiveArtifactCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
// Sanity checks
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
// Sanity check
if (args.size() < 2) {
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.usage"));
return;

View File

@ -17,11 +17,6 @@ public final class GiveCharCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
int avatarId;
int level = 1;

View File

@ -33,10 +33,6 @@ public final class GiveCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
int item;
int lvl = 1;
int amount = 1;

View File

@ -13,11 +13,6 @@ public final class GodModeCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
boolean enabled = !targetPlayer.inGodmode();
if (args.size() == 1) {
switch (args.get(0).toLowerCase()) {

View File

@ -16,11 +16,6 @@ public final class HealCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
targetPlayer.getTeamManager().getActiveTeam().forEach(entity -> {
boolean isAlive = entity.isAlive();
entity.setFightProperty(

View File

@ -10,7 +10,7 @@ import java.util.*;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "help", usage = "help [command]", description = "commands.help.description")
@Command(label = "help", usage = "help [command]", description = "commands.help.description", targetRequirement = Command.TargetRequirement.NONE)
public final class HelpCommand implements CommandHandler {
@Override

View File

@ -13,11 +13,6 @@ public final class KickCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (sender != null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player",
Integer.toString(sender.getAccount().getPlayerUid()), sender.getAccount().getUsername(),

View File

@ -17,11 +17,6 @@ public final class KillAllCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
Scene scene = targetPlayer.getScene();
try {
switch (args.size()) {

View File

@ -18,11 +18,6 @@ public final class KillCharacterCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
// Packets

View File

@ -13,7 +13,7 @@ import java.util.Locale;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "language", usage = "language [language code]", description = "commands.language.description", aliases = {"lang"})
@Command(label = "language", usage = "language [language code]", description = "commands.language.description", aliases = {"lang"}, targetRequirement = Command.TargetRequirement.NONE)
public final class LanguageCommand implements CommandHandler {
@Override

View File

@ -10,7 +10,7 @@ import java.util.Map;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "list", usage = "list [uid]", aliases = {"players"}, description = "commands.list.description")
@Command(label = "list", usage = "list [uid]", aliases = {"players"}, description = "commands.list.description", targetRequirement = Command.TargetRequirement.NONE)
public final class ListCommand implements CommandHandler {
@Override

View File

@ -15,12 +15,6 @@ public final class NoStaminaCommand implements CommandHandler {
//Temp Value
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() == 1) {
switch (args.get(0).toLowerCase()) {
case "on":

View File

@ -15,11 +15,6 @@ public final class PermissionCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() != 2) {
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.usage"));
return;

View File

@ -14,11 +14,6 @@ public final class PositionCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
Position pos = targetPlayer.getPos();
CommandHandler.sendMessage(sender, translate(sender, "commands.position.success",
Float.toString(pos.getX()), Float.toString(pos.getY()), Float.toString(pos.getZ()),

View File

@ -15,11 +15,6 @@ public final class QuestCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() != 2) {
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.usage"));
return;

View File

@ -9,7 +9,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "reload", usage = "reload", permission = "server.reload", description = "commands.reload.description")
@Command(label = "reload", usage = "reload", permission = "server.reload", description = "commands.reload.description", targetRequirement = Command.TargetRequirement.NONE)
public final class ReloadCommand implements CommandHandler {
@Override

View File

@ -16,11 +16,6 @@ public final class ResetConstCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() > 0 && args.get(0).equalsIgnoreCase("all")) {
targetPlayer.getAvatars().forEach(this::resetConstellation);
CommandHandler.sendMessage(sender, translate(sender, "commands.resetConst.reset_all"));

View File

@ -14,11 +14,6 @@ public final class ResetShopLimitCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.isEmpty()) {
CommandHandler.sendMessage(sender, translate(sender, "commands.resetShopLimit.usage"));
return;

View File

@ -8,7 +8,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "restart", usage = "restart", description = "commands.restart.description")
@Command(label = "restart", usage = "restart", description = "commands.restart.description", targetRequirement = Command.TargetRequirement.NONE)
public final class RestartCommand implements CommandHandler {
@Override

View File

@ -13,7 +13,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings("ConstantConditions")
@Command(label = "sendmail", usage = "sendmail <userId|all|help> [templateId]", permission = "server.sendmail", description = "commands.sendMail.description")
@Command(label = "sendmail", usage = "sendmail <userId|all|help> [templateId]", permission = "server.sendmail", description = "commands.sendMail.description", targetRequirement = Command.TargetRequirement.NONE)
public final class SendMailCommand implements CommandHandler {
// TODO: You should be able to do /sendmail and then just send subsequent messages until you finish

View File

@ -14,10 +14,6 @@ public final class SendMessageCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() == 0) {
CommandHandler.sendMessage(null, translate(sender, "commands.sendMessage.usage"));
return;

View File

@ -17,11 +17,6 @@ public final class SetFetterLevelCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() != 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.usage"));
return;

View File

@ -180,11 +180,6 @@ public final class SetStatsCommand implements CommandHandler {
String statStr;
String valueStr;
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() == 2) {
statStr = args.get(0).toLowerCase();
valueStr = args.get(1);

View File

@ -15,11 +15,6 @@ public final class SetWorldLevelCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.usage"));
return;

View File

@ -27,11 +27,6 @@ public final class SpawnCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
int id = 0; // This is just to shut up the linter, it's not a real default
int amount = 1;
int level = 1;

View File

@ -9,14 +9,14 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "stop", usage = "stop", permission = "server.stop", description = "commands.stop.description")
@Command(label = "stop", usage = "stop", permission = "server.stop", description = "commands.stop.description", targetRequirement = Command.TargetRequirement.NONE)
public final class StopCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
CommandHandler.sendMessage(null, translate(sender, "commands.stop.success"));
CommandHandler.sendMessage(null, translate("commands.stop.success"));
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
CommandHandler.sendMessage(p, translate(sender, "commands.stop.success"));
CommandHandler.sendMessage(p, translate(p, "commands.stop.success"));
}
System.exit(1000);

View File

@ -45,11 +45,6 @@ public final class TalentCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.size() < 1){
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));

View File

@ -21,11 +21,6 @@ public final class TeamCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (args.isEmpty()) {
CommandHandler.sendMessage(sender, translate(sender, "commands.team.usage"));
return;

View File

@ -15,11 +15,6 @@ public final class TeleportAllCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
if (!targetPlayer.getWorld().isMultiplayer()) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.error"));
return;

View File

@ -26,11 +26,6 @@ public final class TeleportCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
Position pos = targetPlayer.getPos();
float x = pos.getX();
float y = pos.getY();

View File

@ -15,10 +15,10 @@ public class UnlockTowerCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
unlockFloor(sender, sender.getServer().getTowerScheduleManager()
unlockFloor(targetPlayer, targetPlayer.getServer().getTowerScheduleManager()
.getCurrentTowerScheduleData().getEntranceFloorId());
unlockFloor(sender, sender.getServer().getTowerScheduleManager()
unlockFloor(targetPlayer, targetPlayer.getServer().getTowerScheduleManager()
.getScheduleFloors());
CommandHandler.sendMessage(sender, translate(sender, "commands.unlocktower.success"));

View File

@ -16,11 +16,6 @@ public final class WeatherCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.need_target"));
return;
}
int weatherId = 0;
int climateId = 1;
switch (args.size()) {

View File

@ -88,7 +88,11 @@
"argument_error": "Invalid arguments.",
"clear_target": "Target cleared.",
"set_target": "Subsequent commands will target @%s by default.",
"need_target": "This command requires a target UID. Add a <@UID> argument or set a persistent target with /target @UID."
"set_target_online": "@%s is online. Some commands may require an offline target.",
"set_target_offline": "@%s is offline. Some commands may require an online target.",
"need_target": "This command requires a target UID. Add a <@UID> argument or set a persistent target with /target @UID.",
"need_target_online": "This command requires an online target UID, but current target is offline. Add a different <@UID> argument or set a persistent target with /target @UID.",
"need_target_offline": "This command requires an offline target UID, but current target is online. Add a different <@UID> argument or set a persistent target with /target @UID."
},
"status": {
"enabled": "Enabled",

View File

@ -83,7 +83,11 @@
"argument_error": "Błędne argumenty.",
"clear_target": "Cel wyczyszczony.",
"set_target": "Następne komendy będą celować w @%s.",
"need_target": "Ta komenda wymaga docelowego UID. Dodaj argument <@UID> lub ustaw stały cel poleceniem /target @UID."
"set_target_online": "@%s jest online. Niektóre polecenia mogą wymagać celu offline.",
"set_target_offline": "@%s jest offline. Niektóre polecenia mogą wymagać celu online.",
"need_target": "Ta komenda wymaga docelowego UID. Dodaj argument <@UID> lub ustaw stały cel poleceniem /target @UID.",
"need_target_online": "To polecenie wymaga identyfikatora UID celu w trybie online, ale bieżący cel jest w trybie offline. Dodaj inny argument <@UID> lub ustaw trwały cel za pomocą /target @UID.",
"need_target_offline": "To polecenie wymaga identyfikatora UID celu offline, ale bieżący cel jest online. Dodaj inny argument <@UID> lub ustaw trwały cel za pomocą /target @UID."
},
"status": {
"enabled": "Włączone",

View File

@ -88,7 +88,11 @@
"argument_error": "无效的参数。",
"clear_target": "目标已清除。",
"set_target": "随后的的命令都会以 @%s 为预设。",
"need_target": "此命令需要一个目标 UID。添加 <@UID> 参数或使用 /target @UID 来指定默认目标。"
"set_target_online": "@%s 在线。 某些命令可能需要离线目标。",
"set_target_offline": "@%s 离线。 某些命令可能需要在线目标。",
"need_target": "此命令需要一个目标 UID。添加 <@UID> 参数或使用 /target @UID 来指定默认目标。",
"need_target_online": "此命令需要在线目标 UID但当前目标离线。 添加不同的 <@UID> 参数或使用 /target @UID 设置持久目标。",
"need_target_offline": "此命令需要离线目标 UID但当前目标在线。 添加不同的 <@UID> 参数或使用 /target @UID 设置持久目标。"
},
"status": {
"enabled": "已启用",

View File

@ -87,7 +87,11 @@
"argument_error": "無效的參數。",
"clear_target": "目標已清除.",
"set_target": "隨後的指令都會以@%s為預設。",
"need_target": "此指令需要一個目標 UID。添加 <@UID> 引數或者使用 /target @UID 來設定持久目標。"
"set_target_online": "@%s 在線。 某些命令可能需要離線目標。",
"set_target_offline": "@%s 離線。 某些命令可能需要在線目標。",
"need_target": "此指令需要一個目標 UID。添加 <@UID> 引數或者使用 /target @UID 來設定持久目標。",
"need_target_online": "此命令需要在線目標 UID但當前目標離線。 添加不同的 <@UID> 參數或使用 /target @UID 設置持久目標。",
"need_target_offline": "此命令需要離線目標 UID但當前目標在線。 添加不同的 <@UID> 參數或使用 /target @UID 設置持久目標。"
},
"status": {
"enabled": "已啟用",