Skip to content
Snippets Groups Projects
Commit 6fd1ce81 authored by AnimeGitB's avatar AnimeGitB Committed by Melledy
Browse files

Remove Drop, ChangeScene, Restart, Broadcast commands

parent bb372011
Branches
Tags
No related merge requests found
Showing
with 107 additions and 312 deletions
......@@ -109,6 +109,79 @@ public final class CommandMap {
return this.commands.get(label);
}
private Player getTargetPlayer(String playerId, Player player, Player targetPlayer, List<String> args) {
// Top priority: If any @UID argument is present, override targetPlayer with it.
for (int i = 0; i < args.size(); i++) {
String arg = args.get(i);
if (arg.startsWith("@")) {
arg = args.remove(i).substring(1);
if (arg.equals("")) {
// This is a special case to target nothing, distinct from failing to assign a target.
// This is specifically to allow in-game players to run a command without targeting themselves or anyone else.
return null;
}
try {
int uid = Integer.parseInt(arg);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
throw new IllegalArgumentException();
}
return targetPlayer;
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
throw new IllegalArgumentException();
}
}
}
// Next priority: If we invoked with a target, use that.
// By default, this only happens when you message another player in-game with a command.
if (targetPlayer != null) {
return targetPlayer;
}
// Next priority: Use previously-set target. (see /target [[@]UID])
if (targetPlayerIds.containsKey(playerId)) {
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.sendTranslatedMessage(player, "commands.execution.player_exist_error");
throw new IllegalArgumentException();
}
return targetPlayer;
}
// Lowest priority: Target the player invoking the command. In the case of the console, this will return null.
return player;
}
private boolean setPlayerTarget(String playerId, Player player, String targetUid) {
if (targetUid.equals("")) { // Clears the default targetPlayer.
targetPlayerIds.remove(playerId);
CommandHandler.sendTranslatedMessage(player, "commands.execution.clear_target");
return true;
}
// Sets default targetPlayer to the UID provided.
try {
int uid = Integer.parseInt(targetUid);
Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return false;
}
targetPlayerIds.put(playerId, uid);
CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", targetUid);
CommandHandler.sendTranslatedMessage(player, targetPlayer.isOnline()? "commands.execution.set_target_online" : "commands.execution.set_target_offline", targetUid);
return true;
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
return false;
}
}
/**
* Invoke a command handler with the given arguments.
*
......@@ -129,39 +202,21 @@ public final class CommandMap {
String playerId = (player == null) ? consoleId : player.getAccount().getId();
// Check for special cases - currently only target command.
String targetUidStr = null;
if (label.startsWith("@")) { // @[UID]
targetUidStr = label.substring(1);
this.setPlayerTarget(playerId, player, label.substring(1));
return;
} else if (label.equalsIgnoreCase("target")) { // target [[@]UID]
if (args.size() > 0) {
targetUidStr = args.get(0);
String targetUidStr = args.get(0);
if (targetUidStr.startsWith("@")) {
targetUidStr = targetUidStr.substring(1);
}
this.setPlayerTarget(playerId, player, targetUidStr);
return;
} else {
targetUidStr = "";
}
}
if (targetUidStr != null) {
if (targetUidStr.equals("")) { // Clears the default targetPlayer.
this.targetPlayerIds.remove(playerId);
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, true);
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
} else {
this.targetPlayerIds.put(playerId, uid);
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.sendTranslatedMessage(player, "commands.generic.invalid.uid");
}
this.setPlayerTarget(playerId, player, "");
return;
}
return;
}
// Get command handler.
......@@ -179,38 +234,11 @@ public final class CommandMap {
// Get the command's annotation.
Command annotation = this.annotations.get(label);
// If any @UID argument is present, override targetPlayer with it.
for (int i = 0; i < args.size(); i++) {
String arg = args.get(i);
if (arg.startsWith("@")) {
arg = args.remove(i).substring(1);
try {
int uid = Integer.parseInt(arg);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return;
}
break;
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(player, "commands.generic.invalid.uid");
return;
}
}
}
// If there's still no targetPlayer at this point, use previously-set target
if (targetPlayer == null) {
if (this.targetPlayerIds.containsKey(playerId)) {
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(this.targetPlayerIds.get(playerId), true); // We check every time in case the target is deleted after being targeted
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return;
}
} else {
// If there's still no targetPlayer at this point, use executor.
targetPlayer = player;
}
// Resolve targetPlayer
try{
targetPlayer = getTargetPlayer(playerId, player, targetPlayer, args);
} catch (IllegalArgumentException e) {
return;
}
// Check for permissions.
......
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
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", targetRequirement = Command.TargetRequirement.NONE)
public final class BroadcastCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.command_usage"));
return;
}
String message = String.join(" ", args.subList(0, args.size()));
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
CommandHandler.sendMessage(p, message);
}
CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.message_sent"));
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "changescene", usage = "changescene <sceneId>", aliases = {"scene"}, permission = "player.changescene", permissionTargeted = "player.changescene.others", description = "commands.changescene.description")
public final class ChangeSceneCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() != 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.usage"));
return;
}
try {
int sceneId = Integer.parseInt(args.get(0));
if (sceneId == targetPlayer.getSceneId()) {
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.already_in_scene"));
return;
}
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, targetPlayer.getPos());
if (!result) {
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.exists_error"));
return;
}
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.success", Integer.toString(sceneId)));
} catch (Exception e) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
}
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Position;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "drop", usage = "drop <itemId|itemName> [amount]", aliases = {"d", "dropitem"}, permission = "server.drop", permissionTargeted = "server.drop.others", description = "commands.drop.description")
public final class DropCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
int item = 0;
int amount = 1;
switch (args.size()) {
case 2:
try {
amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
return;
} // Slightly cheeky here: no break, so it falls through to initialize the first argument too
case 1:
try {
item = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
return;
}
break;
default:
CommandHandler.sendMessage(sender, translate(sender, "commands.drop.command_usage"));
return;
}
ItemData itemData = GameData.getItemDataMap().get(item);
if (itemData == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
return;
}
if (itemData.isEquip()) {
float range = (5f + (.1f * amount));
for (int i = 0; i < amount; i++) {
Position pos = targetPlayer.getPos().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f).addZ((float) (Math.random() * range) - (range / 2));
EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, pos, 1);
targetPlayer.getScene().addEntity(entity);
}
} else {
EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, targetPlayer.getPos().clone().addY(3f), amount);
targetPlayer.getScene().addEntity(entity);
}
CommandHandler.sendMessage(sender, translate(sender, "commands.drop.success", Integer.toString(amount), Integer.toString(item)));
}
}
......@@ -8,15 +8,15 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "kick", usage = "kick", permission = "server.kick", description = "commands.kick.description")
@Command(label = "kick", usage = "kick", aliases = {"restart"}, permissionTargeted = "server.kick", description = "commands.kick.description")
public final class KickCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (sender != null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player",
Integer.toString(sender.getUid()), sender.getAccount().getUsername(),
Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player",
Integer.toString(sender.getUid()), sender.getAccount().getUsername(),
Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
} else {
CommandHandler.sendMessage(null, translate(sender, "commands.kick.server_kick_player", Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
}
......
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "restart", usage = "restart", description = "commands.restart.description", targetRequirement = Command.TargetRequirement.NONE)
public final class RestartCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (sender == null) {
return;
}
sender.getSession().close();
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.Command.TargetRequirement;
import emu.grasscutter.game.player.Player;
import java.util.List;
......@@ -9,7 +11,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "sendmessage", usage = "sendmessage <message>",
aliases = {"say", "sendservmsg", "sendservermessage"}, permission = "server.sendmessage", permissionTargeted = "server.sendmessage.others", description = "commands.sendMessage.description")
aliases = {"say", "sendservmsg", "sendservermessage", "b", "broadcast"}, permission = "server.sendmessage", permissionTargeted = "server.sendmessage.others", description = "commands.sendMessage.description", targetRequirement = TargetRequirement.NONE)
public final class SendMessageCommand implements CommandHandler {
@Override
......@@ -20,7 +22,14 @@ public final class SendMessageCommand implements CommandHandler {
}
String message = String.join(" ", args);
CommandHandler.sendMessage(targetPlayer, message);
if (targetPlayer == null) {
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
CommandHandler.sendMessage(p, message);
}
} else {
CommandHandler.sendMessage(targetPlayer, message);
}
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMessage.success"));
}
}
......@@ -23,7 +23,7 @@ import java.util.Random;
import static emu.grasscutter.Configuration.*;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "spawn", usage = "spawn <entityId> [amount] [level(monster only)] [<x> <y> <z>(monster only, optional)]", permission = "server.spawn", permissionTargeted = "server.spawn.others", description = "commands.spawn.description")
@Command(label = "spawn", usage = "spawn <entityId> [amount] [level(monster only)] [<x> <y> <z>(monster only, optional)]", aliases = {"drop"}, permission = "server.spawn", permissionTargeted = "server.spawn.others", description = "commands.spawn.description")
public final class SpawnCommand implements CommandHandler {
@Override
......
......@@ -56,7 +56,7 @@ public final class TeleportCommand implements CommandHandler {
Position target_pos = new Position(x, y, z);
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos);
if (!result) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));
} else {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success",
targetPlayer.getNickname(), Float.toString(x), Float.toString(y),
......
......@@ -109,18 +109,6 @@
"no_account": "Account not found.",
"description": "Modify user accounts"
},
"broadcast": {
"command_usage": "Usage: broadcast <message>",
"message_sent": "Message sent.",
"description": "Sends a message to all the players"
},
"changescene": {
"usage": "Usage: changescene <sceneID>",
"already_in_scene": "You are already in that scene.",
"success": "Changed to scene %s.",
"exists_error": "The specified scene does not exist.",
"description": "Changes your scene"
},
"clear": {
"command_usage": "Usage: clear <all|wp|art|mat>",
"weapons": "Cleared weapons for %s.",
......@@ -137,11 +125,6 @@
"success": "Summoned %s to %s's world.",
"description": "Forces someone to join the world of others. If no one is targeted, it sends you into co-op mode anyway."
},
"drop": {
"command_usage": "Usage: drop <itemID|itemName> [amount]",
"success": "Dropped %s of %s.",
"description": "Drops an item near you"
},
"enter_dungeon": {
"usage": "Usage: enterdungeon <dungeonID>",
"changed": "Changed to dungeon %s.",
......@@ -259,9 +242,6 @@
"success": "Reset complete.",
"description": "Reset target player's shop refresh time"
},
"restart": {
"description": "Restarts the current session"
},
"sendMail": {
"usage": "Usage: sendmail <userID|all|help> [templateID]",
"user_not_exist": "The user with an ID of '%s' does not exist.",
......@@ -371,6 +351,7 @@
"usage": "Usage: tp [@<playerID>] <x> <y> <z> [sceneID]",
"specify_player_id": "You must specify a player ID.",
"invalid_position": "Invalid position.",
"exists_error": "The specified scene does not exist.",
"success": "Teleported %s to %s, %s, %s in scene %s.",
"description": "Change the player's position"
},
......
......@@ -110,18 +110,6 @@
"command_usage": "Utilisation: account <create|delete> <nom_d'utilisateur> [UID]",
"description": "Modifie les comptes utilisateurs"
},
"broadcast": {
"command_usage": "Usage: broadcast <message>",
"message_sent": "Message envoyé.",
"description": "Envoie un message a tous les joueurs"
},
"changescene": {
"usage": "Usage: changescene <sceneID>",
"already_in_scene": "Vous êtes déjà dans cette scène.",
"success": "Nouvelle scène : %s.",
"exists_error": "La scène spécifié n'existe pas.",
"description": "Change votre scène"
},
"clear": {
"command_usage": "Usage: clear <all|wp|art|mat>",
"weapons": "Les armes de %s ont été supprimés.",
......@@ -138,11 +126,6 @@
"success": "%s est apparu dans de monde de %s.",
"description": "Force quelqu'un a rejoindre le monde d'un autre. Si personne n'est ciblé, vous envoie quand même en mode multijoueur."
},
"drop": {
"command_usage": "Usage: drop <itemID|itemName> [quantité]",
"success": " %s %s ont été jetés.",
"description": "Jette un objet près de vous"
},
"enter_dungeon": {
"usage": "Usage: enterdungeon <dungeonID>",
"changed": "Entré dans le donjon %s.",
......@@ -260,9 +243,6 @@
"success": "Réinitialisation terminée.",
"description": "Réinitialise le temps d'actualisation de la boutique du joueur spécifié"
},
"restart": {
"description": "Redémare la session actuelle"
},
"sendMail": {
"usage": "Usage: sendmail <userID|all|help> [templateID]",
"user_not_exist": "L'utilisateur avec l'identifiant '%s' n'existe pas.",
......@@ -372,6 +352,7 @@
"usage": "Utilisation: tp [@<playerID>] <x> <y> <z> [sceneID]",
"specify_player_id": "Vous devez spécifier un ID d'utilisateur.",
"invalid_position": "Position invalide.",
"exists_error": "La scène spécifié n'existe pas.",
"success": "%s a été téléporté à %s, %s, %s dans la scène %s.",
"description": "Change la position du joueur"
},
......
......@@ -103,16 +103,6 @@
"no_account": "Nie znaleziono konta.",
"command_usage": "Użycie: account <create|delete> <nazwa> [uid]"
},
"broadcast": {
"command_usage": "Użycie: broadcast <wiadomość>",
"message_sent": "Wiadomość wysłana."
},
"changescene": {
"usage": "Użycie: changescene <id sceny>",
"already_in_scene": "Już jesteś na tej scenie.",
"success": "Zmieniono scene na %s.",
"exists_error": "Ta scena nie istenieje."
},
"clear": {
"command_usage": "Użycie: clear <all|wp|art|mat>",
"weapons": "Wyczyszczono bronie dla %s.",
......@@ -286,6 +276,7 @@
"usage": "Użycie: /tp [@<ID gracza>] <x> <y> <z> [ID sceny]",
"specify_player_id": "Musisz określić ID gracza.",
"invalid_position": "Błędna pozycja.",
"exists_error": "Ta scena nie istenieje.",
"success": "Przeteleportowano %s do %s, %s, %s w scenie %s"
},
"weather": {
......@@ -294,10 +285,6 @@
"success": "Set weather ID to %s with climate type %s.",
"status": "Current weather ID is %s with climate type %s."
},
"drop": {
"command_usage": "Użycie: drop <ID przedmiotu|nazwa przedmiotu> [ilość]",
"success": "Wyrzucono %s of %s."
},
"help": {
"usage": "Użycie: ",
"aliases": "Aliasy: ",
......
......@@ -109,18 +109,6 @@
"no_account": "账号不存在。",
"description": "创建或删除账号"
},
"broadcast": {
"command_usage": "用法:broadcast <消息>",
"message_sent": "公告已发送。",
"description": "向所有玩家发送公告"
},
"changescene": {
"usage": "用法:changescene <场景ID>",
"already_in_scene": "你已经在这个场景中了。",
"success": "已切换至场景 %s。",
"exists_error": "场景不存在。",
"description": "切换指定场景"
},
"clear": {
"command_usage": "用法:clear <all|wp|art|mat>\nall: 所有, wp: 武器, art: 圣遗物, mat: 材料",
"weapons": "已清除 %s 的武器。",
......@@ -137,11 +125,6 @@
"success": "已强制传送 %s 到 %s 的世界。",
"description": "强制传送指定玩家到他人的世界。如果没有指定玩家,则会使你进入多人游戏状态"
},
"drop": {
"command_usage": "用法:drop <物品ID|物品名称> [数量]",
"success": "已丢下 %s 个 %s。",
"description": "在你附近丢下物品"
},
"enter_dungeon": {
"usage": "用法:enterdungeon <秘境ID>",
"changed": "已进入秘境 %s。",
......@@ -259,9 +242,6 @@
"success": "重置完成。",
"description": "重置指定玩家的商店刷新时间"
},
"restart": {
"description": "重新启动服务器"
},
"sendMail": {
"usage": "用法:sendmail <用户ID|all|help> [模板ID]",
"user_not_exist": "用户 '%s' 不存在。",
......@@ -371,6 +351,7 @@
"usage": "用法:tp [@<玩家ID>] <x> <y> <z> [场景ID]",
"specify_player_id": "你必须指定一个玩家ID。",
"invalid_position": "无效的位置。",
"exists_error": "此场景不存在。",
"success": "传送 %s 到坐标 %s, %s, %s,场景为 %s。",
"description": "改变指定玩家的位置"
},
......
......@@ -108,18 +108,6 @@
"command_usage": "用法:account <create|delete> <username> [uid]",
"description": "建立或刪除帳號。"
},
"broadcast": {
"command_usage": "用法:broadcast <message>",
"message_sent": "公告已發送。",
"description": "向所有玩家發送公告。"
},
"changescene": {
"usage": "用法:changescene <scene id>",
"already_in_scene": "你已經在這個場景中了。",
"success": "已切換至場景 %s.",
"exists_error": "此場景不存在。",
"description": "切換指定場景。"
},
"clear": {
"command_usage": "用法: clear <all|wp|art|mat>",
"weapons": "已將 %s 的武器清空。",
......@@ -136,11 +124,6 @@
"success": "召喚了 %s 到 %s 的世界。",
"description": "強制傳送指定用戶到他人的世界。如果未指定玩家,則會將你設為多人遊戲狀態。"
},
"drop": {
"command_usage": "用法:drop <itemId|itemName> [amount]",
"success": "已將 %s x %s 丟在附近。",
"description": "在你附近丟下一個物品。"
},
"enter_dungeon": {
"usage": "用法:enterdungeon <dungeon id>",
"changed": "已進入祕境 %s",
......@@ -263,9 +246,6 @@
"success": "重置完成。",
"description": "重置所選玩家的商店刷新時間。"
},
"restart": {
"description": "重新啟動伺服器。"
},
"sendMail": {
"usage": "用法:sendmail <userId|all|help> [templateId]",
"user_not_exist": "ID '%s' 的使用者不存在。",
......@@ -374,6 +354,7 @@
"usage": "用法:tp [@<playerId>] <x> <y> <z> [sceneId]",
"specify_player_id": "你必須指定一個玩家ID。",
"invalid_position": "無效的座標。",
"exists_error": "此場景不存在。",
"success": "傳送 %s 到座標 %s,%s,%s ,場景為 %s 。",
"description": "將玩家的位置傳送到你所指定的座標。"
},
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment