Convert to the superior language system. (pt. 2)

This commit is contained in:
KingRainbow44 2022-05-06 00:57:45 -04:00
parent 023c5baffe
commit f7311968d6
No known key found for this signature in database
GPG Key ID: FC2CB64B00D257BE
44 changed files with 687 additions and 334 deletions

4
.gitignore vendored
View File

@ -64,6 +64,4 @@ mitmdump.exe
!lib/*.jar
mongod.exe
/src/generated/
/*.sh
language/
languages/
/*.sh

View File

@ -6,7 +6,6 @@ import emu.grasscutter.Grasscutter.ServerRunMode;
import emu.grasscutter.game.mail.Mail;
public final class Config {
public String DatabaseUrl = "mongodb://localhost:27017";
public String DatabaseCollection = "grasscutter";

View File

@ -8,6 +8,8 @@ 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<>();
@ -109,7 +111,7 @@ public final class CommandMap {
public void invoke(Player player, Player targetPlayer, String rawMessage) {
rawMessage = rawMessage.trim();
if (rawMessage.length() == 0) {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().No_command_specified);
CommandHandler.sendMessage(player, translate("commands.generic.not_specified"));
return;
}
@ -118,11 +120,12 @@ public final class CommandMap {
List<String> args = new LinkedList<>(Arrays.asList(split));
String label = args.remove(0);
String playerId = (player == null) ? consoleId : player.getAccount().getId();
// Check for special cases - currently only target command
// Check for special cases - currently only target command.
String targetUidStr = null;
if (label.startsWith("@")) { // @[UID]
if (label.startsWith("@")) { // @[UID]
targetUidStr = label.substring(1);
} else if (label.equalsIgnoreCase("target")) { // target [[@]UID]
} else if (label.equalsIgnoreCase("target")) { // target [[@]UID]
if (args.size() > 0) {
targetUidStr = args.get(0);
if (targetUidStr.startsWith("@")) {
@ -133,68 +136,64 @@ public final class CommandMap {
}
}
if (targetUidStr != null) {
if (targetUidStr.equals("")) { // Clears default targetPlayer
if (targetUidStr.equals("")) { // Clears the default targetPlayer.
targetPlayerIds.remove(playerId);
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Target_cleared);
return;
} else { // Sets default targetPlayer to the UID given
CommandHandler.sendMessage(player, translate("commands.execution.clear_target"));
} else { // Sets default targetPlayer to the UID provided.
try {
int uid = Integer.parseInt(targetUidStr);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid);
if (targetPlayer == null) {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Player_not_found_or_offline);
CommandHandler.sendMessage(player, translate("commands.generic.execution.player_exist_offline_error"));
} else {
targetPlayerIds.put(playerId, uid);
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Target_set.replace("{uid}", targetUidStr));
CommandHandler.sendMessage(player, translate("commands.execution.set_target", targetUidStr));
}
} catch (NumberFormatException e) {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Invalid_UID);
CommandHandler.sendMessage(player, translate("commands.execution.uid_error"));
}
return;
}
return;
}
// Get command handler.
CommandHandler handler = this.commands.get(label);
if (handler == null) {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Unknown_command + label);
CommandHandler.sendMessage(player, translate("commands.generic.unknown_command", label));
return;
}
// If any @UID argument is present, override targetPlayer with it
// 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("@")) {
continue;
} else {
if (arg.startsWith("@")) {
arg = args.remove(i).substring(1);
try {
int uid = Integer.parseInt(arg);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid);
if (targetPlayer == null) {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Player_not_found_or_offline);
CommandHandler.sendMessage(player, translate("commands.generic.execution.player_exist_offline_error"));
return;
}
break;
} catch (NumberFormatException e) {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Invalid_UID);
CommandHandler.sendMessage(player, translate("commands.execution.uid_error"));
return;
}
}
}
// 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
if (targetPlayer == null) {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Player_not_found_or_offline);
CommandHandler.sendMessage(player, translate("commands.generic.execution.player_exist_offline_error"));
return;
}
} else {
// If there's still no targetPlayer at this point, use local player
if (targetPlayer == null) {
targetPlayer = player;
}
// If there's still no targetPlayer at this point, use executor.
targetPlayer = player;
}
}
@ -205,12 +204,12 @@ 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, Grasscutter.getLanguage().You_not_permission_run_command);
CommandHandler.sendMessage(player, translate("commands.generic.permission_error"));
return;
}
}
if (!permissionNode.isEmpty() && !account.hasPermission(permissionNode)) {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().You_not_permission_run_command);
CommandHandler.sendMessage(player, translate("commands.generic.permission_error"));
return;
}
}
@ -220,10 +219,8 @@ public final class CommandMap {
final Player targetPlayerF = targetPlayer; // Is there a better way to do this?
Runnable runnable = () -> handler.execute(player, targetPlayerF, args);
if(threading) {
Thread command = new Thread(runnable);
command.start();
}
else {
new Thread(runnable).start();
} else {
runnable.run();
}
}

View File

@ -1,6 +1,5 @@
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.database.DatabaseHelper;
@ -8,18 +7,20 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "account", usage = "account <create|delete> <username> [uid]", description = "Modify user accounts")
public final class AccountCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (sender != null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().This_command_can_only_run_from_console);
CommandHandler.sendMessage(sender, translate("commands.generic.console_execute_error"));
return;
}
if (args.size() < 2) {
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Account_command_usage);
CommandHandler.sendMessage(null, translate("commands.account.command_usage"));
return;
}
@ -28,7 +29,7 @@ public final class AccountCommand implements CommandHandler {
switch (action) {
default:
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Account_command_usage);
CommandHandler.sendMessage(null, translate("commands.account.command_usage"));
return;
case "create":
int uid = 0;
@ -36,27 +37,27 @@ public final class AccountCommand implements CommandHandler {
try {
uid = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Invalid_UID);
CommandHandler.sendMessage(null, translate("commands.account.invalid"));
return;
}
}
emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithId(username, uid);
if (account == null) {
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Account_exists);
CommandHandler.sendMessage(null, translate("commands.account.exists"));
return;
} else {
account.addPermission("*");
account.save(); // Save account to database.
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Account_create_UID.replace("{uid}", Integer.toString(account.getPlayerUid())));
CommandHandler.sendMessage(null, translate("commands.account.create", Integer.toString(account.getPlayerUid())));
}
return;
case "delete":
if (DatabaseHelper.deleteAccount(username)) {
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Account_delete);
CommandHandler.sendMessage(null, translate("commands.account.delete"));
} else {
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Account_not_find);
CommandHandler.sendMessage(null, translate("commands.account.no_account"));
}
}
}

View File

@ -7,6 +7,8 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "broadcast", usage = "broadcast <message>",
description = "Sends a message to all the players", aliases = {"b"}, permission = "server.broadcast")
public final class BroadcastCommand implements CommandHandler {
@ -14,7 +16,7 @@ public final class BroadcastCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Broadcast_command_usage);
CommandHandler.sendMessage(sender, translate("commands.broadcast.command_usage"));
return;
}
@ -24,6 +26,6 @@ public final class BroadcastCommand implements CommandHandler {
CommandHandler.sendMessage(p, message);
}
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Broadcast_message_sent);
CommandHandler.sendMessage(sender, translate("commands.broadcast.message_sent"));
}
}

View File

@ -1,43 +1,43 @@
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 = "changescene", usage = "changescene <scene id>",
description = "Changes your scene", aliases = {"scene"}, permission = "player.changescene")
public final class ChangeSceneCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
if (args.size() != 1) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Change_screen_usage);
CommandHandler.sendMessage(sender, translate("commands.changescene.usage"));
return;
}
try {
int sceneId = Integer.parseInt(args.get(0));
if (sceneId == targetPlayer.getSceneId()) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Change_screen_you_in_that_screen);
CommandHandler.sendMessage(sender, translate("commands.changescene.already_in_scene"));
return;
}
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, targetPlayer.getPos());
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Change_screen + sceneId);
CommandHandler.sendMessage(sender, translate("commands.changescene.result", Integer.toString(sceneId)));
if (!result) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Change_screen_not_exist);
CommandHandler.sendMessage(sender, translate("commands.changescene.exists_error"));
}
} catch (Exception e) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_arguments);
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
}
}
}

View File

@ -10,6 +10,8 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "clear", usage = "clear <all|wp|art|mat>", //Merged /clearartifacts and /clearweapons to /clear <args> [uid]
description = "Deletes unequipped unlocked items, including yellow rarity ones from your inventory",
aliases = {"clear"}, permission = "player.clearinv")
@ -19,11 +21,11 @@ public final class ClearCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
if (args.size() < 1) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_usage);
CommandHandler.sendMessage(sender, translate("commands.clear.command_usage"));
return;
}
Inventory playerInventory = targetPlayer.getInventory();
@ -35,7 +37,7 @@ public final class ClearCommand implements CommandHandler {
.filter(item -> item.getItemType() == ItemType.ITEM_WEAPON)
.filter(item -> !item.isLocked() && !item.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_weapons.replace("{name}", targetPlayer.getNickname()));
CommandHandler.sendMessage(sender, translate("commands.clear.weapons", targetPlayer.getNickname()));
}
case "art" -> {
toDelete = playerInventory.getItems().values().stream()
@ -43,7 +45,7 @@ public final class ClearCommand implements CommandHandler {
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
.filter(item -> !item.isLocked() && !item.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_artifacts.replace("{name}", targetPlayer.getNickname()));
CommandHandler.sendMessage(sender, translate("commands.clear.artifacts", targetPlayer.getNickname()));
}
case "mat" -> {
toDelete = playerInventory.getItems().values().stream()
@ -51,7 +53,7 @@ public final class ClearCommand implements CommandHandler {
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
.filter(item -> !item.isLocked() && !item.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_artifacts.replace("{name}", targetPlayer.getNickname()));
CommandHandler.sendMessage(sender, translate("commands.clear.materials", targetPlayer.getNickname()));
}
case "all" -> {
toDelete = playerInventory.getItems().values().stream()
@ -59,34 +61,44 @@ public final class ClearCommand implements CommandHandler {
.filter(item1 -> item1.getLevel() == 1 && item1.getExp() == 0)
.filter(item1 -> !item1.isLocked() && !item1.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_artifacts.replace("{name}", targetPlayer.getNickname()));
CommandHandler.sendMessage(sender, translate("commands.clear.artifacts", targetPlayer.getNickname()));
playerInventory.removeItems(toDelete);
toDelete = playerInventory.getItems().values().stream()
.filter(item2 -> item2.getItemType() == ItemType.ITEM_MATERIAL)
.filter(item2 -> !item2.isLocked() && !item2.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_artifacts.replace("{name}", targetPlayer.getNickname()));
playerInventory.removeItems(toDelete);
CommandHandler.sendMessage(sender, translate("commands.clear.materials", targetPlayer.getNickname()));
toDelete = playerInventory.getItems().values().stream()
.filter(item3 -> item3.getItemType() == ItemType.ITEM_WEAPON)
.filter(item3 -> item3.getLevel() == 1 && item3.getExp() == 0)
.filter(item3 -> !item3.isLocked() && !item3.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_artifacts.replace("{name}", targetPlayer.getNickname()));
playerInventory.removeItems(toDelete);
CommandHandler.sendMessage(sender, translate("commands.clear.weapons", targetPlayer.getNickname()));
toDelete = playerInventory.getItems().values().stream()
.filter(item4 -> item4.getItemType() == ItemType.ITEM_FURNITURE)
.filter(item4 -> !item4.isLocked() && !item4.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_furniture.replace("{name}", targetPlayer.getNickname()));
playerInventory.removeItems(toDelete);
CommandHandler.sendMessage(sender, translate("commands.clear.furniture", targetPlayer.getNickname()));
toDelete = playerInventory.getItems().values().stream()
.filter(item5 -> item5.getItemType() == ItemType.ITEM_DISPLAY)
.filter(item5 -> !item5.isLocked() && !item5.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_displays.replace("{name}", targetPlayer.getNickname()));
playerInventory.removeItems(toDelete);
CommandHandler.sendMessage(sender, translate("commands.clear.displays", targetPlayer.getNickname()));
toDelete = playerInventory.getItems().values().stream()
.filter(item6 -> item6.getItemType() == ItemType.ITEM_VIRTUAL)
.filter(item6 -> !item6.isLocked() && !item6.isEquipped())
.toList();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_virtuals.replace("{name}", targetPlayer.getNickname()));
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Clear_everything.replace("{name}", targetPlayer.getNickname()));
CommandHandler.sendMessage(sender, translate("commands.clear.virtuals", targetPlayer.getNickname()));
CommandHandler.sendMessage(sender, translate("commands.clear.everything", targetPlayer.getNickname()));
}
}

View File

@ -13,7 +13,7 @@ public final class CoopCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -11,6 +11,8 @@ import emu.grasscutter.utils.Position;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "drop", usage = "drop <itemId|itemName> [amount]",
description = "Drops an item near you", aliases = {"d", "dropitem"}, permission = "server.drop")
public final class DropCommand implements CommandHandler {
@ -18,7 +20,7 @@ public final class DropCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(null, translate("commands.execution.need_target"));
return;
}
@ -30,25 +32,25 @@ public final class DropCommand implements CommandHandler {
try {
amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_amount);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
return;
} // Slightly cheeky here: no break so it falls through to initialize the first argument too
} // 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, Grasscutter.getLanguage().Invalid_item_id);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
return;
}
break;
default:
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Drop_usage);
CommandHandler.sendMessage(sender, translate("commands.drop.command_usage"));
return;
}
ItemData itemData = GameData.getItemDataMap().get(item);
if (itemData == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_item_id);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
return;
}
if (itemData.isEquip()) {
@ -62,6 +64,6 @@ public final class DropCommand implements CommandHandler {
EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, targetPlayer.getPos().clone().addY(3f), amount);
targetPlayer.getScene().addEntity(entity);
}
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Drop_dropped_of.replace("{amount}", Integer.toString(amount)).replace("{item}", Integer.toString(item)));
CommandHandler.sendMessage(sender, translate("commands.drop.success", Integer.toString(amount), Integer.toString(item)));
}
}

View File

@ -1,43 +1,43 @@
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 = "enterdungeon", usage = "enterdungeon <dungeon id>",
description = "Enter a dungeon", aliases = {"dungeon"}, permission = "player.enterdungeon")
public final class EnterDungeonCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(null, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(null, translate("commands.execution.need_target"));
return;
}
if (args.size() < 1) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().EnterDungeon_usage);
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.usage"));
return;
}
try {
int dungeonId = Integer.parseInt(args.get(0));
if (dungeonId == targetPlayer.getSceneId()) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().EnterDungeon_you_in_that_dungeon);
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.in_dungeon_error"));
return;
}
boolean result = targetPlayer.getServer().getDungeonManager().enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().EnterDungeon_changed_to_dungeon + dungeonId);
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.changed", dungeonId));
if (!result) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().EnterDungeon_dungeon_not_found);
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.not_found_error"));
}
} catch (Exception e) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().EnterDungeon_usage);
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.usage"));
}
}
}

View File

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

View File

@ -19,7 +19,7 @@ public final class GiveArtifactCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -10,6 +10,8 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "givechar", usage = "givechar <avatarId> [level]",
description = "Gives the player a specified character", aliases = {"givec"}, permission = "player.givechar")
public final class GiveCharCommand implements CommandHandler {
@ -17,7 +19,7 @@ public final class GiveCharCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
@ -30,7 +32,7 @@ public final class GiveCharCommand implements CommandHandler {
level = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
// TODO: Parse from avatar name using GM Handbook.
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_avatar_level);
CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarLevel"));
return;
} // Cheeky fall-through to parse first argument too
case 1:
@ -38,24 +40,24 @@ public final class GiveCharCommand implements CommandHandler {
avatarId = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
// TODO: Parse from avatar name using GM Handbook.
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_avatar_id);
CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarId"));
return;
}
break;
default:
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().GiveChar_usage);
CommandHandler.sendMessage(sender, translate("commands.giveChar.usage"));
return;
}
AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
if (avatarData == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_avatar_id);
CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarId"));
return;
}
// Check level.
if (level > 90) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_avatar_level);
CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarLevel"));
return;
}
@ -75,6 +77,6 @@ public final class GiveCharCommand implements CommandHandler {
avatar.recalcStats();
targetPlayer.addAvatar(avatar);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().GiveChar_given.replace("{avatarId}", Integer.toString(avatarId)).replace("{level}", Integer.toString(level)).replace("{target}", Integer.toString(targetPlayer.getUid())));
CommandHandler.sendMessage(sender, translate("commands.execution.giveChar.given", Integer.toString(avatarId), Integer.toString(level), Integer.toString(targetPlayer.getUid())));
}
}

View File

@ -15,6 +15,8 @@ import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "give", usage = "give <itemId|itemName> [amount] [level]", description = "Gives an item to you or the specified player", aliases = {
"g", "item", "giveitem"}, permission = "player.give")
public final class GiveCommand implements CommandHandler {
@ -33,7 +35,7 @@ public final class GiveCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
int item;
@ -67,21 +69,21 @@ public final class GiveCommand implements CommandHandler {
try {
refinement = Integer.parseInt(args.get(3));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_item_refinement);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemRefinement"));
return;
} // Fallthrough
case 3: // <itemId|itemName> [amount] [level]
try {
lvl = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_item_level);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemLevel"));
return;
} // Fallthrough
case 2: // <itemId|itemName> [amount]
try {
amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_amount);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
return;
} // Fallthrough
case 1: // <itemId|itemName>
@ -89,30 +91,28 @@ public final class GiveCommand implements CommandHandler {
item = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
// TODO: Parse from item name using GM Handbook.
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_item_id);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
return;
}
break;
default: // *No args*
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Give_usage);
CommandHandler.sendMessage(sender, translate("commands.give.usage"));
return;
}
ItemData itemData = GameData.getItemDataMap().get(item);
if (itemData == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_item_id);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
return;
}
if (refinement != 0) {
if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
if (refinement < 1 || refinement > 5) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Give_refinement_must_between_1_and_5);
CommandHandler.sendMessage(sender, translate("commands.give.refinement_must_between_1_and_5"));
return;
}
} else {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Give_refinement_only_applicable_weapons);
CommandHandler.sendMessage(sender, translate("commands.give.refinement_only_applicable_weapons"));
return;
}
}
@ -120,11 +120,11 @@ public final class GiveCommand implements CommandHandler {
this.item(targetPlayer, itemData, amount, lvl, refinement);
if (!itemData.isEquip()) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Give_given.replace("{amount}", Integer.toString(amount)).replace("{item}", Integer.toString(item)).replace("{target}", Integer.toString(targetPlayer.getUid())));
CommandHandler.sendMessage(sender, translate("commands.give.given", Integer.toString(amount), Integer.toString(item), Integer.toString(targetPlayer.getUid())));
} else if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Give_given_with_level_and_refinement.replace("{item}", Integer.toString(item)).replace("{lvl}", Integer.toString(lvl)).replace("{refinement}", Integer.toString(refinement)).replace("{amount}", Integer.toString(amount)).replace("{target}", Integer.toString(targetPlayer.getUid())));
CommandHandler.sendMessage(sender, translate("commands.give.given_with_level_and_refinement", Integer.toString(item), Integer.toString(lvl), Integer.toString(refinement), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
} else {
CommandHandler.sendMessage(sender,Grasscutter.getLanguage().Give_given_level.replace("{item}", Integer.toString(item)).replace("{lvl}", Integer.toString(lvl)).replace("{amount}", Integer.toString(amount)));
CommandHandler.sendMessage(sender, translate("commands.give.given_level", Integer.toString(item), Integer.toString(lvl), Integer.toString(amount)));
}
}

View File

@ -7,6 +7,8 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "godmode", usage = "godmode [on|off|toggle]",
description = "Prevents you from taking damage. Defaults to toggle.", permission = "player.godmode")
public final class GodModeCommand implements CommandHandler {
@ -14,7 +16,7 @@ public final class GodModeCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
@ -30,11 +32,11 @@ public final class GodModeCommand implements CommandHandler {
case "toggle":
break; // Already toggled
default:
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Godmode_status);
break;
}
}
targetPlayer.setGodmode(enabled);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Godmode_status.replace("{status}", (enabled ? Grasscutter.getLanguage().Enabled : Grasscutter.getLanguage().Disabled)).replace("{name}", targetPlayer.getNickname()));
CommandHandler.sendMessage(sender, translate("commands.godmode.success", (enabled ? translate("commands.status.enabled") : translate("commands.status.disabled")), targetPlayer.getNickname()));
}
}

View File

@ -1,6 +1,5 @@
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;
@ -10,13 +9,15 @@ import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "heal", usage = "heal|h", aliases = {"h"},
description = "Heal all characters in your current team.", permission = "player.heal")
public final class HealCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
@ -31,6 +32,6 @@ public final class HealCommand implements CommandHandler {
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
}
});
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Heal_message);
CommandHandler.sendMessage(sender, translate("commands.heal.success"));
}
}

View File

@ -8,6 +8,8 @@ import emu.grasscutter.game.player.Player;
import java.util.*;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "help", usage = "help [command]",
description = "Sends the help message or shows information about a specified command")
public final class HelpCommand implements CommandHandler {
@ -31,16 +33,16 @@ public final class HelpCommand implements CommandHandler {
} else {
String command = args.get(0);
CommandHandler handler = CommandMap.getInstance().getHandler(command);
StringBuilder builder = new StringBuilder(player == null ? "\n" + Grasscutter.getLanguage().Help + " - " : Grasscutter.getLanguage().Help + " - ").append(command).append(": \n");
StringBuilder builder = new StringBuilder(player == null ? "\n" + translate("commands.status.help") + " - " : translate("commands.status.help") + " - ").append(command).append(": \n");
if (handler == null) {
builder.append(Grasscutter.getLanguage().No_command_found);
builder.append(translate("commands.generic.command_exist_error"));
} else {
Command annotation = handler.getClass().getAnnotation(Command.class);
builder.append(" ").append(annotation.description()).append("\n");
builder.append(Grasscutter.getLanguage().Help_usage).append(annotation.usage());
builder.append(translate("commands.help.usage")).append(annotation.usage());
if (annotation.aliases().length >= 1) {
builder.append("\n").append(Grasscutter.getLanguage().Help_aliases);
builder.append("\n").append(translate("commands.help.aliases"));
for (String alias : annotation.aliases()) {
builder.append(alias).append(" ");
}
@ -56,13 +58,13 @@ public final class HelpCommand implements CommandHandler {
void SendAllHelpMessage(Player player, List<Command> annotations) {
if (player == null) {
StringBuilder builder = new StringBuilder("\n" + Grasscutter.getLanguage().Help_available_command + "\n");
StringBuilder builder = new StringBuilder("\n" + translate("commands.help.available_commands") + "\n");
annotations.forEach(annotation -> {
builder.append(annotation.label()).append("\n");
builder.append(" ").append(annotation.description()).append("\n");
builder.append(Grasscutter.getLanguage().Help_usage).append(annotation.usage());
builder.append(translate("commands.help.usage")).append(annotation.usage());
if (annotation.aliases().length >= 1) {
builder.append("\n").append(Grasscutter.getLanguage().Help_aliases);
builder.append("\n").append(translate("commands.help.aliases"));
for (String alias : annotation.aliases()) {
builder.append(alias).append(" ");
}
@ -73,13 +75,13 @@ public final class HelpCommand implements CommandHandler {
CommandHandler.sendMessage(null, builder.toString());
} else {
CommandHandler.sendMessage(player, Grasscutter.getLanguage().Help_available_command);
CommandHandler.sendMessage(player, translate("commands.help.available_commands"));
annotations.forEach(annotation -> {
StringBuilder builder = new StringBuilder(annotation.label()).append("\n");
builder.append(" ").append(annotation.description()).append("\n");
builder.append(Grasscutter.getLanguage().Help_usage).append(annotation.usage());
builder.append(translate("commands.help.usage")).append(annotation.usage());
if (annotation.aliases().length >= 1) {
builder.append("\n").append(Grasscutter.getLanguage().Help_aliases);
builder.append("\n").append(translate("commands.help.aliases"));
for (String alias : annotation.aliases()) {
builder.append(alias).append(" ");
}

View File

@ -1,12 +1,13 @@
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 = "kick", usage = "kick",
description = "Kicks the specified player from the server (WIP)", permission = "server.kick")
public final class KickCommand implements CommandHandler {
@ -14,14 +15,16 @@ public final class KickCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
if (sender != null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Kick_player_kick_player.replace("{sendUid}", Integer.toString(sender.getAccount().getPlayerUid())).replace("{sendName}", sender.getAccount().getUsername()).replace("kickUid", Integer.toString(targetPlayer.getUid())).replace("{kickName}", targetPlayer.getAccount().getUsername()));
CommandHandler.sendMessage(sender, translate("commands.kick.player_kick_player",
Integer.toString(sender.getAccount().getPlayerUid()), sender.getAccount().getUsername(),
Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
} else {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Kick_server_player.replace("{kickUid}", Integer.toString(targetPlayer.getUid())).replace("{kickName}", targetPlayer.getAccount().getUsername()));
CommandHandler.sendMessage(null, translate("commands.kick.server_kick_player", Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
}
targetPlayer.getSession().close();

View File

@ -10,6 +10,8 @@ import emu.grasscutter.game.world.Scene;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "killall", usage = "killall [sceneId]",
description = "Kill all entities", permission = "server.killall")
public final class KillAllCommand implements CommandHandler {
@ -17,7 +19,7 @@ public final class KillAllCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
@ -30,14 +32,14 @@ public final class KillAllCommand implements CommandHandler {
scene = targetPlayer.getWorld().getSceneById(Integer.parseInt(args.get(0)));
break;
default:
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Kill_usage);
CommandHandler.sendMessage(sender, translate("commands.kill.usage"));
return;
}
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_arguments);
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
}
if (scene == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Kill_scene_not_found_in_player_world);
CommandHandler.sendMessage(sender, translate("commands.kill.scene_not_found_in_player_world"));
return;
}
@ -46,7 +48,7 @@ public final class KillAllCommand implements CommandHandler {
List<GameEntity> toKill = sceneF.getEntities().values().stream()
.filter(entity -> entity instanceof EntityMonster)
.toList();
toKill.stream().forEach(entity -> sceneF.killEntity(entity, 0));
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Kill_kill_monsters_in_scene.replace("{size}", Integer.toString(toKill.size())).replace("{id}", Integer.toString(scene.getId())));
toKill.forEach(entity -> sceneF.killEntity(entity, 0));
CommandHandler.sendMessage(sender, translate("commands.kill.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
}
}

View File

@ -19,7 +19,7 @@ public final class KillCharacterCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -8,6 +8,8 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "permission", usage = "permission <add|remove> <permission>",
description = "Grants or removes a permission for a user", permission = "*")
public final class PermissionCommand implements CommandHandler {
@ -15,7 +17,7 @@ public final class PermissionCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -1,6 +1,5 @@
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;
@ -8,6 +7,8 @@ import emu.grasscutter.utils.Position;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "position", usage = "position", aliases = {"pos"},
description = "Get coordinates.")
public final class PositionCommand implements CommandHandler {
@ -15,11 +16,13 @@ public final class PositionCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
Position pos = targetPlayer.getPos();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Position_message.replace("{x}", Float.toString(pos.getX())).replace("{y}", Float.toString(pos.getY())).replace("{z}", Float.toString(pos.getZ())).replace("{id}", Integer.toString(targetPlayer.getSceneId())));
CommandHandler.sendMessage(sender, translate("commands.position.success",
Float.toString(pos.getX()), Float.toString(pos.getY()), Float.toString(pos.getZ()),
Integer.toString(targetPlayer.getSceneId())));
}
}

View File

@ -7,19 +7,23 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "reload", usage = "reload",
description = "Reload server config", permission = "server.reload")
public final class ReloadCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Reload_reload_start);
CommandHandler.sendMessage(sender, translate("commands.reload.reload_start"));
Grasscutter.loadConfig();
Grasscutter.loadLanguage();
Grasscutter.getGameServer().getGachaManager().load();
Grasscutter.getGameServer().getDropManager().load();
Grasscutter.getGameServer().getShopManager().load();
Grasscutter.getDispatchServer().loadQueries();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Reload_reload_done);
CommandHandler.sendMessage(sender, translate("commands.reload.reload_done"));
}
}

View File

@ -1,6 +1,5 @@
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.avatar.Avatar;
@ -9,6 +8,8 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "resetconst", usage = "resetconst [all]",
description = "Resets the constellation level on your current active character, will need to relog after using the command to see any changes.",
aliases = {"resetconstellation"}, permission = "player.resetconstellation")
@ -17,13 +18,13 @@ public final class ResetConstCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
if (args.size() > 0 && args.get(0).equalsIgnoreCase("all")) {
targetPlayer.getAvatars().forEach(this::resetConstellation);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().ResetConst_reset_all);
CommandHandler.sendMessage(sender, translate("commands.resetConst.reset_all"));
} else {
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
if (entity == null) {
@ -33,7 +34,7 @@ public final class ResetConstCommand implements CommandHandler {
Avatar avatar = entity.getAvatar();
this.resetConstellation(avatar);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().ResetConst_reset_all_done.replace("{name}", avatar.getAvatarData().getName()));
CommandHandler.sendMessage(sender, translate("commands.resetConst.success", avatar.getAvatarData().getName()));
}
}

View File

@ -13,7 +13,7 @@ public final class ResetShopLimitCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -10,6 +10,9 @@ import emu.grasscutter.game.player.Player;
import java.util.HashMap;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings("ConstantConditions")
@Command(label = "sendmail", usage = "sendmail <userId|all|help> [templateId]",
description = "Sends mail to the specified user. The usage of this command changes based on it's composition state.", permission = "server.sendmail")
public final class SendMailCommand implements CommandHandler {
@ -45,16 +48,16 @@ public final class SendMailCommand implements CommandHandler {
if (DatabaseHelper.getPlayerById(Integer.parseInt(args.get(0))) != null) {
mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail());
} else {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_user_not_exist.replace("{id}", args.get(0)));
CommandHandler.sendMessage(sender, translate("commands.sendMail.user_not_exist", args.get(0)));
return;
}
}
}
mailBeingConstructed.put(senderId, mailBuilder);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_start_composition);
CommandHandler.sendMessage(sender, translate("commands.sendMail.start_composition"));
}
case 2 -> CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_templates);
default -> CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_invalid_arguments);
case 2 -> CommandHandler.sendMessage(sender, translate("commands.sendMail.templates"));
default -> CommandHandler.sendMessage(sender, translate("commands.sendMail.invalid_arguments"));
}
} else {
MailBuilder mailBuilder = mailBeingConstructed.get(senderId);
@ -63,28 +66,28 @@ public final class SendMailCommand implements CommandHandler {
switch (args.get(0).toLowerCase()) {
case "stop" -> {
mailBeingConstructed.remove(senderId);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_send_cancel);
CommandHandler.sendMessage(sender, translate("commands.sendMail.sendCancel"));
return;
}
case "finish" -> {
if (mailBuilder.constructionStage == 3) {
if (!mailBuilder.sendToAll) {
Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_send_done.replace("{name}", Integer.toString(mailBuilder.recipient)));
CommandHandler.sendMessage(sender, translate("commands.sendMail.send_done", Integer.toString(mailBuilder.recipient)));
} else {
for (Player player : DatabaseHelper.getAllPlayers()) {
Grasscutter.getGameServer().getPlayerByUid(player.getUid(), true).sendMail(mailBuilder.mail);
}
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_send_all_done);
CommandHandler.sendMessage(sender, translate("commands.sendMail.send_all_done"));
}
mailBeingConstructed.remove(senderId);
} else {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_not_composition_end.replace("{args}", getConstructionArgs(mailBuilder.constructionStage)));
CommandHandler.sendMessage(sender, translate("commands.sendMail.not_composition_end", getConstructionArgs(mailBuilder.constructionStage)));
}
return;
}
case "help" -> {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_please_use.replace("{args}", getConstructionArgs(mailBuilder.constructionStage)));
CommandHandler.sendMessage(sender, translate("commands.sendMail.please_use", getConstructionArgs(mailBuilder.constructionStage)));
return;
}
default -> {
@ -92,19 +95,19 @@ public final class SendMailCommand implements CommandHandler {
case 0 -> {
String title = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.title = title;
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_set_title.replace("{title}", title));
CommandHandler.sendMessage(sender, translate("commands.sendMail.set_title", title));
mailBuilder.constructionStage++;
}
case 1 -> {
String contents = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.content = contents;
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_set_contents.replace("{contents}", contents));
CommandHandler.sendMessage(sender, translate("commands.sendMail.set_contents", contents));
mailBuilder.constructionStage++;
}
case 2 -> {
String msgSender = String.join(" ", args.subList(0, args.size()));
mailBuilder.mail.mailContent.sender = msgSender;
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_set_message_sender.replace("{send}", msgSender));
CommandHandler.sendMessage(sender, translate("commands.sendMail.set_message_sender", msgSender));
mailBuilder.constructionStage++;
}
case 3 -> {
@ -117,21 +120,21 @@ public final class SendMailCommand implements CommandHandler {
try {
refinement = Integer.parseInt(args.get(3));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_item_refinement);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemRefinement"));
return;
} // Fallthrough
case 3: // <itemId|itemName> [amount] [level]
try {
lvl = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_item_level);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemLevel"));
return;
} // Fallthrough
case 2: // <itemId|itemName> [amount]
try {
amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_amount);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
return;
} // Fallthrough
case 1: // <itemId|itemName>
@ -139,46 +142,34 @@ public final class SendMailCommand implements CommandHandler {
item = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
// TODO: Parse from item name using GM Handbook.
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Invalid_item_id);
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
return;
}
break;
default: // *No args*
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Give_usage);
CommandHandler.sendMessage(sender, translate("commands.give.usage"));
return;
}
mailBuilder.mail.itemList.add(new Mail.MailItem(item, amount, lvl));
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_send.replace("{amount}", Integer.toString(amount)).replace("{item}", Integer.toString(item)).replace("{lvl}", Integer.toString(lvl)));
CommandHandler.sendMessage(sender, translate("commands.sendMail.send", Integer.toString(amount), Integer.toString(item), Integer.toString(lvl)));
}
}
}
}
} else {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SendMail_invalid_arguments_please_use.replace("{args}", getConstructionArgs(mailBuilder.constructionStage)));
CommandHandler.sendMessage(sender, translate("commands.sendMail.invalid_arguments_please_use", getConstructionArgs(mailBuilder.constructionStage)));
}
}
}
private String getConstructionArgs(int stage) {
switch (stage) {
case 0 -> {
return Grasscutter.getLanguage().SendMail_title;
}
case 1 -> {
return Grasscutter.getLanguage().SendMail_message;
}
case 2 -> {
return Grasscutter.getLanguage().SendMail_sender;
}
case 3 -> {
return Grasscutter.getLanguage().SendMail_arguments;
}
default -> {
Thread.dumpStack();
return Grasscutter.getLanguage().SendMail_error.replace("{stage}", Integer.toString(stage));
}
}
return switch(stage) {
case 0 -> translate("commands.sendMail.title");
case 1 -> translate("commands.sendMail.message");
case 2 -> translate("commands.sendMail.sender");
case 3 -> translate("commands.sendMail.arguments");
default -> translate("commands.sendMail.error", Integer.toString(stage));
};
}
public static class MailBuilder {

View File

@ -7,6 +7,8 @@ import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "say", usage = "say <message>", description = "Sends a message to a player as the server",
aliases = {"sendservmsg", "sendservermessage", "sendmessage"}, permission = "server.sendmessage")
public final class SendMessageCommand implements CommandHandler {
@ -14,7 +16,7 @@ public final class SendMessageCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
if (args.size() == 0) {

View File

@ -18,7 +18,7 @@ public final class SetFetterLevelCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -10,13 +10,15 @@ import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.languages.Language;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.utils.Language;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "setstats", usage = "setstats|stats <stat> <value>",
description = "Set fight property for your current active character", aliases = {"stats"}, permission = "player.setstats")
public final class SetStatsCommand implements CommandHandler {
class Stat {
static class Stat {
String name;
FightProperty prop;
boolean percent;
@ -27,44 +29,44 @@ public final class SetStatsCommand implements CommandHandler {
this.percent = percent;
}
}
Map<String, Stat> stats;
Map<String, Stat> stats = new HashMap<>();
public SetStatsCommand() {
Language lang = Grasscutter.getLanguage();
stats = new HashMap<String, Stat>();
// Default stats
stats.put("maxhp", new Stat(lang.Stats_FIGHT_PROP_MAX_HP, FightProperty.FIGHT_PROP_MAX_HP, false));
stats.put("hp", new Stat(lang.Stats_FIGHT_PROP_CUR_HP, FightProperty.FIGHT_PROP_CUR_HP, false));
stats.put("atk", new Stat(lang.Stats_FIGHT_PROP_CUR_ATTACK, FightProperty.FIGHT_PROP_CUR_ATTACK, false));
stats.put("atkb", new Stat(lang.Stats_FIGHT_PROP_BASE_ATTACK, FightProperty.FIGHT_PROP_BASE_ATTACK, false)); // This doesn't seem to get used to recalculate ATK, so it's only useful for stuff like Bennett's buff.
stats.put("def", new Stat(lang.Stats_FIGHT_PROP_DEFENSE, FightProperty.FIGHT_PROP_DEFENSE, false));
stats.put("em", new Stat(lang.Stats_FIGHT_PROP_ELEMENT_MASTERY, FightProperty.FIGHT_PROP_ELEMENT_MASTERY, false));
stats.put("er", new Stat(lang.Stats_FIGHT_PROP_CHARGE_EFFICIENCY, FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, true));
stats.put("crate", new Stat(lang.Stats_FIGHT_PROP_CRITICAL, FightProperty.FIGHT_PROP_CRITICAL, true));
stats.put("cdmg", new Stat(lang.Stats_FIGHT_PROP_CRITICAL_HURT, FightProperty.FIGHT_PROP_CRITICAL_HURT, true));
stats.put("dmg", new Stat(lang.Stats_FIGHT_PROP_ADD_HURT, FightProperty.FIGHT_PROP_ADD_HURT, true)); // This seems to get reset after attacks
stats.put("eanemo", new Stat(lang.Stats_FIGHT_PROP_WIND_ADD_HURT, FightProperty.FIGHT_PROP_WIND_ADD_HURT, true));
stats.put("ecryo", new Stat(lang.Stats_FIGHT_PROP_ICE_ADD_HURT, FightProperty.FIGHT_PROP_ICE_ADD_HURT, true));
stats.put("edendro", new Stat(lang.Stats_FIGHT_PROP_GRASS_ADD_HURT, FightProperty.FIGHT_PROP_GRASS_ADD_HURT, true));
stats.put("eelectro", new Stat(lang.Stats_FIGHT_PROP_ELEC_ADD_HURT, FightProperty.FIGHT_PROP_ELEC_ADD_HURT, true));
stats.put("egeo", new Stat(lang.Stats_FIGHT_PROP_ROCK_ADD_HURT, FightProperty.FIGHT_PROP_ROCK_ADD_HURT, true));
stats.put("ehydro", new Stat(lang.Stats_FIGHT_PROP_WATER_ADD_HURT, FightProperty.FIGHT_PROP_WATER_ADD_HURT, true));
stats.put("epyro", new Stat(lang.Stats_FIGHT_PROP_FIRE_ADD_HURT, FightProperty.FIGHT_PROP_FIRE_ADD_HURT, true));
stats.put("ephys", new Stat(lang.Stats_FIGHT_PROP_PHYSICAL_ADD_HURT, FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, true));
stats.put("resall", new Stat(lang.Stats_FIGHT_PROP_SUB_HURT, FightProperty.FIGHT_PROP_SUB_HURT, true)); // This seems to get reset after attacks
stats.put("resanemo", new Stat(lang.Stats_FIGHT_PROP_WIND_SUB_HURT, FightProperty.FIGHT_PROP_WIND_SUB_HURT, true));
stats.put("rescryo", new Stat(lang.Stats_FIGHT_PROP_ICE_SUB_HURT, FightProperty.FIGHT_PROP_ICE_SUB_HURT, true));
stats.put("resdendro", new Stat(lang.Stats_FIGHT_PROP_GRASS_SUB_HURT, FightProperty.FIGHT_PROP_GRASS_SUB_HURT, true));
stats.put("reselectro", new Stat(lang.Stats_FIGHT_PROP_ELEC_SUB_HURT, FightProperty.FIGHT_PROP_ELEC_SUB_HURT, true));
stats.put("resgeo", new Stat(lang.Stats_FIGHT_PROP_ROCK_SUB_HURT, FightProperty.FIGHT_PROP_ROCK_SUB_HURT, true));
stats.put("reshydro", new Stat(lang.Stats_FIGHT_PROP_WATER_SUB_HURT, FightProperty.FIGHT_PROP_WATER_SUB_HURT, true));
stats.put("respyro", new Stat(lang.Stats_FIGHT_PROP_FIRE_SUB_HURT, FightProperty.FIGHT_PROP_FIRE_SUB_HURT, true));
stats.put("resphys", new Stat(lang.Stats_FIGHT_PROP_PHYSICAL_SUB_HURT, FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, true));
stats.put("cdr", new Stat(lang.Stats_FIGHT_PROP_SKILL_CD_MINUS_RATIO, FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO, true));
stats.put("heal", new Stat(lang.Stats_FIGHT_PROP_HEAL_ADD, FightProperty.FIGHT_PROP_HEAL_ADD, true));
stats.put("heali", new Stat(lang.Stats_FIGHT_PROP_HEALED_ADD, FightProperty.FIGHT_PROP_HEALED_ADD, true));
stats.put("shield", new Stat(lang.Stats_FIGHT_PROP_SHIELD_COST_MINUS_RATIO, FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO, true));
stats.put("defi", new Stat(lang.Stats_FIGHT_PROP_DEFENCE_IGNORE_RATIO, FightProperty.FIGHT_PROP_DEFENCE_IGNORE_RATIO, true));
stats.put("maxhp", new Stat(FightProperty.FIGHT_PROP_MAX_HP.toString(), FightProperty.FIGHT_PROP_MAX_HP, false));
stats.put("hp", new Stat(FightProperty.FIGHT_PROP_CUR_HP.toString(), FightProperty.FIGHT_PROP_CUR_HP, false));
stats.put("atk", new Stat(FightProperty.FIGHT_PROP_CUR_ATTACK.toString(), FightProperty.FIGHT_PROP_CUR_ATTACK, false));
stats.put("atkb", new Stat(FightProperty.FIGHT_PROP_BASE_ATTACK.toString(), FightProperty.FIGHT_PROP_BASE_ATTACK, false)); // This doesn't seem to get used to recalculate ATK, so it's only useful for stuff like Bennett's buff.
stats.put("def", new Stat(FightProperty.FIGHT_PROP_DEFENSE.toString(), FightProperty.FIGHT_PROP_DEFENSE, false));
stats.put("em", new Stat(FightProperty.FIGHT_PROP_ELEMENT_MASTERY.toString(), FightProperty.FIGHT_PROP_ELEMENT_MASTERY, false));
stats.put("er", new Stat(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY.toString(), FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, true));
stats.put("crate", new Stat(FightProperty.FIGHT_PROP_CRITICAL.toString(), FightProperty.FIGHT_PROP_CRITICAL, true));
stats.put("cdmg", new Stat(FightProperty.FIGHT_PROP_CRITICAL_HURT.toString(), FightProperty.FIGHT_PROP_CRITICAL_HURT, true));
stats.put("dmg", new Stat(FightProperty.FIGHT_PROP_ADD_HURT.toString(), FightProperty.FIGHT_PROP_ADD_HURT, true)); // This seems to get reset after attacks
stats.put("eanemo", new Stat(FightProperty.FIGHT_PROP_WIND_ADD_HURT.toString(), FightProperty.FIGHT_PROP_WIND_ADD_HURT, true));
stats.put("ecryo", new Stat(FightProperty.FIGHT_PROP_ICE_ADD_HURT.toString(), FightProperty.FIGHT_PROP_ICE_ADD_HURT, true));
stats.put("edendro", new Stat(FightProperty.FIGHT_PROP_GRASS_ADD_HURT.toString(), FightProperty.FIGHT_PROP_GRASS_ADD_HURT, true));
stats.put("eelectro", new Stat(FightProperty.FIGHT_PROP_ELEC_ADD_HURT.toString(), FightProperty.FIGHT_PROP_ELEC_ADD_HURT, true));
stats.put("egeo", new Stat(FightProperty.FIGHT_PROP_ROCK_ADD_HURT.toString(), FightProperty.FIGHT_PROP_ROCK_ADD_HURT, true));
stats.put("ehydro", new Stat(FightProperty.FIGHT_PROP_WATER_ADD_HURT.toString(), FightProperty.FIGHT_PROP_WATER_ADD_HURT, true));
stats.put("epyro", new Stat(FightProperty.FIGHT_PROP_FIRE_ADD_HURT.toString(), FightProperty.FIGHT_PROP_FIRE_ADD_HURT, true));
stats.put("ephys", new Stat(FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT.toString(), FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, true));
stats.put("resall", new Stat(FightProperty.FIGHT_PROP_SUB_HURT.toString(), FightProperty.FIGHT_PROP_SUB_HURT, true)); // This seems to get reset after attacks
stats.put("resanemo", new Stat(FightProperty.FIGHT_PROP_WIND_SUB_HURT.toString(), FightProperty.FIGHT_PROP_WIND_SUB_HURT, true));
stats.put("rescryo", new Stat(FightProperty.FIGHT_PROP_ICE_SUB_HURT.toString(), FightProperty.FIGHT_PROP_ICE_SUB_HURT, true));
stats.put("resdendro", new Stat(FightProperty.FIGHT_PROP_GRASS_SUB_HURT.toString(), FightProperty.FIGHT_PROP_GRASS_SUB_HURT, true));
stats.put("reselectro", new Stat(FightProperty.FIGHT_PROP_ELEC_SUB_HURT.toString(), FightProperty.FIGHT_PROP_ELEC_SUB_HURT, true));
stats.put("resgeo", new Stat(FightProperty.FIGHT_PROP_ROCK_SUB_HURT.toString(), FightProperty.FIGHT_PROP_ROCK_SUB_HURT, true));
stats.put("reshydro", new Stat(FightProperty.FIGHT_PROP_WATER_SUB_HURT.toString(), FightProperty.FIGHT_PROP_WATER_SUB_HURT, true));
stats.put("respyro", new Stat(FightProperty.FIGHT_PROP_FIRE_SUB_HURT.toString(), FightProperty.FIGHT_PROP_FIRE_SUB_HURT, true));
stats.put("resphys", new Stat(FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT.toString(), FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, true));
stats.put("cdr", new Stat(FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO.toString(), FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO, true));
stats.put("heal", new Stat(FightProperty.FIGHT_PROP_HEAL_ADD.toString(), FightProperty.FIGHT_PROP_HEAL_ADD, true));
stats.put("heali", new Stat(FightProperty.FIGHT_PROP_HEALED_ADD.toString(), FightProperty.FIGHT_PROP_HEALED_ADD, true));
stats.put("shield", new Stat(FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO.toString(), FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO, true));
stats.put("defi", new Stat(FightProperty.FIGHT_PROP_DEFENCE_IGNORE_RATIO.toString(), FightProperty.FIGHT_PROP_DEFENCE_IGNORE_RATIO, true));
// Compatibility aliases
stats.put("mhp", stats.get("maxhp"));
stats.put("cr", stats.get("crate"));
@ -175,26 +177,23 @@ public final class SetStatsCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
Language lang = Grasscutter.getLanguage();
String syntax = sender == null ? lang.SetStats_usage_console : lang.SetStats_usage_console;
String usage = syntax + lang.SetStats_help_message;
String syntax = sender == null ? translate("commands.setStats.usage_console") : translate("commands.setStats.ingame");
String usage = syntax + translate("commands.setStats.help_message");
String statStr;
String valueStr;
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, lang.Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
switch (args.size()) {
default:
CommandHandler.sendMessage(sender, usage);
return;
case 2:
statStr = args.get(0).toLowerCase();
valueStr = args.get(1);
break;
};
if (args.size() == 2) {
statStr = args.get(0).toLowerCase();
valueStr = args.get(1);
} else {
CommandHandler.sendMessage(sender, usage);
return;
}
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
@ -206,7 +205,7 @@ public final class SetStatsCommand implements CommandHandler {
value = Float.parseFloat(valueStr);
}
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, lang.SetStats_value_error);
CommandHandler.sendMessage(sender, translate("commands.setStats.value_error"));
return;
}
@ -220,15 +219,14 @@ public final class SetStatsCommand implements CommandHandler {
valueStr = String.format("%.0f", value);
}
if (targetPlayer == sender) {
CommandHandler.sendMessage(sender, lang.SetStats_set_self.replace("{name}", stat.name).replace("{value}", valueStr));
CommandHandler.sendMessage(sender, translate("commands.setStats.set_self", stat.name, valueStr));
} else {
String uidStr = targetPlayer.getAccount().getId();
CommandHandler.sendMessage(sender, lang.SetStats_set_for_uid.replace("{name}", stat.name).replace("{uid}", uidStr).replace("{value}", valueStr));
CommandHandler.sendMessage(sender, translate("commands.setStats.set_self", stat.name, uidStr, valueStr));
}
return;
} else {
CommandHandler.sendMessage(sender, usage);
return;
}
return;
}
}

View File

@ -15,7 +15,7 @@ public final class SetWorldLevelCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -27,7 +27,7 @@ public final class SpawnCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -12,13 +12,15 @@ import emu.grasscutter.server.packet.send.PacketAvatarSkillUpgradeRsp;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "talent", usage = "talent <talentID> <value>",
description = "Set talent level for your current active character", permission = "player.settalent")
public final class TalentCommand implements CommandHandler {
private void setTalentLevel(Player sender, Player player, Avatar avatar, int talentId, int talentLevel) {
int oldLevel = avatar.getSkillLevelMap().get(talentId);
if (talentLevel < 0 || talentLevel > 15) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_lower_16);
CommandHandler.sendMessage(sender, translate("commands.talent.lower_16"));
return;
}
@ -30,29 +32,29 @@ public final class TalentCommand implements CommandHandler {
player.sendPacket(new PacketAvatarSkillChangeNotify(avatar, talentId, oldLevel, talentLevel));
player.sendPacket(new PacketAvatarSkillUpgradeRsp(avatar, talentId, oldLevel, talentLevel));
String successMessage = Grasscutter.getLanguage().Talent_set_id.replace("{id}", Integer.toString(talentId));
String successMessage = "commands.talent.set_id";
AvatarSkillDepotData depot = avatar.getData().getSkillDepot();
if (talentId == depot.getSkills().get(0)) {
successMessage = Grasscutter.getLanguage().Talent_set_atk;
successMessage = "commands.talent.set_atk";
} else if (talentId == depot.getSkills().get(1)) {
successMessage = Grasscutter.getLanguage().Talent_set_e;
successMessage = "commands.talent.set_e";
} else if (talentId == depot.getEnergySkill()) {
successMessage = Grasscutter.getLanguage().Talent_set_q;
successMessage = "commands.talent.set_q";
}
CommandHandler.sendMessage(sender, successMessage.replace("{level}", Integer.toString(talentLevel)));
CommandHandler.sendMessage(sender, translate(successMessage, talentLevel));
}
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}
if (args.size() < 1){
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_1);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_2);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_3);
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
return;
}
@ -60,66 +62,54 @@ public final class TalentCommand implements CommandHandler {
Avatar avatar = entity.getAvatar();
String cmdSwitch = args.get(0);
switch (cmdSwitch) {
default:
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_1);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_2);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_3);
return;
case "set":
if (args.size() < 3){
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_1);
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_3);
default -> {
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
return;
}
case "set" -> {
if (args.size() < 3) {
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
return;
}
try {
int skillId = Integer.parseInt(args.get(1));
int newLevel = Integer.parseInt(args.get(2));
setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel);
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_invalid_skill_id);
CommandHandler.sendMessage(sender, translate("commands.talent.invalid_skill_id"));
return;
}
break;
case "n":
case "e":
case "q":
if (args.size() < 2){
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_usage_2);
}
case "n", "e", "q" -> {
if (args.size() < 2) {
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
return;
}
AvatarSkillDepotData SkillDepot = avatar.getData().getSkillDepot();
int skillId;
switch (cmdSwitch) {
default:
skillId = SkillDepot.getSkills().get(0);
break;
case "e":
skillId = SkillDepot.getSkills().get(1);
break;
case "q":
skillId = SkillDepot.getEnergySkill();
break;
}
int skillId = switch (cmdSwitch) {
default -> SkillDepot.getSkills().get(0);
case "e" -> SkillDepot.getSkills().get(1);
case "q" -> SkillDepot.getEnergySkill();
};
try {
int newLevel = Integer.parseInt(args.get(1));
setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel);
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_invalid_talent_level);
CommandHandler.sendMessage(sender, translate("commands.talent.invalid_level"));
return;
}
break;
case "getid":
}
case "getid" -> {
int skillIdNorAtk = avatar.getData().getSkillDepot().getSkills().get(0);
int skillIdE = avatar.getData().getSkillDepot().getSkills().get(1);
int skillIdQ = avatar.getData().getSkillDepot().getEnergySkill();
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_normal_attack_id.replace("{id}", Integer.toString(skillIdNorAtk)));
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_e_skill_id.replace("{id}", Integer.toString(skillIdE)));
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Talent_q_skill_id.replace("{id}", Integer.toString(skillIdQ)));
break;
CommandHandler.sendMessage(sender, translate("commands.talent.normal_attack_id", Integer.toString(skillIdNorAtk)));
CommandHandler.sendMessage(sender, translate("commands.talent.e_skill_id", Integer.toString(skillIdE)));
CommandHandler.sendMessage(sender, translate("commands.talent.q_skill_id", Integer.toString(skillIdQ)));
}
}
}
}

View File

@ -14,7 +14,7 @@ public final class TeleportAllCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -26,7 +26,7 @@ public final class TeleportCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -16,7 +16,7 @@ public final class WeatherCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed);
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return;
}

View File

@ -4,13 +4,7 @@ import com.google.gson.reflect.TypeToken;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.def.ItemData;
import emu.grasscutter.data.def.ShopGoodsData;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.managers.InventoryManager;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.ShopGoodsOuterClass;
import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@ -54,9 +48,9 @@ public class ShopManager {
public static int getShopNextRefreshTime(ShopInfo shopInfo) {
return switch (shopInfo.getShopRefreshType()) {
case SHOP_REFRESH_DAILY -> Utils.GetNextTimestampOfThisHour(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_WEEKLY -> Utils.GetNextTimestampOfThisHourInNextWeek(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_MONTHLY -> Utils.GetNextTimestampOfThisHourInNextMonth(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_DAILY -> Utils.getNextTimestampOfThisHour(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_WEEKLY -> Utils.getNextTimestampOfThisHourInNextWeek(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_MONTHLY -> Utils.getNextTimestampOfThisHourInNextMonth(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
default -> 0;
};
}

View File

@ -28,6 +28,7 @@ public final class PlayerHook {
/**
* Kicks a player from the server.
* TODO: Refactor to kick using a packet.
*/
public void kick() {
this.player.getSession().close();

View File

@ -2,6 +2,7 @@ package emu.grasscutter.server.dispatch;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerDebugMode;
@ -9,6 +10,8 @@ import express.http.HttpContextHandler;
import express.http.Request;
import express.http.Response;
import static emu.grasscutter.utils.Language.translate;
public final class DispatchHttpJsonHandler implements HttpContextHandler {
private final String response;
private final String[] missingRoutes = { // TODO: When http requests for theses routes are found please remove it from this list and update the route request type in the DispatchServer
@ -31,8 +34,8 @@ public final class DispatchHttpJsonHandler implements HttpContextHandler {
@Override
public void handle(Request req, Response res) throws IOException {
// Checking for ALL here isn't required as when ALL is enabled enableDevLogging() gets enabled
if(Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING && Arrays.stream(missingRoutes).anyMatch(x -> x == req.baseUrl())) {
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_request.replace("{ip}", req.ip()).replace("{method}", req.method()).replace("{url}", req.baseUrl()) + (Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING ? "(MISSING)" : ""));
if(Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING && Arrays.stream(missingRoutes).anyMatch(x -> Objects.equals(x, req.baseUrl()))) {
Grasscutter.getLogger().info(translate("messages.dispatch.request", req.ip(), req.method(), req.baseUrl()) + (Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING ? "(MISSING)" : ""));
}
res.send(response);
}

View File

@ -33,6 +33,8 @@ import java.io.*;
import java.net.URLDecoder;
import java.util.*;
import static emu.grasscutter.utils.Language.translate;
public final class DispatchServer {
public static String query_region_list = "";
public static String query_cur_region = "";
@ -211,21 +213,21 @@ public final class DispatchServer {
sslContextFactory.setKeyStorePassword(Grasscutter.getConfig().getDispatchOptions().KeystorePassword);
} catch (Exception e) {
e.printStackTrace();
Grasscutter.getLogger().warn(Grasscutter.getLanguage().Not_load_keystore);
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.password_error"));
try {
sslContextFactory.setKeyStorePath(keystoreFile.getPath());
sslContextFactory.setKeyStorePassword("123456");
Grasscutter.getLogger().warn(Grasscutter.getLanguage().Use_default_keystore);
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.default_password"));
} catch (Exception e2) {
Grasscutter.getLogger().warn(Grasscutter.getLanguage().Load_keystore_error);
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.general_error"));
e2.printStackTrace();
}
}
serverConnector = new ServerConnector(server, sslContextFactory);
} else {
Grasscutter.getLogger().warn(Grasscutter.getLanguage().Not_find_ssl_cert);
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.no_keystore_error"));
Grasscutter.getConfig().getDispatchOptions().UseSSL = false;
serverConnector = new ServerConnector(server);
@ -245,11 +247,11 @@ public final class DispatchServer {
}
});
httpServer.get("/", (req, res) -> res.send(Grasscutter.getLanguage().Welcome));
httpServer.get("/", (req, res) -> res.send(translate("messages.status.welcome")));
httpServer.raw().error(404, ctx -> {
if(Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING) {
Grasscutter.getLogger().info(Grasscutter.getLanguage().Potential_unhandled_request.replace("{method}", ctx.method()).replace("{url}", ctx.url()));
Grasscutter.getLogger().info(translate("messages.dispatch.unhandled_request_error", ctx.method(), ctx.url()));
}
ctx.contentType("text/html");
ctx.result("<!doctype html><html lang=\"en\"><body><img src=\"https://http.cat/404\" /></body></html>"); // I'm like 70% sure this won't break anything.
@ -307,7 +309,7 @@ public final class DispatchServer {
if (requestData == null) {
return;
}
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_try_login.replace("{ip}", req.ip()));
Grasscutter.getLogger().info(translate("messages.dispatch.account.login_attempt", req.ip()));
res.send(this.getAuthHandler().handleGameLogin(req, requestData));
});
@ -327,7 +329,7 @@ public final class DispatchServer {
return;
}
LoginResultJson responseData = new LoginResultJson();
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_login_token.replace("{ip}", req.ip()));
Grasscutter.getLogger().info(translate("messages.dispatch.account.login_token_attempt"));
// Login
Account account = DatabaseHelper.getAccountById(requestData.uid);
@ -335,16 +337,16 @@ public final class DispatchServer {
// Test
if (account == null || !account.getSessionKey().equals(requestData.token)) {
responseData.retcode = -111;
responseData.message = Grasscutter.getLanguage().Game_account_cache_error;
responseData.message = translate("messages.dispatch.account.account_cache_error");
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_token_login_failed.replace("{ip}", req.ip()));
Grasscutter.getLogger().info(translate("messages.dispatch.account.login_token_error", req.ip()));
} else {
responseData.message = "OK";
responseData.data.account.uid = requestData.uid;
responseData.data.account.token = requestData.token;
responseData.data.account.email = account.getEmail();
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_login_in_token.replace("{ip}", req.ip()).replace("{uid}", responseData.data.account.uid));
Grasscutter.getLogger().info(translate("messages.dispatch.account.login_token_success", req.ip(), requestData.uid));
}
res.send(responseData);
@ -374,16 +376,16 @@ public final class DispatchServer {
// Test
if (account == null || !account.getSessionKey().equals(loginData.token)) {
responseData.retcode = -201;
responseData.message = Grasscutter.getLanguage().Wrong_session_key;
responseData.message = translate("messages.dispatch.account.session_key_error");
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_failed_exchange_combo_token.replace("{ip}", req.ip()));
Grasscutter.getLogger().info(translate("messages.dispatch.account.combo_token_error", req.ip()));
} else {
responseData.message = "OK";
responseData.data.open_id = loginData.uid;
responseData.data.combo_id = "157795300";
responseData.data.combo_token = account.generateLoginToken();
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_exchange_combo_token.replace("{ip}", req.ip()));
Grasscutter.getLogger().info(translate("messages.dispatch.account.combo_token_success", req.ip()));
}
res.send(responseData);
@ -449,7 +451,7 @@ public final class DispatchServer {
httpServer.get("/gcstatic/*", new StaticFileHandler());
httpServer.listen(Grasscutter.getConfig().getDispatchOptions().Port);
Grasscutter.getLogger().info(Grasscutter.getLanguage().Dispatch_start_server_port.replace("{port}", Integer.toString(httpServer.raw().port())));
Grasscutter.getLogger().info(translate("messages.dispatch.port_bind", Integer.toString(httpServer.raw().port())));
}
private Map<String, String> parseQueryString(String qs) {

View File

@ -29,6 +29,8 @@ import java.time.OffsetDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static emu.grasscutter.utils.Language.translate;
public final class GameServer extends KcpServer {
private final InetSocketAddress address;
private final GameServerPacketHandler packetHandler;
@ -48,6 +50,13 @@ public final class GameServer extends KcpServer {
private final CombineManger combineManger;
public GameServer() {
this(new InetSocketAddress(
Grasscutter.getConfig().getGameServerOptions().Ip,
Grasscutter.getConfig().getGameServerOptions().Port
));
}
public GameServer(InetSocketAddress address) {
super(address);
@ -76,7 +85,7 @@ public final class GameServer extends KcpServer {
try {
onTick();
} catch (Exception e) {
Grasscutter.getLogger().error(Grasscutter.getLanguage().An_error_occurred_during_game_update, e);
Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e);
}
}
}, new Date(), 1000L);
@ -214,8 +223,8 @@ public final class GameServer extends KcpServer {
@Override
public void onStartFinish() {
Grasscutter.getLogger().info(Grasscutter.getLanguage().Grasscutter_is_free);
Grasscutter.getLogger().info(Grasscutter.getLanguage().Game_start_port.replace("{port}", Integer.toString(address.getPort())));
Grasscutter.getLogger().info(translate("messages.status.free_software"));
Grasscutter.getLogger().info(translate("messages.game.port_bind", Integer.toString(address.getPort())));
ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call();
}

View File

@ -22,6 +22,8 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import static emu.grasscutter.utils.Language.translate;
public class GameSession extends KcpChannel {
private GameServer server;
@ -113,21 +115,21 @@ public class GameSession extends KcpChannel {
@Override
protected void onConnect() {
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_connect.replace("{address}", getAddress().getHostString().toLowerCase()));
Grasscutter.getLogger().info(translate("messages.game.connect", this.getAddress().getHostString().toLowerCase()));
}
@Override
protected synchronized void onDisconnect() { // Synchronize so we dont add character at the same time
Grasscutter.getLogger().info(Grasscutter.getLanguage().Client_disconnect.replace("{address}", getAddress().getHostString().toLowerCase()));
protected synchronized void onDisconnect() { // Synchronize so we don't add character at the same time.
Grasscutter.getLogger().info(translate("messages.game.disconnect", this.getAddress().getHostString().toLowerCase()));
// Set state so no more packets can be handled
this.setState(SessionState.INACTIVE);
// Save after disconnecting
if (this.isLoggedIn()) {
// Save
// Call logout event.
getPlayer().onLogout();
// Remove from gameserver
// Remove from server.
getServer().getPlayers().remove(getPlayer().getUid());
}
}

View File

@ -93,6 +93,7 @@ public final class Tools {
}
Grasscutter.getLogger().info("GM Handbook generated!");
System.exit(0);
}
@SuppressWarnings("deprecation")
@ -184,6 +185,8 @@ public final class Tools {
writer.println(",\"200\": \"Standard\", \"301\": \"Avatar Event\", \"302\": \"Weapon event\"");
writer.println("}\n}");
}
Grasscutter.getLogger().info("Mappings generated!");
System.exit(0);
}
}

View File

@ -15,6 +15,8 @@ import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"})
public final class Utils {
public static final Random random = new Random();
@ -176,15 +178,15 @@ public final class Utils {
// Check for resources folder.
if(!fileExists(resourcesFolder)) {
logger.info(Grasscutter.getLanguage().Create_resources_folder);
logger.info(Grasscutter.getLanguage().Place_copy);
logger.info(translate("messages.status.create_resources"));
logger.info(translate("messages.status.resources_error"));
createFolder(resourcesFolder); exit = true;
}
// Check for BinOutput + ExcelBinOuput.
// Check for BinOutput + ExcelBinOutput.
if(!fileExists(resourcesFolder + "BinOutput") ||
!fileExists(resourcesFolder + "ExcelBinOutput")) {
logger.info(Grasscutter.getLanguage().Place_copy);
logger.info(translate("messages.status.resources_error"));
exit = true;
}
@ -195,7 +197,11 @@ public final class Utils {
if(exit) System.exit(1);
}
public static int GetNextTimestampOfThisHour(int hour, String timeZone, int param) {
/**
* Gets the timestamp of the next hour.
* @return The timestamp in UNIX seconds.
*/
public static int getNextTimestampOfThisHour(int hour, String timeZone, int param) {
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone));
for (int i = 0; i < param; i ++){
if (zonedDateTime.getHour() < hour) {
@ -204,10 +210,14 @@ public final class Utils {
zonedDateTime = zonedDateTime.plusDays(1).withHour(hour).withMinute(0).withSecond(0);
}
}
return (int)zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond();
return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond();
}
public static int GetNextTimestampOfThisHourInNextWeek(int hour, String timeZone, int param) {
/**
* Gets the timestamp of the next hour in a week.
* @return The timestamp in UNIX seconds.
*/
public static int getNextTimestampOfThisHourInNextWeek(int hour, String timeZone, int param) {
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone));
for (int i = 0; i < param; i++) {
if (zonedDateTime.getDayOfWeek() == DayOfWeek.MONDAY && zonedDateTime.getHour() < hour) {
@ -216,10 +226,14 @@ public final class Utils {
zonedDateTime = zonedDateTime.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).withHour(hour).withMinute(0).withSecond(0);
}
}
return (int)zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond();
return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond();
}
public static int GetNextTimestampOfThisHourInNextMonth(int hour, String timeZone, int param) {
/**
* Gets the timestamp of the next hour in a month.
* @return The timestamp in UNIX seconds.
*/
public static int getNextTimestampOfThisHourInNextMonth(int hour, String timeZone, int param) {
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone));
for (int i = 0; i < param; i++) {
if (zonedDateTime.getDayOfMonth() == 1 && zonedDateTime.getHour() < hour) {
@ -228,6 +242,22 @@ public final class Utils {
zonedDateTime = zonedDateTime.with(TemporalAdjusters.firstDayOfNextMonth()).withHour(hour).withMinute(0).withSecond(0);
}
}
return (int)zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond();
return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond();
}
/**
* Retrieves a string from an input stream.
* @param stream The input stream.
* @return The string.
*/
public static String readFromInputStream(InputStream stream) {
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
String line; while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
} stream.close();
} catch (IOException e) {
Grasscutter.getLogger().warn("Failed to read from input stream.");
} return stringBuilder.toString();
}
}

View File

@ -0,0 +1,295 @@
{
"messages": {
"game": {
"port_bind": "Game Server started on port %s",
"connect": "Client connected from %s",
"disconnect": "Client disconnected from %s",
"game_update_error": "An error occurred during game update.",
"command_error": "Command error:"
},
"dispatch": {
"port_bind": "[Dispatch] Dispatch server started on port %s",
"request": "[Dispatch] Client %s %s request: %s",
"keystore": {
"general_error": "[Dispatch] Error while loading keystore!",
"password_error": "[Dispatch] Unable to load keystore. Trying default keystore password...",
"no_keystore_error": "[Dispatch] No SSL cert found! Falling back to HTTP server.",
"default_password": "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json."
},
"no_commands_error": "Commands are not supported in dispatch only mode.",
"unhandled_request_error": "[Dispatch] Potential unhandled %s request: %s",
"account": {
"login_attempt": "[Dispatch] Client %s is trying to log in",
"login_success": "[Dispatch] Client %s logged in as %s",
"login_token_attempt": "[Dispatch] Client %s is trying to log in via token",
"login_token_error": "[Dispatch] Client %s failed to log in via token",
"login_token_success": "[Dispatch] Client %s logged in via token as %s",
"combo_token_success": "[Dispatch] Client %s succeed to exchange combo token",
"combo_token_error": "[Dispatch] Client %s failed to exchange combo token",
"account_login_create_success": "[Dispatch] Client %s failed to log in: Account %s created",
"account_login_create_error": "[Dispatch] Client %s failed to log in: Account create failed",
"account_login_exist_error": "[Dispatch] Client %s failed to log in: Account no found",
"account_cache_error": "Game account cache information error",
"session_key_error": "Wrong session key.",
"username_error": "Username not found.",
"username_create_error": "Username not found, create failed."
}
},
"status": {
"free_software": "Grasscutter is FREE software. If you have paid for this, you may have been scammed. Homepage: https://github.com/Grasscutters/Grasscutter",
"starting": "Starting Grasscutter...",
"shutdown": "Shutting down...",
"done": "Done! For help, type \"help\"",
"error": "An error occurred.",
"welcome": "Welcome to Grasscutter",
"run_mode_error": "Invalid server run mode: %s.",
"run_mode_help": "Server run mode must be 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Unable to start Grasscutter...",
"create_resources": "Creating resources folder...",
"resources_error": "Place a copy of 'BinOutput' and 'ExcelBinOutput' in the resources folder."
}
},
"commands": {
"generic": {
"not_specified": "No command specified.",
"unknown_command": "Unknown command: %s",
"permission_error": "You do not have permission to run this command.",
"console_execute_error": "This command can only be run from the console.",
"player_execute_error": "Run this command in-game.",
"command_exist_error": "No command found.",
"invalid": {
"amount": "Invalid amount.",
"artifactId": "Invalid artifactId.",
"avatarId": "Invalid avatarId.",
"avatarLevel": "Invalid avatarLevel.",
"entityId": "Invalid entityId.",
"itemId": "Invalid itemId.",
"itemLevel": "Invalid itemLevel.",
"itemRefinement": "Invalid itemRefinement.",
"playerId": "Invalid playerId.",
"uid": "Invalid UID."
}
},
"execution": {
"uid_error": "Invalid UID.",
"player_exist_error": "Player not found.",
"player_offline_error": "Player is not online.",
"item_id_error": "Invalid item ID.",
"item_player_exist_error": "Invalid item or UID.",
"entity_id_error": "Invalid entity ID.",
"player_exist_offline_error": "Player not found or is not online.",
"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."
},
"status": {
"enabled": "Enabled",
"disabled": "Disabled",
"help": "Help",
"success": "Success"
},
"account": {
"modify": "Modify user accounts",
"invalid": "Invalid UID.",
"exists": "Account already exists.",
"create": "Account created with UID %s.",
"delete": "Account deleted.",
"no_account": "Account not found.",
"command_usage": "Usage: account <create|delete> <username> [uid]"
},
"broadcast": {
"command_usage": "Usage: broadcast <message>",
"message_sent": "Message sent."
},
"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."
},
"clear": {
"command_usage": "Usage: clear <all|wp|art|mat>",
"weapons": "Cleared weapons for %s.",
"artifacts": "Cleared artifacts for %s.",
"materials": "Cleared materials for %s.",
"furniture": "Cleared furniture for %s.",
"displays": "Cleared displays for %s.",
"virtuals": "Cleared virtuals for %s.",
"everything": "Cleared everything for %s."
},
"coop": {
"usage": "Usage: coop <playerId> <target playerId>"
},
"enter_dungeon": {
"usage": "Usage: enterdungeon <dungeon id>",
"changed": "Changed to dungeon %s",
"not_found_error": "Dungeon does not exist",
"in_dungeon_error": "You are already in that dungeon"
},
"giveAll": {
"usage": "Usage: giveall [player] [amount]",
"item": "Giving all items...",
"done": "Giving all items done",
"invalid_amount_or_playerId": "Invalid amount or player ID."
},
"giveArtifact": {
"usage": "Usage: giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]",
"invalid_artifact_id": "Invalid artifact ID.",
"given": "Given %s to %s."
},
"giveChar": {
"usage": "Usage: givechar <player> <itemId|itemName> [amount]",
"given": "Given %s with level %s to %s.",
"invalid_avatar_id": "Invalid avatar id.",
"invalid_avatar_level": "Invalid avatar level.",
"invalid_avatar_or_player_id": "Invalid avatar or player ID."
},
"give": {
"usage": "Usage: give <player> <itemId|itemName> [amount] [level]",
"refinement_only_applicable_weapons": "Refinement is only applicable to weapons.",
"refinement_must_between_1_and_5": "Refinement must be between 1 and 5.",
"given": "Given %s of %s to %s.",
"given_with_level_and_refinement": "Given %s with level %s, refinement %s %s times to %s",
"given_level": "Given %s with level %s %s times to %s"
},
"godmode": {
"success": "Godmode is now %s for %s."
},
"heal": {
"success": "All characters have been healed."
},
"kick": {
"player_kick_player": "Player [%s:%s] has kicked player [%s:%s]",
"server_kick_player": "Kicking player [%s:%s]"
},
"kill": {
"usage": "Usage: killall [playerUid] [sceneId]",
"scene_not_found_in_player_world": "Scene not found in player world",
"kill_monsters_in_scene": "Killing %s monsters in scene %s"
},
"killCharacter": {
"usage": "Usage: /killcharacter [playerId]",
"current_character": "Killed %s current character."
},
"list": {
"message": "There are %s player(s) online:"
},
"permission": {
"usage": "Usage: permission <add|remove> <username> <permission>",
"add": "Permission added.",
"have_permission": "They already have this permission!",
"remove": "Permission removed.",
"not_have_permission": "They don't have this permission!"
},
"position": {
"success": "Coordinates: %.3f, %.3f, %.3f\nScene id: %d"
},
"reload": {
"reload_start": "Reloading config.",
"reload_done": "Reload complete."
},
"resetConst": {
"reset_all": "Reset all avatars' constellations.",
"success": "Constellations for %s have been reset. Please relog to see changes."
},
"resetShopLimit": {
"usage": "Usage: /resetshop <player id>"
},
"sendMail": {
"usage": "Usage: give [player] <itemId|itemName> [amount]",
"user_not_exist": "The user with an id of '%s' does not exist",
"start_composition": "Starting composition of message.\nPlease use `/sendmail <title>` to continue.\nYou can use `/sendmail stop` at any time",
"templates": "Mail templates coming soon implemented...",
"invalid_arguments": "Invalid arguments.\nUsage `/sendmail <userId|all|help> [templateId]`",
"send_cancel": "Message sending cancelled",
"send_done": "Message sent to user %s!",
"send_all_done": "Message sent to all users!",
"not_composition_end": "Message composition not at final stage.\nPlease use `/sendmail %s` or `/sendmail stop` to cancel",
"please_use": "Please use `/sendmail %s`",
"set_title": "Message title set as '%s'.\nUse '/sendmail <content>' to continue.",
"set_contents": "Message contents set as '%s'.\nUse '/sendmail <sender>' to continue.",
"set_message_sender": "Message sender set as '%s'.\nUse '/sendmail <itemId|itemName|finish> [amount] [level]' to continue.",
"send": "Attached %s of %s (level %s) to the message.\nContinue adding more items or use `/sendmail finish` to send the message.",
"invalid_arguments_please_use": "Invalid arguments \n Please use `/sendmail %s`",
"title": "<title>",
"message": "<message>",
"sender": "<sender>",
"arguments": "<itemId|itemName|finish> [amount] [level]",
"error": "ERROR: invalid construction stage %s. Check console for stacktrace."
},
"sendMessage": {
"usage": "Usage: sendmessage <player> <message>",
"message_sent": "Message sent."
},
"setFetterLevel": {
"usage": "Usage: setfetterlevel <level>",
"fetter_level_must_between_0_and_10": "Fetter level must be between 0 and 10.",
"fetter_set_level": "Fetter level set to %s",
"invalid_fetter_level": "Invalid fetter level."
},
"setStats": {
"usage_console": "Usage: setstats|stats @<UID> <stat> <value>",
"usage_ingame": "Usage: setstats|stats [@UID] <stat> <value>",
"help_message": "\n\tValues for <stat>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
"value_error": "Invalid stat value.",
"uid_error": "Invalid UID.",
"player_error": "Player not found or offline.",
"set_self": "%s set to %s.",
"set_for_uid": "%s for %s set to %s.",
"set_max_hp": "MAX HP set to %s."
},
"setWorldLevel": {
"usage": "Usage: setworldlevel <level>",
"world_level_must_between_0_and_8": "World level must be between 0-8",
"set_world_level": "World level set to %s.",
"invalid_world_level": "Invalid world level."
},
"spawn": {
"usage": "Usage: spawn <entityId> [amount] [level(monster only)]",
"message": "Spawned %s of %s."
},
"stop": {
"message": "Server shutting down..."
},
"talent": {
"usage_1": "To set talent level: /talent set <talentID> <value>",
"usage_2": "Another way to set talent level: /talent <n or e or q> <value>",
"usage_3": "To get talent ID: /talent getid",
"lower_16": "Invalid talent level. Level should be lower than 16",
"set_id": "Set talent to %s.",
"set_atk": "Set talent Normal ATK to %s.",
"set_e": "Set talent E to %s.",
"set_q": "Set talent Q to %s.",
"invalid_skill_id": "Invalid skill ID.",
"set_this": "Set this talent to %s.",
"invalid_level": "Invalid talent level.",
"normal_attack_id": "Normal Attack ID %s.",
"e_skill_id": "E skill ID %s.",
"q_skill_id": "Q skill ID %s."
},
"teleportAll": {
"message": "You only can use this command in MP mode."
},
"teleport": {
"usage_server": "Usage: /tp @<player id> <x> <y> <z> [scene id]",
"usage": "Usage: /tp [@<player id>] <x> <y> <z> [scene id]",
"specify_player_id": "You must specify a player id.",
"invalid_position": "Invalid position.",
"message": "Teleported %s to %s,%s,%s in scene %s"
},
"weather": {
"usage": "Usage: weather <weatherId> [climateId]",
"message": "Changed weather to %s with climate %s",
"invalid_id": "Invalid ID."
},
"drop": {
"command_usage": "Usage: drop <itemId|itemName> [amount]",
"success": "Dropped %s of %s."
},
"help": {
"usage": "Usage: ",
"aliases": "Aliases: ",
"available_commands": "Available commands: "
}
}
}