Merge branch 'development' into main

This commit is contained in:
Yazawazi 2022-04-20 19:09:48 +08:00 committed by GitHub
commit 31d89369c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 182 additions and 109 deletions

View File

@ -66,6 +66,9 @@ There is a dummy user named "Server" in every player's friends list that you can
`!clearartifacts` - Deletes all unequipped and unlocked level 0 artifacts, **including yellow rarity ones** from your inventory
### Bonus
When you want to teleport to somewhere, use the ingame marking function on Map, click Confirm. You will see your character falling from a very high destination, exact location that you marked.
# Quick Troubleshooting
* If compiling wasnt successful, please check your JDK installation (must be JDK 8 and validated JDK's bin PATH variable)
* My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is the issue, if using Fiddler make sure it running on another port except 8888

File diff suppressed because one or more lines are too long

View File

@ -53,5 +53,6 @@ public final class Config {
public int MaxEntityLimit = 1000; // Max entity limit per world. // TODO: Enforce later.
public int[] WelcomeEmotes = {2007, 1002, 4010};
public String WelcomeMotd = "Welcome to Grasscutter emu";
public boolean AutomaticallyCreateAccounts = false;
}
}

View File

@ -91,7 +91,7 @@ public final class CommandMap {
public void invoke(GenshinPlayer player, String rawMessage) {
rawMessage = rawMessage.trim();
if(rawMessage.length() == 0) {
CommandHandler.sendMessage(player, "No command specified.");
CommandHandler.sendMessage(player, "No command specified."); return;
}
// Remove prefix if present.
@ -113,7 +113,7 @@ public final class CommandMap {
if(player != null) {
String permissionNode = this.annotations.get(label).permission();
Account account = player.getAccount();
if(permissionNode != "" && !account.hasPermission(permissionNode)) {
if(!permissionNode.isEmpty() && !account.hasPermission(permissionNode)) {
CommandHandler.sendMessage(player, "You do not have permission to run this command."); return;
}
}

View File

@ -22,7 +22,9 @@ import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketSceneAreaWeatherNotify;
import emu.grasscutter.server.packet.send.PacketGetPlayerTokenRsp;
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
import emu.grasscutter.server.packet.send.PacketPlayerLoginRsp;
import emu.grasscutter.utils.Position;
import java.util.LinkedList;
@ -40,7 +42,7 @@ public final class PlayerCommands {
public void execute(GenshinPlayer player, List<String> args) {
int target, item, amount = 1;
switch(args.size()) {
switch (args.size()) {
default:
CommandHandler.sendMessage(player, "Usage: give <player> <itemId|itemName> [amount]");
return;
@ -58,8 +60,9 @@ public final class PlayerCommands {
try {
target = Integer.parseInt(args.get(0));
if(Grasscutter.getGameServer().getPlayerByUid(target) == null) {
target = player.getUid(); amount = Integer.parseInt(args.get(1));
if (Grasscutter.getGameServer().getPlayerByUid(target) == null) {
target = player.getUid();
amount = Integer.parseInt(args.get(1));
item = Integer.parseInt(args.get(0));
} else {
item = Integer.parseInt(args.get(1));
@ -73,9 +76,10 @@ public final class PlayerCommands {
case 3:
try {
target = Integer.parseInt(args.get(0));
if(Grasscutter.getGameServer().getPlayerByUid(target) == null) {
CommandHandler.sendMessage(player, "Invalid player ID."); return;
if (Grasscutter.getGameServer().getPlayerByUid(target) == null) {
CommandHandler.sendMessage(player, "Invalid player ID.");
return;
}
item = Integer.parseInt(args.get(1));
@ -90,23 +94,26 @@ public final class PlayerCommands {
GenshinPlayer targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
if(targetPlayer == null) {
CommandHandler.sendMessage(player, "Player not found."); return;
if (targetPlayer == null) {
CommandHandler.sendMessage(player, "Player not found.");
return;
}
ItemData itemData = GenshinData.getItemDataMap().get(item);
if(itemData == null) {
CommandHandler.sendMessage(player, "Invalid item id."); return;
if (itemData == null) {
CommandHandler.sendMessage(player, "Invalid item id.");
return;
}
this.item(targetPlayer, itemData, amount);
}
/**
* give [player] [itemId|itemName] [amount]
*/
@Override public void execute(List<String> args) {
if(args.size() < 2) {
@Override
public void execute(List<String> args) {
if (args.size() < 2) {
CommandHandler.sendMessage(null, "Usage: give <player> <itemId|itemName> [amount]");
return;
}
@ -114,32 +121,37 @@ public final class PlayerCommands {
try {
int target = Integer.parseInt(args.get(0));
int item = Integer.parseInt(args.get(1));
int amount = 1; if(args.size() > 2) amount = Integer.parseInt(args.get(2));
int amount = 1;
if (args.size() > 2)
amount = Integer.parseInt(args.get(2));
GenshinPlayer targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
if(targetPlayer == null) {
CommandHandler.sendMessage(null, "Player not found."); return;
if (targetPlayer == null) {
CommandHandler.sendMessage(null, "Player not found.");
return;
}
ItemData itemData = GenshinData.getItemDataMap().get(item);
if(itemData == null) {
CommandHandler.sendMessage(null, "Invalid item id."); return;
if (itemData == null) {
CommandHandler.sendMessage(null, "Invalid item id.");
return;
}
this.item(targetPlayer, itemData, amount);
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(null, "Invalid item or player ID.");
}
}
private void item(GenshinPlayer player, ItemData itemData, int amount) {
GenshinItem genshinItem = new GenshinItem(itemData);
if(itemData.isEquip()) {
if (itemData.isEquip()) {
List<GenshinItem> items = new LinkedList<>();
for(int i = 0; i < amount; i++) {
for (int i = 0; i < amount; i++) {
items.add(genshinItem);
} player.getInventory().addItems(items);
}
player.getInventory().addItems(items);
player.sendPacket(new PacketItemAddHintNotify(items, ActionReason.SubfieldDrop));
} else {
genshinItem.setCount(amount);
@ -148,7 +160,6 @@ public final class PlayerCommands {
}
}
}
@Command(label = "drop", aliases = {"d", "dropitem"},
usage = "drop <itemId|itemName> [amount]",
execution = Command.Execution.PLAYER, description = "Drops an item near you", permission = "server.drop")
@ -156,29 +167,34 @@ public final class PlayerCommands {
@Override
public void execute(GenshinPlayer player, List<String> args) {
if(args.size() < 1) {
if (args.size() < 1) {
CommandHandler.sendMessage(player, "Usage: drop <itemId|itemName> [amount]");
return;
}
try {
int item = Integer.parseInt(args.get(0));
int amount = 1; if(args.size() > 1) amount = Integer.parseInt(args.get(1));
int amount = 1;
if (args.size() > 1)
amount = Integer.parseInt(args.get(1));
ItemData itemData = GenshinData.getItemDataMap().get(item);
if(itemData == null) {
CommandHandler.sendMessage(player, "Invalid item id."); return;
if (itemData == null) {
CommandHandler.sendMessage(player, "Invalid item id.");
return;
}
if (itemData.isEquip()) {
float range = (5f + (.1f * amount));
for (int i = 0; i < amount; i++) {
Position pos = player.getPos().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f).addZ((float) (Math.random() * range) - (range / 2));
Position pos = player.getPos().clone().addX((float) (Math.random() * range) - (range / 2))
.addY(3f).addZ((float) (Math.random() * range) - (range / 2));
EntityItem entity = new EntityItem(player.getScene(), player, itemData, pos, 1);
player.getScene().addEntity(entity);
}
} else {
EntityItem entity = new EntityItem(player.getScene(), player, itemData, player.getPos().clone().addY(3f), amount);
EntityItem entity = new EntityItem(player.getScene(), player, itemData,
player.getPos().clone().addY(3f), amount);
player.getScene().addEntity(entity);
}
} catch (NumberFormatException ignored) {
@ -190,23 +206,24 @@ public final class PlayerCommands {
@Command(label = "givechar", aliases = { "givec" }, usage = "givechar <playerId> <avatarId> [level]",
description = "Gives the player a specified character", permission = "player.givechar")
public static class GiveCharCommand implements CommandHandler {
@Override public void execute(GenshinPlayer player, List<String> args) {
@Override
public void execute(GenshinPlayer player, List<String> args) {
int target, avatarId, level = 1, ascension = 1;
if(args.size() < 1) {
if (args.size() < 1) {
CommandHandler.sendMessage(player, "Usage: givechar <player> <avatarId> [level]");
return;
}
switch(args.size()) {
switch (args.size()) {
default:
CommandHandler.sendMessage(player, "Usage: givechar <player> <avatarId> [level]");
CommandHandler.sendMessage(player, "Usage: givechar <player> <avatarId> [level]");
return;
case 2:
try {
target = Integer.parseInt(args.get(0));
if(Grasscutter.getGameServer().getPlayerByUid(target) == null) {
target = player.getUid();
if (Grasscutter.getGameServer().getPlayerByUid(target) == null) {
target = player.getUid();
level = Integer.parseInt(args.get(1));
avatarId = Integer.parseInt(args.get(0));
} else {
@ -221,8 +238,9 @@ public final class PlayerCommands {
case 3:
try {
target = Integer.parseInt(args.get(0));
if(Grasscutter.getGameServer().getPlayerByUid(target) == null) {
CommandHandler.sendMessage(player, "Invalid player ID."); return;
if (Grasscutter.getGameServer().getPlayerByUid(target) == null) {
CommandHandler.sendMessage(player, "Invalid player ID.");
return;
}
avatarId = Integer.parseInt(args.get(1));
@ -236,13 +254,15 @@ public final class PlayerCommands {
}
GenshinPlayer targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
if(targetPlayer == null) {
CommandHandler.sendMessage(player, "Player not found."); return;
if (targetPlayer == null) {
CommandHandler.sendMessage(player, "Player not found.");
return;
}
AvatarData avatarData = GenshinData.getAvatarDataMap().get(avatarId);
if(avatarData == null) {
CommandHandler.sendMessage(player, "Invalid avatar id."); return;
if (avatarData == null) {
CommandHandler.sendMessage(player, "Invalid avatar id.");
return;
}
// Calculate ascension level.
@ -255,16 +275,16 @@ public final class PlayerCommands {
GenshinAvatar avatar = new GenshinAvatar(avatarId);
avatar.setLevel(level);
avatar.setPromoteLevel(ascension);
// This will handle stats and talents
avatar.recalcStats();
targetPlayer.addAvatar(avatar);
}
@Override
public void execute(List<String> args) {
if(args.size() < 2) {
if (args.size() < 2) {
CommandHandler.sendMessage(null, "Usage: givechar <player> <itemId|itemName> [amount]");
return;
}
@ -272,33 +292,37 @@ public final class PlayerCommands {
try {
int target = Integer.parseInt(args.get(0));
int avatarID = Integer.parseInt(args.get(1));
int level = 1; if(args.size() > 2) level = Integer.parseInt(args.get(2));
int level = 1;
if (args.size() > 2)
level = Integer.parseInt(args.get(2));
int ascension;
GenshinPlayer targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
if(targetPlayer == null) {
CommandHandler.sendMessage(null, "Player not found."); return;
if (targetPlayer == null) {
CommandHandler.sendMessage(null, "Player not found.");
return;
}
AvatarData avatarData = GenshinData.getAvatarDataMap().get(avatarID);
if(avatarData == null) {
CommandHandler.sendMessage(null, "Invalid avatar id."); return;
if (avatarData == null) {
CommandHandler.sendMessage(null, "Invalid avatar id.");
return;
}
// Calculate ascension level.
if (level <= 40) {
ascension = (int) Math.ceil(level / 20f);
} else {
ascension = (int) Math.ceil(level / 10f) - 3;
}
GenshinAvatar avatar = new GenshinAvatar(avatarID);
avatar.setLevel(level);
avatar.setPromoteLevel(ascension);
// This will handle stats and talents
avatar.recalcStats();
targetPlayer.addAvatar(avatar);
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(null, "Invalid item or player ID.");
@ -309,27 +333,33 @@ public final class PlayerCommands {
@Command(label = "spawn", execution = Command.Execution.PLAYER,
usage = "spawn <entityId|entityName> [level] [amount]", description = "Spawns an entity near you", permission = "server.spawn")
public static class SpawnCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer player, List<String> args) {
if(args.size() < 1) {
if (args.size() < 1) {
CommandHandler.sendMessage(null, "Usage: spawn <entityId|entityName> [amount]");
return;
}
try {
int entity = Integer.parseInt(args.get(0));
int level = 1; if(args.size() > 1) level = Integer.parseInt(args.get(1));
int amount = 1; if(args.size() > 2) amount = Integer.parseInt(args.get(2));
int level = 1;
if (args.size() > 1)
level = Integer.parseInt(args.get(1));
int amount = 1;
if (args.size() > 2)
amount = Integer.parseInt(args.get(2));
MonsterData entityData = GenshinData.getMonsterDataMap().get(entity);
if(entityData == null) {
CommandHandler.sendMessage(null, "Invalid entity id."); return;
if (entityData == null) {
CommandHandler.sendMessage(null, "Invalid entity id.");
return;
}
float range = (5f + (.1f * amount));
for (int i = 0; i < amount; i++) {
Position pos = player.getPos().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f).addZ((float) (Math.random() * range) - (range / 2));
Position pos = player.getPos().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f)
.addZ((float) (Math.random() * range) - (range / 2));
EntityMonster monster = new EntityMonster(player.getScene(), entityData, pos, level);
player.getScene().addEntity(monster);
}
@ -351,29 +381,30 @@ public final class PlayerCommands {
.forEach(entity -> scene.killEntity(entity, 0));
CommandHandler.sendMessage(null, "Killing all monsters in scene " + scene.getId());
}
@Override
public void execute(List<String> args) {
if(args.size() < 2) {
CommandHandler.sendMessage(null, "Usage: killall [playerUid] [sceneId]"); return;
if (args.size() < 2) {
CommandHandler.sendMessage(null, "Usage: killall [playerUid] [sceneId]");
return;
}
try {
int playerUid = Integer.parseInt(args.get(0));
int playerUid = Integer.parseInt(args.get(0));
int sceneId = Integer.parseInt(args.get(1));
GenshinPlayer player = Grasscutter.getGameServer().getPlayerByUid(playerUid);
if (player == null) {
CommandHandler.sendMessage(null, "Player not found or offline.");
return;
CommandHandler.sendMessage(null, "Player not found or offline.");
return;
}
GenshinScene scene = player.getWorld().getSceneById(sceneId);
if (scene == null) {
CommandHandler.sendMessage(null, "Scene not found in player world");
return;
CommandHandler.sendMessage(null, "Scene not found in player world");
return;
}
scene.getEntities().values().stream()
.filter(entity -> entity instanceof EntityMonster)
.forEach(entity -> scene.killEntity(entity, 0));
@ -383,29 +414,30 @@ public final class PlayerCommands {
}
}
}
@Command(label = "resetconst", aliases = {"resetconstellation"},
usage = "resetconst [all]", execution = Command.Execution.PLAYER, permission = "player.resetconstellation",
description = "Resets the constellation level on your current active character, will need to relog after using the command to see any changes.")
public static class ResetConstellationCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer player, List<String> args) {
if(args.size() > 0 && args.get(0).equalsIgnoreCase("all")) {
if (args.size() > 0 && args.get(0).equalsIgnoreCase("all")) {
player.getAvatars().forEach(this::resetConstellation);
player.dropMessage("Reset all avatars' constellations.");
} else {
EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity();
if(entity == null)
EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity();
if (entity == null)
return;
GenshinAvatar avatar = entity.getAvatar();
this.resetConstellation(avatar);
player.dropMessage("Constellations for " + avatar.getAvatarData().getName() + " have been reset. Please relog to see changes.");
player.dropMessage("Constellations for " + avatar.getAvatarData().getName()
+ " have been reset. Please relog to see changes.");
}
}
private void resetConstellation(GenshinAvatar avatar) {
avatar.getTalentIdList().clear();
avatar.setCoreProudSkillLevel(0);
@ -413,18 +445,18 @@ public final class PlayerCommands {
avatar.save();
}
}
@Command(label = "godmode",
usage = "godmode", execution = Command.Execution.PLAYER, description = "Prevents you from taking damage", permission = "player.godmode")
public static class GodModeCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer player, List<String> args) {
player.setGodmode(!player.inGodmode());
player.dropMessage("Godmode is now " + (player.inGodmode() ? "enabled" : "disabled") + ".");
}
}
@Command(label = "sethealth", aliases = {"sethp"},
usage = "sethealth <hp>", execution = Command.Execution.PLAYER, description = "Sets your health to the specified value",
permission = "player.sethealth")
@ -432,18 +464,20 @@ public final class PlayerCommands {
@Override
public void execute(GenshinPlayer player, List<String> args) {
if(args.size() < 1) {
CommandHandler.sendMessage(null, "Usage: sethealth <hp>"); return;
if (args.size() < 1) {
CommandHandler.sendMessage(null, "Usage: sethealth <hp>");
return;
}
try {
int health = Integer.parseInt(args.get(0));
EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity();
if(entity == null)
if (entity == null)
return;
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, health);
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
entity.getWorld().broadcastPacket(
new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
player.dropMessage("Health set to " + health + ".");
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(null, "Invalid health value.");
@ -457,10 +491,11 @@ public final class PlayerCommands {
public static class SetWorldLevelCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer player, List<String> args) {
if(args.size() < 1) {
CommandHandler.sendMessage(player, "Usage: setworldlevel <level>"); return;
if (args.size() < 1) {
CommandHandler.sendMessage(player, "Usage: setworldlevel <level>");
return;
}
try {
int level = Integer.parseInt(args.get(0));
@ -474,7 +509,7 @@ public final class PlayerCommands {
}
}
}
@Command(label = "clearartifacts", aliases = {"clearart"},
usage = "clearartifacts", execution = Command.Execution.PLAYER, permission = "player.clearartifacts",
description = "Deletes all unequipped and unlocked level 0 artifacts, including yellow rarity ones from your inventory")
@ -495,10 +530,11 @@ public final class PlayerCommands {
public static class ChangeSceneCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer player, List<String> args) {
if(args.size() < 1) {
CommandHandler.sendMessage(player, "Usage: changescene <scene id>"); return;
if (args.size() < 1) {
CommandHandler.sendMessage(player, "Usage: changescene <scene id>");
return;
}
try {
int sceneId = Integer.parseInt(args.get(0));
boolean result = player.getWorld().transferPlayerToScene(player, sceneId, player.getPos());
@ -507,7 +543,8 @@ public final class PlayerCommands {
CommandHandler.sendMessage(null, "Scene does not exist or you are already in it");
}
} catch (Exception e) {
CommandHandler.sendMessage(player, "Usage: changescene <scene id>"); return;
CommandHandler.sendMessage(player, "Usage: changescene <scene id>");
return;
}
}
}
@ -539,11 +576,22 @@ public final class PlayerCommands {
}
}
@Command(label = "pos",
usage = "Usage: pos", description = "Get coordinates.",
execution = Command.Execution.PLAYER)
public static class CordCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer player, List<String> args) {
player.dropMessage(String.format("Coord: %.3f, %.3f, %.3f", player.getPos().getX(), player.getPos().getY(), player.getPos().getZ()));
}
}
@Command(label = "weather", aliases = {"weather", "w"},
usage = "weather <weather id>", description = "Changes the weather.",
execution = Command.Execution.PLAYER, permission = "player.weather"
)
public static class ChangeWeatherCommand implements CommandHandler {
public static class ChangeWeatherCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer player, List<String> args) {
if (args.size() < 1) {
@ -563,4 +611,12 @@ public final class PlayerCommands {
}
}
}
@Command(label = "restart", usage = "Usage: restart", description = "Restarts the current session", execution = Command.Execution.PLAYER, permission = "player.restart")
public static class RestartCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer player, List<String> args) {
player.getSession().close();
}
}
}

View File

@ -188,6 +188,7 @@ public final class ServerCommands {
} else {
CommandHandler.sendMessage(null, "Account created with UID " + account.getPlayerId() + ".");
account.addPermission("*"); // Grant the player superuser permissions.
account.save(); // Save account to database.
}
return;
case "delete":

View File

@ -225,11 +225,23 @@ public final class DispatchServer {
// Login
Account account = DatabaseHelper.getAccountByName(requestData.account);
// Test
// Check if account exists, else create a new one.
if (account == null) {
responseData.retcode = -201;
responseData.message = "Username not found.";
// Account doesnt exist, so we can either auto create it if the config value is set
if (Grasscutter.getConfig().ServerOptions.AutomaticallyCreateAccounts) {
// This account has been created AUTOMATICALLY. There will be no permissions added.
account = DatabaseHelper.createAccountWithId(requestData.account, 0);
responseData.message = "OK";
responseData.data.account.uid = account.getId();
responseData.data.account.token = account.generateSessionKey();
responseData.data.account.email = account.getEmail();
} else {
responseData.retcode = -201;
responseData.message = "Username not found.";
}
} else {
// Account was found, log the player in
responseData.message = "OK";
responseData.data.account.uid = account.getId();
responseData.data.account.token = account.generateSessionKey();