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 fa0344d1f9
commit 0ae3c3d7da
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` 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 | ### 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.
| 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. | | 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.
| broadcast | broadcast \<message> | server.broadcast | Both side | Sends a message to all the players. | b | 3. If none of the above, it will default to a persistent target player you previously set using the command `/target <UID>`.
| coop | coop \<playerId> \<target playerId> | server.coop | Both side | Forces someone to join the world of others. | | 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!**
| 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 | 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.
| 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 | | | Commands | Description | Alias | Targeting | Usage | Permission node |
| 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 | | account | Creates an account with the specified username, and the in-game UID if specified. | | Server only | account \<create\|delete> \<username> [UID] | |
| giveart | giveart [player] \<artifactId> \<mainPropId> [\<appendPropId>[,\<times>]]... [level] | player.giveart | Both side | Gives the player a specified artifact. | gart | | broadcast | Sends a message to all the players. | b | None | broadcast \<message> | server.broadcast |
| giveall | giveall [uid] [amount] | player.giveall | Both side | Gives all items. | givea | | coop | Forces someone to join the world of others. | | Online Player | coop [host UID (default self)] | server.coop |
| godmode | godmode [uid] | player.godmode | Client only | Prevents you from taking damage. | | | changescene | Switch scenes by scene ID. | scene | Online Player | changescene \<scene id> | player.changescene |
| heal | heal | player.heal | Client only | Heals all characters in your current team. | h | | clear | Deletes all unequipped and unlocked lvl0 artifacts(art)/weapons(wp)/material(mat) from inventory. | | Online Player | clear \<all\|wp\|art\|mat> | player.clearinv |
| help | help [command] | | Both side | Sends the help message or shows information about a specified command. | | | drop | Drops an item around you. | d dropitem | Online Player | drop \<itemID\|itemName> [amount] | server.drop |
| join | join [avatarIds] | player.join | Client only | Force let avatars to join into your current team. Such as `join 10000020 10000021`. | | | enterdungeon | Enter a dungeon by dungeon ID. | | Online Player | enterdungeon \<dungeon id> | player.enterdungeon |
| kick | kick \<player> | server.kick | Both side | Kicks the specified player from the server. (WIP) | k | | give | Gives item(s) to you or the specified player. | g item giveitem | Online Player | give \<itemId\|itemName> [amount] [level] [refinement] | player.give |
| killall | killall [playerUid] [sceneId] | server.killall | Both side | Kills all entities in the current scene or specified scene of the corresponding player. | | | giveall | Gives all items. | givea | Online Player | giveall [amount] | player.giveall |
| list | list | | Both side | Lists online players. | | | giveart | Gives the player a specified artifact. | gart | Online Player | giveart \<artifactId> \<mainPropId> [\<appendPropId>[,\<times>]]... [level] | player.giveart |
| permission | permission <add\|remove> \<UID> \<permission> | permission | Both side | Grants or removes a permission for a user. | | | givechar | Gives the player a specified character. | givec | Online Player | givechar \<avatarId> | player.givechar |
| position | position | | Client only | Sends your current coordinates. | pos | | godmode | Prevents you from taking damage. | | Online Player | godmode | player.godmode |
| reload | reload | server.reload | Both side | Reloads the server config | | | heal | Heals all characters in your current team. | h | Online Player | heal | player.heal |
| remove | remove [avatarIndexInYourTeams] | player.remove | Client only | Force remove avatar in your current team. Index start from 1.Such as `remove 1 2`. | | | help | Sends the help message or shows information about a specified command. | | None | help [command] | |
| 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 | | kick | Kicks the specified player from the server. | k | Online Player | kick | server.kick |
| restart | | | Both side | Restarts the current session | | | killall | Kills all entities in the current scene or specified scene of the corresponding player. | | Online Player | killall [sceneId] | server.killall |
| say | say \<player> \<message> | server.sendmessage | Both side | Sends a message to a player as the server | `sendservmsg` `sendservermessage` `sendmessage` | | list | Lists online players. | | None | list | |
| setfetterlevel | setfetterlevel \<level> | player.setfetterlevel | Client only | Sets the friendship level for your currently selected character | setfetterlvl | | permission | Grants or removes a permission for a user. | | Online Player | permission \<add\|remove> \<permission> | permission |
| setstats | setstats \<stat> \<value> | player.setstats | Client only | Sets a stat for your currently selected character | stats | | position | Sends your current coordinates. | pos | Online Player | position | |
| setworldlevel | setworldlevel \<level> | player.setworldlevel | Client only | Sets your world level (Relog to see proper effects) | setworldlvl | | reload | Reloads the server config. | | None | reload | server.reload |
| spawn | spawn \<entityId> [amount] [level(monster only)] | server.spawn | Client only | Spawns some entities around you | | | resetconst | Resets currently selected (or all) character(s) to C0. Relog to see proper effects. | resetconstellation | Online Player | resetconst [all] | player.resetconstellation |
| stop | stop | server.stop | Both side | Stops the server | | | restart | Restarts the current session. | | None | restart | |
| talent | talent \<talentID> \<value> | player.settalent | Client only | Sets talent level for your currently selected character | | | sendmessage | Sends a message to a player as the server. | say | Online Player | say \<message> | server.sendmessage |
| teleport | teleport [@playerUid] \<x> \<y> \<z> [sceneId] | player.teleport | Both side | Change the player's position. | tp | | setfetterlevel | Sets the friendship level for your currently selected character. | setfetterlvl | Online Player | setfetterlevel \<level> | player.setfetterlevel |
| tpall | | player.tpall | Client only | Teleports all players in your world to your position | | | setstats | Sets a stat for your currently selected character. | stats | Online Player | setstats \<stat> \<value> | player.setstats |
| unlocktower | | player.tower | Client only | Unlock the all floors of abyss | ut | | setworldlevel | Sets your world level. Relog to see proper effects. | setworldlvl | Online Player | setworldlevel \<level> | player.setworldlevel |
| weather | weather \<weatherID> \<climateID> | player.weather | Client only | Changes the weather | w | | 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 ### Bonus

View File

@ -17,5 +17,13 @@ public @interface Command {
String permissionTargeted() default ""; 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; boolean threading() default false;
} }

View File

@ -4,6 +4,7 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.game.CommandResponseEvent; import emu.grasscutter.server.event.game.CommandResponseEvent;
import emu.grasscutter.server.event.types.ServerEvent; import emu.grasscutter.server.event.types.ServerEvent;
import static emu.grasscutter.utils.Language.translate;
import java.util.List; import java.util.List;
@ -24,6 +25,10 @@ public interface CommandHandler {
CommandResponseEvent event = new CommandResponseEvent(ServerEvent.Type.GAME,player, message); CommandResponseEvent event = new CommandResponseEvent(ServerEvent.Type.GAME,player, message);
event.call(); 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. * Called when a player/console invokes a command.

View File

@ -8,8 +8,6 @@ import org.reflections.Reflections;
import java.util.*; import java.util.*;
import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings({"UnusedReturnValue", "unused"}) @SuppressWarnings({"UnusedReturnValue", "unused"})
public final class CommandMap { public final class CommandMap {
private final Map<String, CommandHandler> commands = new HashMap<>(); 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) { public void invoke(Player player, Player targetPlayer, String rawMessage) {
rawMessage = rawMessage.trim(); rawMessage = rawMessage.trim();
if (rawMessage.length() == 0) { if (rawMessage.length() == 0) {
CommandHandler.sendMessage(player, translate("commands.generic.not_specified")); CommandHandler.sendTranslatedMessage(player, "commands.generic.not_specified");
return; return;
} }
@ -144,19 +142,20 @@ public final class CommandMap {
if (targetUidStr != null) { if (targetUidStr != null) {
if (targetUidStr.equals("")) { // Clears the default targetPlayer. if (targetUidStr.equals("")) { // Clears the default targetPlayer.
targetPlayerIds.remove(playerId); 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. } else { // Sets default targetPlayer to the UID provided.
try { try {
int uid = Integer.parseInt(targetUidStr); int uid = Integer.parseInt(targetUidStr);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid); targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(player, translate("commands.execution.player_exist_offline_error")); CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
} else { } else {
targetPlayerIds.put(playerId, uid); 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) { } catch (NumberFormatException e) {
CommandHandler.sendMessage(player, translate("commands.execution.uid_error")); CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
} }
} }
return; return;
@ -165,7 +164,7 @@ public final class CommandMap {
// Get command handler. // Get command handler.
CommandHandler handler = this.commands.get(label); CommandHandler handler = this.commands.get(label);
if (handler == null) { if (handler == null) {
CommandHandler.sendMessage(player, translate("commands.generic.unknown_command", label)); CommandHandler.sendTranslatedMessage(player, "commands.generic.unknown_command", label);
return; return;
} }
@ -176,14 +175,14 @@ public final class CommandMap {
arg = args.remove(i).substring(1); arg = args.remove(i).substring(1);
try { try {
int uid = Integer.parseInt(arg); int uid = Integer.parseInt(arg);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid); targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(player, translate("commands.execution.player_exist_offline_error")); CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return; return;
} }
break; break;
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
CommandHandler.sendMessage(player, translate("commands.execution.uid_error")); CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
return; return;
} }
} }
@ -192,9 +191,9 @@ public final class CommandMap {
// If there's still no targetPlayer at this point, use previously-set target // If there's still no targetPlayer at this point, use previously-set target
if (targetPlayer == null) { if (targetPlayer == null) {
if (targetPlayerIds.containsKey(playerId)) { 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) { if (targetPlayer == null) {
CommandHandler.sendMessage(player, translate("commands.execution.player_exist_offline_error")); CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return; return;
} }
} else { } else {
@ -210,12 +209,29 @@ public final class CommandMap {
Account account = player.getAccount(); Account account = player.getAccount();
if (player != targetPlayer) { // Additional permission required for targeting another player if (player != targetPlayer) { // Additional permission required for targeting another player
if (!permissionNodeTargeted.isEmpty() && !account.hasPermission(permissionNodeTargeted)) { if (!permissionNodeTargeted.isEmpty() && !account.hasPermission(permissionNodeTargeted)) {
CommandHandler.sendMessage(player, translate("commands.generic.permission_error")); CommandHandler.sendTranslatedMessage(player, "commands.generic.permission_error");
return; return;
} }
} }
if (!permissionNode.isEmpty() && !account.hasPermission(permissionNode)) { 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; return;
} }
} }

View File

@ -11,7 +11,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; 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 { public final class AccountCommand implements CommandHandler {
@Override @Override

View File

@ -9,7 +9,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; 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 { public final class BroadcastCommand implements CommandHandler {
@Override @Override

View File

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

View File

@ -20,10 +20,6 @@ public final class ClearCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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) { if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.command_usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.clear.command_usage"));
return; return;

View File

@ -14,11 +14,6 @@ public final class CoopCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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; Player host = sender;
switch (args.size()) { switch (args.size()) {
case 0: // Summon target to self case 0: // Summon target to self

View File

@ -18,11 +18,6 @@ public final class DropCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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 item = 0;
int amount = 1; int amount = 1;

View File

@ -13,11 +13,6 @@ public final class EnterDungeonCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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) { if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.usage"));
return; return;

View File

@ -20,10 +20,6 @@ public final class GiveAllCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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; int amount = 99999;
switch (args.size()) { switch (args.size()) {

View File

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

View File

@ -17,11 +17,6 @@ public final class GiveCharCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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 avatarId;
int level = 1; int level = 1;

View File

@ -33,10 +33,6 @@ public final class GiveCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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 item;
int lvl = 1; int lvl = 1;
int amount = 1; int amount = 1;

View File

@ -13,11 +13,6 @@ public final class GodModeCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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(); boolean enabled = !targetPlayer.inGodmode();
if (args.size() == 1) { if (args.size() == 1) {
switch (args.get(0).toLowerCase()) { switch (args.get(0).toLowerCase()) {

View File

@ -16,11 +16,6 @@ public final class HealCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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 -> { targetPlayer.getTeamManager().getActiveTeam().forEach(entity -> {
boolean isAlive = entity.isAlive(); boolean isAlive = entity.isAlive();
entity.setFightProperty( entity.setFightProperty(

View File

@ -10,7 +10,7 @@ import java.util.*;
import static emu.grasscutter.utils.Language.translate; 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 { public final class HelpCommand implements CommandHandler {
@Override @Override

View File

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

View File

@ -17,11 +17,6 @@ public final class KillAllCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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(); Scene scene = targetPlayer.getScene();
try { try {
switch (args.size()) { switch (args.size()) {

View File

@ -18,11 +18,6 @@ public final class KillCharacterCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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(); EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f); entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
// Packets // Packets

View File

@ -13,7 +13,7 @@ import java.util.Locale;
import static emu.grasscutter.utils.Language.translate; 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 { public final class LanguageCommand implements CommandHandler {
@Override @Override

View File

@ -10,7 +10,7 @@ import java.util.Map;
import static emu.grasscutter.utils.Language.translate; 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 { public final class ListCommand implements CommandHandler {
@Override @Override

View File

@ -15,12 +15,6 @@ public final class NoStaminaCommand implements CommandHandler {
//Temp Value //Temp Value
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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) { if (args.size() == 1) {
switch (args.get(0).toLowerCase()) { switch (args.get(0).toLowerCase()) {
case "on": case "on":

View File

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

View File

@ -14,11 +14,6 @@ public final class PositionCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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(); Position pos = targetPlayer.getPos();
CommandHandler.sendMessage(sender, translate(sender, "commands.position.success", CommandHandler.sendMessage(sender, translate(sender, "commands.position.success",
Float.toString(pos.getX()), Float.toString(pos.getY()), Float.toString(pos.getZ()), 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 @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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) { if (args.size() != 2) {
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.quest.usage"));
return; return;

View File

@ -9,7 +9,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; 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 { public final class ReloadCommand implements CommandHandler {
@Override @Override

View File

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

View File

@ -14,11 +14,6 @@ public final class ResetShopLimitCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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()) { if (args.isEmpty()) {
CommandHandler.sendMessage(sender, translate(sender, "commands.resetShopLimit.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.resetShopLimit.usage"));
return; return;

View File

@ -8,7 +8,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; 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 { public final class RestartCommand implements CommandHandler {
@Override @Override

View File

@ -13,7 +13,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings("ConstantConditions") @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 { public final class SendMailCommand implements CommandHandler {
// TODO: You should be able to do /sendmail and then just send subsequent messages until you finish // 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 @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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) { if (args.size() == 0) {
CommandHandler.sendMessage(null, translate(sender, "commands.sendMessage.usage")); CommandHandler.sendMessage(null, translate(sender, "commands.sendMessage.usage"));
return; return;

View File

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

View File

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

View File

@ -15,11 +15,6 @@ public final class SetWorldLevelCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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) { if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.usage"));
return; return;

View File

@ -27,11 +27,6 @@ public final class SpawnCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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 id = 0; // This is just to shut up the linter, it's not a real default
int amount = 1; int amount = 1;
int level = 1; int level = 1;

View File

@ -9,14 +9,14 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; 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 { public final class StopCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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()) { 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); System.exit(1000);

View File

@ -45,11 +45,6 @@ public final class TalentCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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){ if (args.size() < 1){
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2")); CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));

View File

@ -21,11 +21,6 @@ public final class TeamCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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()) { if (args.isEmpty()) {
CommandHandler.sendMessage(sender, translate(sender, "commands.team.usage")); CommandHandler.sendMessage(sender, translate(sender, "commands.team.usage"));
return; return;

View File

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

View File

@ -26,11 +26,6 @@ public final class TeleportCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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(); Position pos = targetPlayer.getPos();
float x = pos.getX(); float x = pos.getX();
float y = pos.getY(); float y = pos.getY();

View File

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

View File

@ -16,11 +16,6 @@ public final class WeatherCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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 weatherId = 0;
int climateId = 1; int climateId = 1;
switch (args.size()) { switch (args.size()) {

View File

@ -88,7 +88,11 @@
"argument_error": "Invalid arguments.", "argument_error": "Invalid arguments.",
"clear_target": "Target cleared.", "clear_target": "Target cleared.",
"set_target": "Subsequent commands will target @%s by default.", "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": { "status": {
"enabled": "Enabled", "enabled": "Enabled",

View File

@ -83,7 +83,11 @@
"argument_error": "Błędne argumenty.", "argument_error": "Błędne argumenty.",
"clear_target": "Cel wyczyszczony.", "clear_target": "Cel wyczyszczony.",
"set_target": "Następne komendy będą celować w @%s.", "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": { "status": {
"enabled": "Włączone", "enabled": "Włączone",

View File

@ -88,7 +88,11 @@
"argument_error": "无效的参数。", "argument_error": "无效的参数。",
"clear_target": "目标已清除。", "clear_target": "目标已清除。",
"set_target": "随后的的命令都会以 @%s 为预设。", "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": { "status": {
"enabled": "已启用", "enabled": "已启用",

View File

@ -87,7 +87,11 @@
"argument_error": "無效的參數。", "argument_error": "無效的參數。",
"clear_target": "目標已清除.", "clear_target": "目標已清除.",
"set_target": "隨後的指令都會以@%s為預設。", "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": { "status": {
"enabled": "已啟用", "enabled": "已啟用",