Commit 19d81463 authored by KingRainbow44's avatar KingRainbow44
Browse files

Merge remote-tracking branch 'origin/development' into development

parents 71b118dd e3e917ef
......@@ -78,4 +78,5 @@ BuildConfig.java
# macOS
.DS_Store
.directory
data/hk4e/announcement/
......@@ -93,6 +93,8 @@ dependencies {
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
testCompileOnly 'org.projectlombok:lombok:1.18.24'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.24'
}
configurations.all {
......
......@@ -18,6 +18,11 @@ public final class GameConstants {
public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player".
public static final int BATTLE_PASS_MAX_LEVEL = 50;
public static final int BATTLE_PASS_POINT_PER_LEVEL = 1000;
public static final int BATTLE_PASS_POINT_PER_WEEK = 10000;
public static final int BATTLE_PASS_LEVEL_PRICE = 150;
// Default entity ability hashes.
public static final String[] DEFAULT_ABILITY_STRINGS = {
"Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible",
......
......@@ -109,6 +109,79 @@ public final class CommandMap {
return this.commands.get(label);
}
private Player getTargetPlayer(String playerId, Player player, Player targetPlayer, List<String> args) {
// Top priority: If any @UID argument is present, override targetPlayer with it.
for (int i = 0; i < args.size(); i++) {
String arg = args.get(i);
if (arg.startsWith("@")) {
arg = args.remove(i).substring(1);
if (arg.equals("")) {
// This is a special case to target nothing, distinct from failing to assign a target.
// This is specifically to allow in-game players to run a command without targeting themselves or anyone else.
return null;
}
try {
int uid = Integer.parseInt(arg);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
throw new IllegalArgumentException();
}
return targetPlayer;
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
throw new IllegalArgumentException();
}
}
}
// Next priority: If we invoked with a target, use that.
// By default, this only happens when you message another player in-game with a command.
if (targetPlayer != null) {
return targetPlayer;
}
// Next priority: Use previously-set target. (see /target [[@]UID])
if (targetPlayerIds.containsKey(playerId)) {
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(targetPlayerIds.get(playerId), true);
// We check every time in case the target is deleted after being targeted
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
throw new IllegalArgumentException();
}
return targetPlayer;
}
// Lowest priority: Target the player invoking the command. In the case of the console, this will return null.
return player;
}
private boolean setPlayerTarget(String playerId, Player player, String targetUid) {
if (targetUid.equals("")) { // Clears the default targetPlayer.
targetPlayerIds.remove(playerId);
CommandHandler.sendTranslatedMessage(player, "commands.execution.clear_target");
return true;
}
// Sets default targetPlayer to the UID provided.
try {
int uid = Integer.parseInt(targetUid);
Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return false;
}
targetPlayerIds.put(playerId, uid);
CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", targetUid);
CommandHandler.sendTranslatedMessage(player, targetPlayer.isOnline()? "commands.execution.set_target_online" : "commands.execution.set_target_offline", targetUid);
return true;
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
return false;
}
}
/**
* Invoke a command handler with the given arguments.
*
......@@ -129,39 +202,21 @@ public final class CommandMap {
String playerId = (player == null) ? consoleId : player.getAccount().getId();
// Check for special cases - currently only target command.
String targetUidStr = null;
if (label.startsWith("@")) { // @[UID]
targetUidStr = label.substring(1);
this.setPlayerTarget(playerId, player, label.substring(1));
return;
} else if (label.equalsIgnoreCase("target")) { // target [[@]UID]
if (args.size() > 0) {
targetUidStr = args.get(0);
String targetUidStr = args.get(0);
if (targetUidStr.startsWith("@")) {
targetUidStr = targetUidStr.substring(1);
}
this.setPlayerTarget(playerId, player, targetUidStr);
return;
} else {
targetUidStr = "";
}
}
if (targetUidStr != null) {
if (targetUidStr.equals("")) { // Clears the default targetPlayer.
this.targetPlayerIds.remove(playerId);
CommandHandler.sendTranslatedMessage(player, "commands.execution.clear_target");
} else { // Sets default targetPlayer to the UID provided.
try {
int uid = Integer.parseInt(targetUidStr);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
} else {
this.targetPlayerIds.put(playerId, uid);
CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", targetUidStr);
CommandHandler.sendTranslatedMessage(player, targetPlayer.isOnline() ? "commands.execution.set_target_online" : "commands.execution.set_target_offline", targetUidStr);
}
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(player, "commands.generic.invalid.uid");
}
this.setPlayerTarget(playerId, player, "");
return;
}
return;
}
// Get command handler.
......@@ -179,38 +234,11 @@ public final class CommandMap {
// Get the command's annotation.
Command annotation = this.annotations.get(label);
// If any @UID argument is present, override targetPlayer with it.
for (int i = 0; i < args.size(); i++) {
String arg = args.get(i);
if (arg.startsWith("@")) {
arg = args.remove(i).substring(1);
try {
int uid = Integer.parseInt(arg);
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return;
}
break;
} catch (NumberFormatException e) {
CommandHandler.sendTranslatedMessage(player, "commands.generic.invalid.uid");
return;
}
}
}
// If there's still no targetPlayer at this point, use previously-set target
if (targetPlayer == null) {
if (this.targetPlayerIds.containsKey(playerId)) {
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(this.targetPlayerIds.get(playerId), true); // We check every time in case the target is deleted after being targeted
if (targetPlayer == null) {
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
return;
}
} else {
// If there's still no targetPlayer at this point, use executor.
targetPlayer = player;
}
// Resolve targetPlayer
try{
targetPlayer = getTargetPlayer(playerId, player, targetPlayer, args);
} catch (IllegalArgumentException e) {
return;
}
// Check for permissions.
......
......@@ -2,36 +2,26 @@ package emu.grasscutter.command.commands;
import java.util.List;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.server.game.GameSession;
@Command(
label = "ban",
usage = "ban <player> [time] [reason]",
usage = "ban <@player> [time] [reason]",
description = "commands.ban.description",
targetRequirement = Command.TargetRequirement.NONE
permission = "server.ban",
targetRequirement = Command.TargetRequirement.PLAYER
)
public final class BanCommand implements CommandHandler {
private boolean banAccount(int uid, int time, String reason) {
Player player = Grasscutter.getGameServer().getPlayerByUid(uid, true);
if (player == null) {
return false;
}
private boolean banAccount(Player targetPlayer, int time, String reason) {
Account account = targetPlayer.getAccount();
Account account = player.getAccount();
if (account == null) {
account = DatabaseHelper.getAccountByPlayerId(uid);
if (account == null) {
return false;
}
return false;
}
account.setBanReason(reason);
......@@ -40,51 +30,36 @@ public final class BanCommand implements CommandHandler {
account.setBanned(true);
account.save();
Player banUser = Grasscutter.getGameServer().getPlayerByUid(uid);
if (banUser != null) {
banUser.getSession().close();
GameSession session = targetPlayer.getSession();
if (session != null) {
session.close();
}
return true;
}
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.command_usage"));
return;
}
int uid = 0;
int time = 2051190000;
String reason = "Reason not specified.";
if (args.size() >= 1) {
try {
uid = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.invalid_player_id"));
return;
}
}
if (args.size() >= 2) {
try {
time = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.invalid_time"));
return;
}
}
if (args.size() >= 3) {
reason = args.get(2);
switch (args.size()) {
case 2:
reason = args.get(1); // Fall-through
case 1:
try {
time = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
CommandHandler.sendTranslatedMessage(sender, "commands.ban.invalid_time");
return;
} // Fall-through, unimportant
default:
break;
}
if (banAccount(uid, time, reason)) {
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.success"));
if (banAccount(targetPlayer, time, reason)) {
CommandHandler.sendTranslatedMessage(sender, "commands.ban.success");
} else {
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.failure"));
CommandHandler.sendTranslatedMessage(sender, "commands.ban.failure");
}
}
}
\ No newline at end of file
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "broadcast", usage = "broadcast <message>", aliases = {"b"}, permission = "server.broadcast", description = "commands.broadcast.description", targetRequirement = Command.TargetRequirement.NONE)
public final class BroadcastCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.command_usage"));
return;
}
String message = String.join(" ", args.subList(0, args.size()));
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
CommandHandler.sendMessage(p, message);
}
CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.message_sent"));
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "changescene", usage = "changescene <sceneId>", aliases = {"scene"}, permission = "player.changescene", permissionTargeted = "player.changescene.others", description = "commands.changescene.description")
public final class ChangeSceneCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() != 1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.usage"));
return;
}
try {
int sceneId = Integer.parseInt(args.get(0));
if (sceneId == targetPlayer.getSceneId()) {
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.already_in_scene"));
return;
}
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, targetPlayer.getPos());
if (!result) {
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.exists_error"));
return;
}
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.success", Integer.toString(sceneId)));
} catch (Exception e) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
}
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Position;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "drop", usage = "drop <itemId|itemName> [amount]", aliases = {"d", "dropitem"}, permission = "server.drop", permissionTargeted = "server.drop.others", description = "commands.drop.description")
public final class DropCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
int item = 0;
int amount = 1;
switch (args.size()) {
case 2:
try {
amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
return;
} // Slightly cheeky here: no break, so it falls through to initialize the first argument too
case 1:
try {
item = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
return;
}
break;
default:
CommandHandler.sendMessage(sender, translate(sender, "commands.drop.command_usage"));
return;
}
ItemData itemData = GameData.getItemDataMap().get(item);
if (itemData == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
return;
}
if (itemData.isEquip()) {
float range = (5f + (.1f * amount));
for (int i = 0; i < amount; i++) {
Position pos = targetPlayer.getPos().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f).addZ((float) (Math.random() * range) - (range / 2));
EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, pos, 1);
targetPlayer.getScene().addEntity(entity);
}
} else {
EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, targetPlayer.getPos().clone().addY(3f), amount);
targetPlayer.getScene().addEntity(entity);
}
CommandHandler.sendMessage(sender, translate(sender, "commands.drop.success", Integer.toString(amount), Integer.toString(item)));
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.AvatarData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.player.Player;
import java.util.*;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "giveall", usage = "giveall [amount]", aliases = {"givea"}, permission = "player.giveall", permissionTargeted = "player.giveall.others", threading = true, description = "commands.giveAll.description")
public final class GiveAllCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
int amount = 99999;
switch (args.size()) {
case 0:
break;
case 1: // [amount]
try {
amount = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
return;
}
break;
default: // invalid
CommandHandler.sendMessage(sender, translate(sender, "commands.giveAll.usage"));
return;
}
this.giveAllItems(targetPlayer, amount);
CommandHandler.sendMessage(sender, translate(targetPlayer, "commands.giveAll.success", targetPlayer.getNickname()));
}
public void giveAllItems(Player player, int amount) {
CommandHandler.sendMessage(player, translate(player, "commands.giveAll.started"));
for (AvatarData avatarData: GameData.getAvatarDataMap().values()) {
//Exclude test avatar
if (isTestAvatar(avatarData.getId())) continue;
Avatar avatar = new Avatar(avatarData);
avatar.setLevel(90);
avatar.setPromoteLevel(6);
// Add constellations.
int talentBase = switch (avatar.getAvatarId()) {
case 10000005 -> 70;
case 10000006 -> 40;
default -> (avatar.getAvatarId()-10000000)*10;
};
for(int i = 1;i <= 6;++i){
avatar.getTalentIdList().add(talentBase + i);
}
// Handle skill depot for traveller.
if (avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_MALE) {
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(504));
}
else if(avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_FEMALE) {
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(704));
}
// This will handle stats and talents
avatar.recalcStats();
// Don't try to add each avatar to the current team
player.addAvatar(avatar, false);
}
//some test items
List<GameItem> itemList = new ArrayList<>();
for (ItemData itemdata: GameData.getItemDataMap().values()) {
//Exclude test item
if (isTestItem(itemdata.getId())) continue;
if (itemdata.isEquip()) {
if (itemdata.getItemType() == ItemType.ITEM_WEAPON) {
for (int i = 0; i < 5; ++i) {
GameItem item = new GameItem(itemdata);
item.setLevel(90);
item.setPromoteLevel(6);
item.setRefinement(4);
itemList.add(item);
}
}
}
else {
GameItem item = new GameItem(itemdata);
item.setCount(amount);
itemList.add(item);
}
}
int packetNum = 10;
int itemLength = itemList.size();
int number = itemLength / packetNum;
int remainder = itemLength % packetNum;
int offset = 0;
for (int i = 0; i < packetNum; ++i) {
if (remainder > 0) {
player.getInventory().addItems(itemList.subList(i * number + offset, (i + 1) * number + offset + 1));
--remainder;
++offset;
}
else {
player.getInventory().addItems(itemList.subList(i * number + offset, (i + 1) * number + offset));
}
}
}
public boolean isTestAvatar(int avatarId) {
return avatarId < 10000002 || avatarId >= 11000000;
}
public boolean isTestItem(int itemId) {
for (Range range: testItemRanges) {
if (range.check(itemId)) {
return true;
}
}
return testItemsList.contains(itemId);
}
static class Range {
private final int min, max;
public Range(int min, int max) {
if(min > max){
min ^= max;
max ^= min;
min ^= max;
}
this.min = min;
this.max = max;
}
public boolean check(int value) {
return value >= this.min && value <= this.max;
}
}
private static final Range[] testItemRanges = new Range[] {
new Range(106, 139),
new Range(1000, 1099),
new Range(2001, 3022),
new Range(23300, 23340),
new Range(23383, 23385),
new Range(78310, 78554),
new Range(99310, 99554),
new Range(100001, 100187),
new Range(100210, 100214),
new Range(100303, 100398),
new Range(100414, 100425),
new Range(100454, 103008),
new Range(109000, 109492),
new Range(115001, 118004),
new Range(141001, 141072),
new Range(220050, 221016),
};
private static final Integer[] testItemsIds = new Integer[] {
210, 211, 314, 315, 317, 1005, 1007, 1105, 1107, 1201, 1202,10366,
101212, 11411, 11506, 11507, 11508, 12505, 12506, 12508, 12509, 13503,
13506, 14411, 14503, 14505, 14508, 15504, 15505, 15506,
20001, 10002, 10003, 10004, 10005, 10006, 10008,100231,100232,100431,
101689,105001,105004, 106000,106001,108000,110000
};
private static final Collection<Integer> testItemsList = Arrays.asList(testItemsIds);
}
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.inventory.EquipType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "giveart", usage = "giveart <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]", aliases = {"gart"}, permission = "player.giveart", permissionTargeted = "player.giveart.others", description = "commands.giveArtifact.description")
public final class GiveArtifactCommand implements CommandHandler {
private static final Map<String, Map<EquipType, Integer>> mainPropMap = Map.ofEntries(
entry("hp", Map.ofEntries(entry(EquipType.EQUIP_BRACER, 14001))),
entry("hp%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10980), entry(EquipType.EQUIP_RING, 50980), entry(EquipType.EQUIP_DRESS, 30980))),
entry("atk", Map.ofEntries(entry(EquipType.EQUIP_NECKLACE, 12001))),
entry("atk%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10990), entry(EquipType.EQUIP_RING, 50990), entry(EquipType.EQUIP_DRESS, 30990))),
entry("def%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10970), entry(EquipType.EQUIP_RING, 50970), entry(EquipType.EQUIP_DRESS, 30970))),
entry("er", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10960))),
entry("em", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10950), entry(EquipType.EQUIP_RING, 50880), entry(EquipType.EQUIP_DRESS, 30930))),
entry("hb", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30940))),
entry("cdmg", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30950))),
entry("cr", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30960))),
entry("phys%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50890))),
entry("dendro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50900))),
entry("geo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50910))),
entry("anemo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50920))),
entry("hydro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50930))),
entry("cryo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50940))),
entry("electro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50950))),
entry("pyro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50960)))
);
private static final Map<String, String> appendPropMap = Map.ofEntries(
entry("hp", "0102"),
entry("hp%", "0103"),
entry("atk", "0105"),
entry("atk%", "0106"),
entry("def", "0108"),
entry("def%", "0109"),
entry("er", "0123"),
entry("em", "0124"),
entry("cr", "0120"),
entry("cdmg", "0122")
);
private int getAppendPropId(String substatText, ItemData itemData) {
int res;
// If the given substat text is an integer, we just use that
// as the append prop ID.
try {
res = Integer.parseInt(substatText);
return res;
}
catch (NumberFormatException ignores) {
// No need to handle this here. We just continue with the
// possibility of the argument being a substat string.
}
// If the argument was not an integer, we try to determine
// the append prop ID from the given text + artifact information.
// A substat string has the format `substat_tier`, with the
// `_tier` part being optional.
String[] substatArgs = substatText.split("_");
String substatType;
int substatTier;
if (substatArgs.length == 1) {
substatType = substatArgs[0];
substatTier =
itemData.getRankLevel() == 1 ? 2
: itemData.getRankLevel() == 2 ? 3
: 4;
}
else if (substatArgs.length == 2) {
substatType = substatArgs[0];
substatTier = Integer.parseInt(substatArgs[1]);
}
else {
throw new IllegalArgumentException();
}
// Check if the specified tier is legal for the artifact rarity.
if (substatTier < 1 || substatTier > 4) {
throw new IllegalArgumentException();
}
if (itemData.getRankLevel() == 1 && substatTier > 2) {
throw new IllegalArgumentException();
}
if (itemData.getRankLevel() == 2 && substatTier > 3) {
throw new IllegalArgumentException();
}
// Check if the given substat type string is a legal stat.
if (!appendPropMap.containsKey(substatType)) {
throw new IllegalArgumentException();
}
// Build the append prop ID.
return Integer.parseInt(Integer.toString(itemData.getRankLevel()) + appendPropMap.get(substatType) + Integer.toString(substatTier));
}
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
// Sanity check
if (args.size() < 2) {
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.usage"));
return;
}
// Get the artifact piece ID from the arguments.
int itemId;
try {
itemId = Integer.parseInt(args.remove(0));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.id_error"));
return;
}
ItemData itemData = GameData.getItemDataMap().get(itemId);
if (itemData.getItemType() != ItemType.ITEM_RELIQUARY) {
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.id_error"));
return;
}
// Get the main stat from the arguments.
// If the given argument is an integer, we use that.
// If not, we check if the argument string is in the main prop map.
String mainPropIdString = args.remove(0);
int mainPropId;
try {
mainPropId = Integer.parseInt(mainPropIdString);
} catch (NumberFormatException ignored) {
mainPropId = -1;
}
if (mainPropMap.containsKey(mainPropIdString) && mainPropMap.get(mainPropIdString).containsKey(itemData.getEquipType())) {
mainPropId = mainPropMap.get(mainPropIdString).get(itemData.getEquipType());
}
if (mainPropId == -1) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
return;
}
// Get the level from the arguments.
int level = 1;
try {
int last = Integer.parseInt(args.get(args.size()-1));
if (last > 0 && last < 22) { // Luckily appendPropIds aren't in the range of [1,21]
level = last;
args.remove(args.size()-1);
}
} catch (NumberFormatException ignored) { // Could be a stat,times string so no need to panic
}
// Get substats.
ArrayList<Integer> appendPropIdList = new ArrayList<>();
try {
// Every remaining argument is a substat.
args.forEach(it -> {
// The substat syntax permits specifying a number of rolls for the given
// substat. Split the string into stat and number if that is the case here.
String[] arr;
int n = 1;
if ((arr = it.split(",")).length == 2) {
it = arr[0];
n = Integer.parseInt(arr[1]);
if (n > 200) {
n = 200;
}
}
// Determine the substat ID.
int appendPropId = getAppendPropId(it, itemData);
// Add the current substat.
appendPropIdList.addAll(Collections.nCopies(n, appendPropId));
});
} catch (Exception ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
return;
}
// Create item for the artifact.
GameItem item = new GameItem(itemData);
item.setLevel(level);
item.setMainPropId(mainPropId);
item.getAppendPropIdList().clear();
item.getAppendPropIdList().addAll(appendPropIdList);
targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop);
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.success", Integer.toString(itemId), Integer.toString(targetPlayer.getUid())));
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.AvatarData;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "givechar", usage = "givechar <avatarId> [level]", aliases = {"givec"}, permission = "player.givechar", permissionTargeted = "player.givechar.others", description = "commands.giveChar.description")
public final class GiveCharCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
int avatarId;
int level = 1;
switch (args.size()) {
case 2:
try {
level = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) {
// TODO: Parse from avatar name using GM Handbook.
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarLevel"));
return;
} // Cheeky fall-through to parse first argument too
case 1:
try {
avatarId = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) {
// TODO: Parse from avatar name using GM Handbook.
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarId"));
return;
}
break;
default:
CommandHandler.sendMessage(sender, translate(sender, "commands.giveChar.usage"));
return;
}
AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
if (avatarData == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarId"));
return;
}
// Check level.
if (level > 90) {
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarLevel"));
return;
}
// Calculate ascension level.
int ascension;
if (level <= 40) {
ascension = (int) Math.ceil(level / 20f) - 1;
} else {
ascension = (int) Math.ceil(level / 10f) - 3;
ascension = Math.min(ascension, 6);
}
Avatar avatar = new Avatar(avatarId);
avatar.setLevel(level);
avatar.setPromoteLevel(ascension);
// Handle skill depot for traveller.
if (avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_MALE) {
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(504));
}
else if(avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_FEMALE) {
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(704));
}
// This will handle stats and talents
avatar.recalcStats();
targetPlayer.addAvatar(avatar);
CommandHandler.sendMessage(sender, translate(sender, "commands.giveChar.given", Integer.toString(avatarId), Integer.toString(level), Integer.toString(targetPlayer.getUid())));
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "godmode", usage = "godmode [on|off|toggle]", permission = "player.godmode", permissionTargeted = "player.godmode.others", description = "commands.godmode.description")
public final class GodModeCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
boolean enabled = !targetPlayer.inGodmode();
if (args.size() == 1) {
switch (args.get(0).toLowerCase()) {
case "on":
enabled = true;
break;
case "off":
enabled = false;
break;
case "toggle":
break; // Already toggled
default:
break;
}
}
targetPlayer.setGodmode(enabled);
CommandHandler.sendMessage(sender, translate(sender, "commands.godmode.success", (enabled ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
}
}
......@@ -8,15 +8,15 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "kick", usage = "kick", permission = "server.kick", description = "commands.kick.description")
@Command(label = "kick", usage = "kick", aliases = {"restart"}, permissionTargeted = "server.kick", description = "commands.kick.description")
public final class KickCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (sender != null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player",
Integer.toString(sender.getUid()), sender.getAccount().getUsername(),
Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player",
Integer.toString(sender.getUid()), sender.getAccount().getUsername(),
Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
} else {
CommandHandler.sendMessage(null, translate(sender, "commands.kick.server_kick_player", Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
}
......
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "nostamina", usage = "nostamina [on|off|toggle]", aliases = {"ns"}, permission = "player.nostamina", permissionTargeted = "player.nostamina.others", description = "commands.nostamina.description")
public final class NoStaminaCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
boolean stamina = !targetPlayer.getStamina();
if (args.size() == 1) {
switch (args.get(0).toLowerCase()) {
case "on":
stamina = true;
break;
case "off":
stamina = false;
break;
default:
// toggled
break;
}
}
targetPlayer.setStamina(stamina); //Set
CommandHandler.sendMessage(sender, translate(sender, "commands.nostamina.success", (stamina ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
}
}
......@@ -3,6 +3,7 @@ package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.Command.TargetRequirement;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
......@@ -10,7 +11,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "permission", usage = "permission <add|remove> <permission>", permission = "permission", description = "commands.permission.description")
@Command(label = "permission", usage = "permission <add|remove> <permission>", permission = "permission", description = "commands.permission.description", targetRequirement = TargetRequirement.PLAYER)
public final class PermissionCommand implements CommandHandler {
@Override
......
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "restart", usage = "restart", description = "commands.restart.description", targetRequirement = Command.TargetRequirement.NONE)
public final class RestartCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (sender == null) {
return;
}
sender.getSession().close();
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.Command.TargetRequirement;
import emu.grasscutter.game.player.Player;
import java.util.List;
......@@ -9,7 +11,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "sendmessage", usage = "sendmessage <message>",
aliases = {"say", "sendservmsg", "sendservermessage"}, permission = "server.sendmessage", permissionTargeted = "server.sendmessage.others", description = "commands.sendMessage.description")
aliases = {"say", "sendservmsg", "sendservermessage", "b", "broadcast"}, permission = "server.sendmessage", permissionTargeted = "server.sendmessage.others", description = "commands.sendMessage.description", targetRequirement = TargetRequirement.NONE)
public final class SendMessageCommand implements CommandHandler {
@Override
......@@ -20,7 +22,14 @@ public final class SendMessageCommand implements CommandHandler {
}
String message = String.join(" ", args);
CommandHandler.sendMessage(targetPlayer, message);
if (targetPlayer == null) {
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
CommandHandler.sendMessage(p, message);
}
} else {
CommandHandler.sendMessage(targetPlayer, message);
}
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMessage.success"));
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import java.util.List;
@Command(label = "setbp", usage = "", aliases = "bp",permission = "player.setbp", description = "")
public final class SetBPLevelCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() < 1) {
CommandHandler.sendMessage(sender , "Need a arg");
return;
}
int level = Integer.parseInt(args.get(0));
sender.getBattlePassManager().addPoint(level);
sender.getBattlePassManager().updateAwardTakenLevel(0);
}
}
package emu.grasscutter.command.commands;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.tower.TowerLevelRecord;
@Command(label = "setprop", usage = "setprop|prop <prop> <value>", aliases = {"prop"}, permission = "player.setprop", permissionTargeted = "player.setprop.others", description = "commands.setProp.description")
public final class SetPropCommand implements CommandHandler {
static enum PseudoProp {
NONE,
WORLD_LEVEL,
TOWER_LEVEL,
BP_LEVEL,
GOD_MODE,
NO_STAMINA,
UNLIMITED_ENERGY
}
static class Prop {
String name;
PlayerProperty prop;
PseudoProp pseudoProp;
public Prop(PlayerProperty prop) {
this(prop.toString(), prop, PseudoProp.NONE);
}
public Prop(String name) {
this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE);
}
public Prop(String name, PseudoProp pseudoProp) {
this(name, PlayerProperty.PROP_NONE, pseudoProp);
}
public Prop(String name, PlayerProperty prop) {
this(name, prop, PseudoProp.NONE);
}
public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) {
this.name = name;
this.prop = prop;
this.pseudoProp = pseudoProp;
}
}
Map<String, Prop> props;
public SetPropCommand() {
this.props = new HashMap<>();
// Full PlayerProperty enum that won't be advertised but can be used by devs
for (PlayerProperty prop : PlayerProperty.values()) {
String name = prop.toString().substring(5); // PROP_EXP -> EXP
String key = name.toLowerCase(); // EXP -> exp
this.props.put(key, new Prop(name, prop));
}
// Add special props
Prop worldlevel = new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL);
this.props.put("worldlevel", worldlevel);
this.props.put("wl", worldlevel);
Prop abyss = new Prop("Tower Level", PseudoProp.TOWER_LEVEL);
this.props.put("abyss", abyss);
this.props.put("abyssfloor", abyss);
this.props.put("ut", abyss);
this.props.put("tower", abyss);
this.props.put("towerlevel", abyss);
this.props.put("unlocktower", abyss);
Prop bplevel = new Prop("BP Level", PseudoProp.BP_LEVEL);
this.props.put("bplevel", bplevel);
this.props.put("bp", bplevel);
this.props.put("battlepass", bplevel);
Prop godmode = new Prop("godmode", PseudoProp.GOD_MODE);
this.props.put("godmode", godmode);
this.props.put("god", godmode);
Prop nostamina = new Prop("nostamina", PseudoProp.NO_STAMINA);
this.props.put("nostamina", nostamina);
this.props.put("nostam", nostamina);
this.props.put("ns", nostamina);
Prop unlimitedenergy = new Prop("unlimitedenergy", PseudoProp.UNLIMITED_ENERGY);
this.props.put("unlimitedenergy", unlimitedenergy);
this.props.put("ue", unlimitedenergy);
}
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() != 2) {
CommandHandler.sendTranslatedMessage(sender, "commands.setProp.usage");
return;
}
String propStr = args.get(0).toLowerCase();
String valueStr = args.get(1).toLowerCase();
int value;
if (!props.containsKey(propStr)) {
CommandHandler.sendTranslatedMessage(sender, "commands.setProp.usage");
return;
}
try {
value = switch(valueStr.toLowerCase()) {
case "on", "true" -> 1;
case "off", "false" -> 0;
case "toggle" -> -1;
default -> Integer.parseInt(valueStr);
};
} catch (NumberFormatException ignored) {
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
return;
}
boolean success = false;
Prop prop = props.get(propStr);
success = switch (prop.pseudoProp) {
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
case GOD_MODE, NO_STAMINA, UNLIMITED_ENERGY -> this.setBool(sender, targetPlayer, prop.pseudoProp, value);
default -> targetPlayer.setProperty(prop.prop, value);
};
if (success) {
if (targetPlayer == sender) {
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", prop.name, valueStr);
} else {
String uidStr = targetPlayer.getAccount().getId();
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr);
}
} else {
if (prop.prop != PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages
String min = Integer.toString(targetPlayer.getPropertyMin(prop.prop));
String max = Integer.toString(targetPlayer.getPropertyMax(prop.prop));
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", prop.name, min, max);
}
}
}
private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) {
List<Integer> floorIds = targetPlayer.getServer().getTowerScheduleManager().getAllFloors();
if (topFloor < 0 || topFloor > floorIds.size()) {
String min = Integer.toString(0);
String max = Integer.toString(floorIds.size());
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", "Tower Level", min, max);
return false;
}
Map<Integer, TowerLevelRecord> recordMap = targetPlayer.getTowerManager().getRecordMap();
// Add records for each unlocked floor
for (int floor : floorIds.subList(0, topFloor)) {
if (!recordMap.containsKey(floor)) {
recordMap.put(floor, new TowerLevelRecord(floor));
}
}
// Remove records for each floor past our target
for (int floor : floorIds.subList(topFloor, floorIds.size())) {
if (recordMap.containsKey(floor)) {
recordMap.remove(floor);
}
}
// Six stars required on Floor 8 to unlock Floor 9+
if (topFloor > 8) {
recordMap.get(floorIds.get(7)).setLevelStars(0, 6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at all
}
return true;
}
private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) {
boolean enabled = switch (pseudoProp) {
case GOD_MODE -> targetPlayer.inGodmode();
case NO_STAMINA -> targetPlayer.getUnlimitedStamina();
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage();
default -> false;
};
enabled = switch (value) {
case -1 -> !enabled;
case 0 -> false;
default -> true;
};
switch (pseudoProp) {
case GOD_MODE:
targetPlayer.setGodmode(enabled);
break;
case NO_STAMINA:
targetPlayer.setUnlimitedStamina(enabled);
break;
case UNLIMITED_ENERGY:
targetPlayer.getEnergyManager().setEnergyUsage(!enabled);
break;
default:
return false;
}
return true;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment