Commit a5720973 authored by Magix's avatar Magix Committed by GitHub
Browse files

Merge branch 'development' into main

parents 708ee021 16318b37
......@@ -60,12 +60,19 @@ There is a dummy user named "Server" in every player's friends list that you can
`!resetconst` - Resets the constellation level on your current active character, will need to relog after using the command to see any changes.
`!setstats [stat] [value]`
`!setstats [stats] [amount]` - Changes the current character's specified stat.
`!clearartifacts` - Deletes all unequipped and unlocked level 0 artifacts, **including yellow rarity ones** from your inventory
`!pos` - Gets your current coordinate.
`!weather [weather id] [climate id]` - Changes the current weather.
*More commands will be updated in the [wiki](https://github.com/Melledy/Grasscutter/wiki/).*
### 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 wasn't 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
......
......@@ -23,19 +23,21 @@ repositories {
}
dependencies {
compile fileTree(dir: 'lib', include: '*.jar')
implementation fileTree(dir: 'lib', include: ['*.jar'])
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.32'
compile group: 'ch.qos.logback', name: 'logback-core', version: '1.2.6'
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.6'
compile group: 'io.netty', name: 'netty-all', version: '4.1.69.Final'
implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.32'
implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.2.6'
implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.6'
implementation group: 'io.netty', name: 'netty-all', version: '4.1.69.Final'
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.8'
compile group: 'com.google.protobuf', name: 'protobuf-java', version: '3.18.1'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.8'
implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.18.1'
compile group: 'org.reflections', name: 'reflections', version: '0.9.12'
implementation group: 'org.reflections', name: 'reflections', version: '0.9.12'
compile group: 'dev.morphia.morphia', name: 'core', version: '1.6.1'
implementation group: 'dev.morphia.morphia', name: 'core', version: '1.6.1'
implementation group: 'org.greenrobot', name: 'eventbus-java', version: '3.3.1'
}
application {
......@@ -51,9 +53,11 @@ jar {
jar.baseName = 'grasscutter'
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
duplicatesStrategy = DuplicatesStrategy.INCLUDE
from('src/main/java') {
include '*.xml'
}
......
......@@ -19,7 +19,7 @@
"bannerType": "EVENT",
"prefabPath": "GachaShowPanel_A079",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A079",
"titlePath": "UI_GACHA_SHOW_PANEL_A079_TITLE",
"titlePath": "UI_GACHA_SHOW_PANEL_A048_TITLE",
"costItem": 223,
"beginTime": 0,
"endTime": 1924992000,
......@@ -34,7 +34,7 @@
"bannerType": "WEAPON",
"prefabPath": "GachaShowPanel_A080",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A080",
"titlePath": "UI_GACHA_SHOW_PANEL_A080_TITLE",
"titlePath": "UI_GACHA_SHOW_PANEL_A021_TITLE",
"costItem": 223,
"beginTime": 0,
"endTime": 1924992000,
......
GpgdCgw0Ny44OS4xNTIuNDcQ1awBGitodHRwczovL29zdXNhb2FzZXJ2ZXIueXVhbnNoZW4uY29tL3JlY2hhcmdlOgNVU0FCOWh0dHBzOi8vYXV0b3BhdGNoaGsueXVhbnNoZW4uY29tL2NsaWVudF9nYW1lX3Jlcy8yLjZfbGl2ZUo8aHR0cHM6Ly9hdXRvcGF0Y2hoay55dWFuc2hlbi5jb20vY2xpZW50X2Rlc2lnbl9kYXRhLzIuNl9saXZlUpIBaHR0cHM6Ly93ZWJzdGF0aWMtc2VhLmhveW92ZXJzZS5jb20veXMvZXZlbnQvaW0tc2VydmljZS9pbmRleC5odG1sP2ltX291dD1mYWxzZSZzaWduX3R5cGU9MiZhdXRoX2FwcGlkPWltX2NjcyZhdXRoa2V5X3Zlcj0xJndpbl9kaXJlY3Rpb249cG9ydHJhaXRiCDIuNl9saXZlcNnsmgOQAdnsmgOaAVx7InJlbW90ZU5hbWUiOiAiZGF0YV92ZXJzaW9ucyIsICJtZDUiOiAiMWE0NDVhZTQ4ZmJkYmUwMzgzMTJiZTg2OGYyODEzZDIiLCAiZmlsZVNpemUiOiA0NDE1faIBW3sicmVtb3RlTmFtZSI6ICJkYXRhX3ZlcnNpb25zIiwgIm1kNSI6ICIxNzU0MmM3YmJhYzQ5YjkxMWRlMjlhOTYyNzU0YmQ2MSIsICJmaWxlU2l6ZSI6IDUxNH2yAYEGCL23mQMa4AV7InJlbW90ZU5hbWUiOiAicmVzX3ZlcnNpb25zX2V4dGVybmFsIiwgIm1kNSI6ICI5ZjA5MmNhMTMwNjdjYWU0MzEzNDkzZWVkM2QzZTlhZSIsICJmaWxlU2l6ZSI6IDUyNjk2Nn0NCnsicmVtb3RlTmFtZSI6ICJyZXNfdmVyc2lvbnNfbWVkaXVtIiwgIm1kNSI6ICI3Yzk0MmU3MDRhODA0YzIxMjJmYzYzZWU5MjhlNzE0OCIsICJmaWxlU2l6ZSI6IDI4NTU1MH0NCnsicmVtb3RlTmFtZSI6ICJyZXNfdmVyc2lvbnNfc3RyZWFtaW5nIiwgIm1kNSI6ICJlMzVmNmQ4NTNkMDRjZTAyMmFjN2MzNmQ0M2Y0MGU3YyIsICJmaWxlU2l6ZSI6IDEyMjAzNn0NCnsicmVtb3RlTmFtZSI6ICJyZWxlYXNlX3Jl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
\ No newline at end of file
GpgdCgo4LjIwOS42Ni4xENWsARosaHR0cHM6Ly9vc2V1cm9vYXNlcnZlci55dWFuc2hlbi5jb20vcmVjaGFyZ2U6BGV1cm9COWh0dHBzOi8vYXV0b3BhdGNoaGsueXVhbnNoZW4uY29tL2NsaWVudF9nYW1lX3Jlcy8yLjZfbGl2ZUo8aHR0cHM6Ly9hdXRvcGF0Y2hoay55dWFuc2hlbi5jb20vY2xpZW50X2Rlc2lnbl9kYXRhLzIuNl9saXZlUpIBaHR0cHM6Ly93ZWJzdGF0aWMtc2VhLmhveW92ZXJzZS5jb20veXMvZXZlbnQvaW0tc2VydmljZS9pbmRleC5odG1sP2ltX291dD1mYWxzZSZzaWduX3R5cGU9MiZhdXRoX2FwcGlkPWltX2NjcyZhdXRoa2V5X3Zlcj0xJndpbl9kaXJlY3Rpb249cG9ydHJhaXRiCDIuNl9saXZlcNnsmgOQAdnsmgOaAVx7InJlbW90ZU5hbWUiOiAiZGF0YV92ZXJzaW9ucyIsICJtZDUiOiAiMWE0NDVhZTQ4ZmJkYmUwMzgzMTJiZTg2OGYyODEzZDIiLCAiZmlsZVNpemUiOiA0NDE1faIBW3sicmVtb3RlTmFtZSI6ICJkYXRhX3ZlcnNpb25zIiwgIm1kNSI6ICIxNzU0MmM3YmJhYzQ5YjkxMWRlMjlhOTYyNzU0YmQ2MSIsICJmaWxlU2l6ZSI6IDUxNH2yAYEGCL23mQMa4AV7InJlbW90ZU5hbWUiOiAicmVzX3ZlcnNpb25zX2V4dGVybmFsIiwgIm1kNSI6ICI5ZjA5MmNhMTMwNjdjYWU0MzEzNDkzZWVkM2QzZTlhZSIsICJmaWxlU2l6ZSI6IDUyNjk2Nn0NCnsicmVtb3RlTmFtZSI6ICJyZXNfdmVyc2lvbnNfbWVkaXVtIiwgIm1kNSI6ICI3Yzk0MmU3MDRhODA0YzIxMjJmYzYzZWU5MjhlNzE0OCIsICJmaWxlU2l6ZSI6IDI4NTU1MH0NCnsicmVtb3RlTmFtZSI6ICJyZXNfdmVyc2lvbnNfc3RyZWFtaW5nIiwgIm1kNSI6ICJlMzVmNmQ4NTNkMDRjZTAyMmFjN2MzNmQ0M2Y0MGU3YyIsICJmaWxlU2l6ZSI6IDEyMjAzNn0NCnsicmVtb3RlTmFtZSI6ICJyZWxlYXNlX3Jl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
\ No newline at end of file
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
......@@ -16,12 +16,14 @@
# - mitmdump from mitmproxy
#
# @author MlgmXyysd
# @version 1.0
# @version 1.1
#
##
from mitmproxy import http
from proxy_config import USE_SSL
from proxy_config import REMOTE_HOST
from proxy_config import REMOTE_PORT
class MlgmXyysd_Genshin_Impact_Proxy:
......@@ -60,7 +62,12 @@ class MlgmXyysd_Genshin_Impact_Proxy:
def request(self, flow: http.HTTPFlow) -> None:
if flow.request.host in self.LIST_DOMAINS:
if USE_SSL:
flow.request.scheme = "https"
else:
flow.request.scheme = "http"
flow.request.host = REMOTE_HOST
flow.request.port = REMOTE_PORT
addons = [
MlgmXyysd_Genshin_Impact_Proxy()
......
# This can also be replaced with another IP address.
REMOTE_HOST = "localhost"
\ No newline at end of file
USE_SSL = True
REMOTE_HOST = "127.0.0.1"
REMOTE_PORT = 443
\ No newline at end of file
package emu.grasscutter.commands;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import emu.grasscutter.data.GenshinData;
import emu.grasscutter.data.def.ItemData;
import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GenshinEntity;
import emu.grasscutter.game.inventory.GenshinItem;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
import emu.grasscutter.utils.Position;
public class PlayerCommands {
private static HashMap<String, PlayerCommand> list = new HashMap<>();
static {
try {
// Look for classes
for (Class<?> cls : PlayerCommands.class.getDeclaredClasses()) {
// Get non abstract classes
if (!Modifier.isAbstract(cls.getModifiers())) {
Command commandAnnotation = cls.getAnnotation(Command.class);
PlayerCommand command = (PlayerCommand) cls.newInstance();
if (commandAnnotation != null) {
command.setLevel(commandAnnotation.gmLevel());
for (String alias : commandAnnotation.aliases()) {
if (alias.length() == 0) {
continue;
}
String commandName = "!" + alias;
list.put(commandName, command);
commandName = "/" + alias;
list.put(commandName, command);
}
}
String commandName = "!" + cls.getSimpleName().toLowerCase();
list.put(commandName, command);
commandName = "/" + cls.getSimpleName().toLowerCase();
list.put(commandName, command);
}
}
} catch (Exception e) {
}
}
public static void handle(GenshinPlayer player, String msg) {
String[] split = msg.split(" ");
// End if invalid
if (split.length == 0) {
return;
}
//
String first = split[0].toLowerCase();
PlayerCommand c = PlayerCommands.list.get(first);
if (c != null) {
// Level check
if (player.getGmLevel() < c.getLevel()) {
return;
}
// Execute
int len = Math.min(first.length() + 1, msg.length());
c.execute(player, msg.substring(len));
}
}
public static abstract class PlayerCommand {
// GM level required to use this command
private int level;
protected int getLevel() { return this.level; }
protected void setLevel(int minLevel) { this.level = minLevel; }
// Main
public abstract void execute(GenshinPlayer player, String raw);
}
// ================ Commands ================
@Command(aliases = {"g", "item", "additem"}, helpText = "/give [item id] [count] - Gives {count} amount of {item id}")
public static class Give extends PlayerCommand {
@Override
public void execute(GenshinPlayer player, String raw) {
String[] split = raw.split(" ");
int itemId = 0, count = 1;
try {
itemId = Integer.parseInt(split[0]);
} catch (Exception e) {
itemId = 0;
}
try {
count = Math.max(Math.min(Integer.parseInt(split[1]), Integer.MAX_VALUE), 1);
} catch (Exception e) {
count = 1;
}
// Give
ItemData itemData = GenshinData.getItemDataMap().get(itemId);
GenshinItem item;
if (itemData == null) {
player.dropMessage("Error: Item data not found");
return;
}
if (itemData.isEquip()) {
List<GenshinItem> items = new LinkedList<>();
for (int i = 0; i < count; i++) {
item = new GenshinItem(itemData);
items.add(item);
}
player.getInventory().addItems(items);
player.sendPacket(new PacketItemAddHintNotify(items, ActionReason.SubfieldDrop));
} else {
item = new GenshinItem(itemData, count);
player.getInventory().addItem(item);
player.sendPacket(new PacketItemAddHintNotify(item, ActionReason.SubfieldDrop));
}
}
}
@Command(aliases = {"d"}, helpText = "/drop [item id] [count] - Drops {count} amount of {item id}")
public static class Drop extends PlayerCommand {
@Override
public void execute(GenshinPlayer player, String raw) {
String[] split = raw.split(" ");
int itemId = 0, count = 1;
try {
itemId = Integer.parseInt(split[0]);
} catch (Exception e) {
itemId = 0;
}
try {
count = Math.max(Math.min(Integer.parseInt(split[1]), Integer.MAX_VALUE), 1);
} catch (Exception e) {
count = 1;
}
// Give
ItemData itemData = GenshinData.getItemDataMap().get(itemId);
if (itemData == null) {
player.dropMessage("Error: Item data not found");
return;
}
if (itemData.isEquip()) {
float range = (5f + (.1f * count));
for (int i = 0; i < count; i++) {
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.getWorld(), player, itemData, pos, 1);
player.getWorld().addEntity(entity);
}
} else {
EntityItem entity = new EntityItem(player.getWorld(), player, itemData, player.getPos().clone().addY(3f), count);
player.getWorld().addEntity(entity);
}
}
}
@Command(helpText = "/spawn [monster id] [count] - Creates {count} amount of {item id}")
public static class Spawn extends PlayerCommand {
@Override
public void execute(GenshinPlayer player, String raw) {
String[] split = raw.split(" ");
int monsterId = 0, count = 1, level = 1;
try {
monsterId = Integer.parseInt(split[0]);
} catch (Exception e) {
monsterId = 0;
}
try {
level = Math.max(Math.min(Integer.parseInt(split[1]), 200), 1);
} catch (Exception e) {
level = 1;
}
try {
count = Math.max(Math.min(Integer.parseInt(split[2]), 1000), 1);
} catch (Exception e) {
count = 1;
}
// Give
MonsterData monsterData = GenshinData.getMonsterDataMap().get(monsterId);
if (monsterData == null) {
player.dropMessage("Error: Monster data not found");
return;
}
float range = (5f + (.1f * count));
for (int i = 0; i < count; i++) {
Position pos = player.getPos().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f).addZ((float) (Math.random() * range) - (range / 2));
EntityMonster entity = new EntityMonster(player.getWorld(), monsterData, pos, level);
player.getWorld().addEntity(entity);
}
}
}
@Command(helpText = "/killall")
public static class KillAll extends PlayerCommand {
@Override
public void execute(GenshinPlayer player, String raw) {
List<GenshinEntity> toRemove = new LinkedList<>();
for (GenshinEntity entity : player.getWorld().getEntities().values()) {
if (entity instanceof EntityMonster) {
toRemove.add(entity);
}
}
toRemove.forEach(e -> player.getWorld().killEntity(e, 0));
}
}
@Command(helpText = "/resetconst - Resets all constellations for the currently active character")
public static class ResetConst extends PlayerCommand {
@Override
public void execute(GenshinPlayer player, String raw) {
EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity();
if (entity == null) {
return;
}
GenshinAvatar avatar = entity.getAvatar();
avatar.getTalentIdList().clear();
avatar.setCoreProudSkillLevel(0);
avatar.recalcStats();
avatar.save();
player.dropMessage("Constellations for " + entity.getAvatar().getAvatarData().getName() + " have been reset. Please relogin to see changes.");
}
}
@Command(helpText = "/godmode - Prevents you from taking damage")
public static class Godmode extends PlayerCommand {
@Override
public void execute(GenshinPlayer player, String raw) {
player.setGodmode(!player.hasGodmode());
player.dropMessage("Godmode is now " + (player.hasGodmode() ? "ON" : "OFF"));
}
}
@Command(helpText = "/sethp [hp]")
public static class Sethp extends PlayerCommand {
@Override
public void execute(GenshinPlayer player, String raw) {
String[] split = raw.split(" ");
int hp = 0;
try {
hp = Math.max(Integer.parseInt(split[0]), 1);
} catch (Exception e) {
hp = 1;
}
EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity();
if (entity == null) {
return;
}
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, hp);
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
}
}
@Command(aliases = {"clearart"}, helpText = "/clearartifacts")
public static class ClearArtifacts extends PlayerCommand {
@Override
public void execute(GenshinPlayer player, String raw) {
List<GenshinItem> toRemove = new LinkedList<>();
for (GenshinItem item : player.getInventory().getItems().values()) {
if (item.getItemType() == ItemType.ITEM_RELIQUARY && item.getLevel() == 1 && item.getExp() == 0 && !item.isLocked() && !item.isEquipped()) {
toRemove.add(item);
}
}
player.getInventory().removeItems(toRemove);
}
}
}
package emu.grasscutter.commands;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GenshinData;
import emu.grasscutter.data.def.ItemData;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.inventory.GenshinItem;
import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.Utils;
public class ServerCommands {
private static HashMap<String, ServerCommand> list = new HashMap<>();
static {
try {
// Look for classes
for (Class<?> cls : ServerCommands.class.getDeclaredClasses()) {
// Get non abstract classes
if (!Modifier.isAbstract(cls.getModifiers())) {
String commandName = cls.getSimpleName().toLowerCase();
list.put(commandName, (ServerCommand) cls.newInstance());
}
}
} catch (Exception e) {
}
}
public static void handle(String msg) {
String[] split = msg.split(" ");
// End if invalid
if (split.length == 0) {
return;
}
//
String first = split[0].toLowerCase();
ServerCommand c = ServerCommands.list.get(first);
if (c != null) {
// Execute
int len = Math.min(first.length() + 1, msg.length());
c.execute(msg.substring(len));
}
}
public static abstract class ServerCommand {
public abstract void execute(String raw);
}
// ================ Commands ================
public static class Reload extends ServerCommand {
@Override
public void execute(String raw) {
Grasscutter.getLogger().info("Reloading config.");
Grasscutter.loadConfig();
Grasscutter.getDispatchServer().loadQueries();
Grasscutter.getLogger().info("Reload complete.");
}
}
public static class sendMsg extends ServerCommand {
@Override
public void execute(String raw) {
List<String> split = Arrays.asList(raw.split(" "));
if (split.size() < 2) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
String playerID = split.get(0);
String message = split.stream().skip(1).collect(Collectors.joining(" "));
emu.grasscutter.game.Account account = DatabaseHelper.getAccountByPlayerId(Integer.parseInt(playerID));
if (account != null) {
GenshinPlayer player = Grasscutter.getGameServer().getPlayerById(Integer.parseInt(playerID));
if(player != null) {
player.dropMessage(message);
Grasscutter.getLogger().info(String.format("Successfully sent message to %s: %s", playerID, message));
} else {
Grasscutter.getLogger().error("Player not online");
}
} else {
Grasscutter.getLogger().error(String.format("Player %s does not exist", playerID));
}
}
}
public static class Account extends ServerCommand {
@Override
public void execute(String raw) {
String[] split = raw.split(" ");
if (split.length < 2) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
String command = split[0].toLowerCase();
String username = split[1];
switch (command) {
case "create":
if (split.length < 2) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
int reservedId = 0;
try {
reservedId = Integer.parseInt(split[2]);
} catch (Exception e) {
reservedId = 0;
}
emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithId(username, reservedId);
if (account != null) {
Grasscutter.getLogger().info("Account created" + (reservedId > 0 ? " with an id of " + reservedId : ""));
} else {
Grasscutter.getLogger().error("Account already exists");
}
break;
case "delete":
boolean success = DatabaseHelper.deleteAccount(username);
if (success) {
Grasscutter.getLogger().info("Account deleted");
}
break;
/*
case "setpw":
case "setpass":
case "setpassword":
if (split.length < 3) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
account = DatabaseHelper.getAccountByName(username);
if (account == null) {
Grasscutter.getLogger().error("No account found!");
return;
}
token = split[2];
token = PasswordHelper.hashPassword(token);
account.setPassword(token);
DatabaseHelper.saveAccount(account);
Grasscutter.getLogger().info("Password set");
break;
*/
}
}
}
}
package emu.grasscutter;
import java.util.ArrayList;
public final class Config {
public String DispatchServerIp = "127.0.0.1";
public String DispatchServerPublicIp = "";
public int DispatchServerPort = 443;
public String DispatchServerKeystorePath = "./keystore.p12";
public String DispatchServerKeystorePassword = "";
public Boolean UseSSL = true;
public String GameServerName = "Test";
public String GameServerIp = "127.0.0.1";
public String GameServerPublicIp = "";
public int GameServerPort = 22102;
public int UploadLogPort = 80;
public String DatabaseUrl = "mongodb://localhost:27017";
public String DatabaseCollection = "grasscutter";
public String RESOURCE_FOLDER = "./resources/";
public String DATA_FOLDER = "./data/";
public String PACKETS_FOLDER = "./packets/";
public String DUMPS_FOLDER = "./dumps/";
public String KEY_FOLDER = "./keys/";
public boolean LOG_PACKETS = false;
public GameRates Game = new GameRates();
public ServerOptions ServerOptions = new ServerOptions();
public GameRates getGameRates() {
return Game;
}
public ServerOptions getServerOptions() {
return ServerOptions;
public String RunMode = "HYBRID"; // HYBRID, DISPATCH_ONLY, GAME_ONLY
public GameServerOptions GameServer = new GameServerOptions();
public DispatchServerOptions DispatchServer = new DispatchServerOptions();
public GameServerOptions getGameServerOptions() {
return GameServer;
}
public static class GameRates {
public float ADVENTURE_EXP_RATE = 1.0f;
public float MORA_RATE = 1.0f;
public float DOMAIN_DROP_RATE = 1.0f;
public DispatchServerOptions getDispatchOptions() { return DispatchServer; }
public static class DispatchServerOptions {
public String Ip = "0.0.0.0";
public String PublicIp = "127.0.0.1";
public int Port = 443;
public String KeystorePath = "./keystore.p12";
public String KeystorePassword = "";
public Boolean UseSSL = true;
public boolean AutomaticallyCreateAccounts = false;
public RegionInfo[] GameServers = {};
public RegionInfo[] getGameServers() {
return GameServers;
}
public static class RegionInfo {
public String Name = "os_usa";
public String Title = "Test";
public String Ip = "127.0.0.1";
public int Port = 22102;
}
}
public static class ServerOptions {
public static class GameServerOptions {
public String Name = "Test";
public String Ip = "0.0.0.0";
public String PublicIp = "127.0.0.1";
public int Port = 22102;
public String DispatchServerDatabaseUrl = "mongodb://localhost:27017";
public String DispatchServerDatabaseCollection = "grasscutter";
public boolean LOG_PACKETS = false;
public int InventoryLimitWeapon = 2000;
public int InventoryLimitRelic = 2000;
public int InventoryLimitMaterial = 2000;
......@@ -51,8 +66,18 @@ public final class Config {
public int MaxAvatarsInTeam = 4;
public int MaxAvatarsInTeamMultiplayer = 4;
public int MaxEntityLimit = 1000; // Max entity limit per world. // TODO: Enforce later.
public boolean WatchGacha = false;
public int[] WelcomeEmotes = {2007, 1002, 4010};
public String WelcomeMotd = "Welcome to Grasscutter emu";
public boolean AutomaticallyCreateAccounts = false;
public GameRates Game = new GameRates();
public GameRates getGameRates() { return Game; }
public static class GameRates {
public float ADVENTURE_EXP_RATE = 1.0f;
public float MORA_RATE = 1.0f;
public float DOMAIN_DROP_RATE = 1.0f;
}
}
}
......@@ -7,7 +7,7 @@ import java.io.FileWriter;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import emu.grasscutter.commands.CommandMap;
import emu.grasscutter.command.CommandMap;
import emu.grasscutter.utils.Utils;
import org.reflections.Reflections;
import org.slf4j.LoggerFactory;
......@@ -73,11 +73,26 @@ public final class Grasscutter {
DatabaseManager.initialize();
// Start servers.
dispatchServer = new DispatchServer();
dispatchServer.start();
gameServer = new GameServer(new InetSocketAddress(getConfig().GameServerIp, getConfig().GameServerPort));
gameServer.start();
if(getConfig().RunMode.equalsIgnoreCase("HYBRID")) {
dispatchServer = new DispatchServer();
dispatchServer.start();
gameServer = new GameServer(new InetSocketAddress(getConfig().getGameServerOptions().Ip, getConfig().getGameServerOptions().Port));
gameServer.start();
} else if(getConfig().RunMode.equalsIgnoreCase("DISPATCH_ONLY")) {
dispatchServer = new DispatchServer();
dispatchServer.start();
} else if(getConfig().RunMode.equalsIgnoreCase("GAME_ONLY")) {
gameServer = new GameServer(new InetSocketAddress(getConfig().getGameServerOptions().Ip, getConfig().getGameServerOptions().Port));
gameServer.start();
} else {
getLogger().error("Invalid server run mode. " + getConfig().RunMode);
getLogger().error("Server run mode must be 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Unable to start Grasscutter...");
getLogger().error("Shutting down...");
System.exit(1);
}
// Open console.
startConsole();
......@@ -86,8 +101,10 @@ public final class Grasscutter {
public static void loadConfig() {
try (FileReader file = new FileReader(configFile)) {
config = gson.fromJson(file, Config.class);
saveConfig();
} catch (Exception e) {
Grasscutter.config = new Config(); saveConfig();
Grasscutter.config = new Config();
saveConfig();
}
}
......@@ -104,9 +121,14 @@ public final class Grasscutter {
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
while ((input = br.readLine()) != null) {
try {
if(getConfig().RunMode.equalsIgnoreCase("DISPATCH_ONLY")) {
getLogger().error("Commands are not supported in dispatch only mode");
return;
}
CommandMap.getInstance().invoke(null, input);
} catch (Exception e) {
Grasscutter.getLogger().error("Command error: " + e.getMessage());
Grasscutter.getLogger().error("Command error: ");
e.printStackTrace();
}
}
} catch (Exception e) {
......
package emu.grasscutter.command;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Command {
String label() default "";
String usage() default "No usage specified";
String description() default "No description specified";
String[] aliases() default {};
String permission() default "";
}
package emu.grasscutter.commands;
package emu.grasscutter.command;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.GenshinPlayer;
......@@ -6,23 +6,25 @@ import emu.grasscutter.game.GenshinPlayer;
import java.util.List;
public interface CommandHandler {
/* Invoked on player execution. */
default void execute(GenshinPlayer player, List<String> args) { }
/* Invoked on server execution. */
default void execute(List<String> args) { }
/*
* Utilities.
*/
/**
* Send a message to the target.
* @param player The player to send the message to, or null for the server console.
*
* @param player The player to send the message to, or null for the server console.
* @param message The message to send.
*/
static void sendMessage(GenshinPlayer player, String message) {
if(player == null) {
if (player == null) {
Grasscutter.getLogger().info(message);
} else player.dropMessage(message);
} else {
player.dropMessage(message);
}
}
/**
* Called when a player/console invokes a command.
* @param sender The player/console that invoked the command.
* @param args The arguments to the command.
*/
default void execute(GenshinPlayer sender, List<String> args) {
}
}
package emu.grasscutter.commands;
package emu.grasscutter.command;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.Account;
......@@ -7,75 +7,89 @@ import org.reflections.Reflections;
import java.util.*;
@SuppressWarnings("UnusedReturnValue")
@SuppressWarnings({"UnusedReturnValue", "unused"})
public final class CommandMap {
private final Map<String, CommandHandler> commands = new HashMap<>();
private final Map<String, Command> annotations = new HashMap<>();
public CommandMap() {
this(false);
}
public CommandMap(boolean scan) {
if (scan) this.scan();
}
public static CommandMap getInstance() {
return Grasscutter.getGameServer().getCommandMap();
}
private final Map<String, CommandHandler> commands = new HashMap<>();
private final Map<String, Command> annotations = new HashMap<>();
/**
* Register a command handler.
* @param label The command label.
*
* @param label The command label.
* @param command The command handler.
* @return Instance chaining.
*/
public CommandMap registerCommand(String label, CommandHandler command) {
Grasscutter.getLogger().debug("Registered command: " + label);
// Get command data.
Command annotation = command.getClass().getAnnotation(Command.class);
this.annotations.put(label, annotation);
this.commands.put(label, command);
// Register aliases.
if(annotation.aliases().length > 0) {
if (annotation.aliases().length > 0) {
for (String alias : annotation.aliases()) {
this.commands.put(alias, command);
this.annotations.put(alias, annotation);
}
} return this;
}
return this;
}
/**
* Removes a registered command handler.
*
* @param label The command label.
* @return Instance chaining.
*/
public CommandMap unregisterCommand(String label) {
Grasscutter.getLogger().debug("Unregistered command: " + label);
CommandHandler handler = this.commands.get(label);
if(handler == null) return this;
if (handler == null) return this;
Command annotation = handler.getClass().getAnnotation(Command.class);
this.annotations.remove(label);
this.commands.remove(label);
// Unregister aliases.
if(annotation.aliases().length > 0) {
if (annotation.aliases().length > 0) {
for (String alias : annotation.aliases()) {
this.commands.remove(alias);
this.annotations.remove(alias);
}
}
return this;
}
/**
* Returns a list of all registered commands.
*
* @return All command handlers as a list.
*/
public List<CommandHandler> getHandlersAsList() {
return new LinkedList<>(this.commands.values());
}
public HashMap<String, CommandHandler> getHandlers() { return new LinkedHashMap<>(this.commands); }
public HashMap<String, CommandHandler> getHandlers() {
return new LinkedHashMap<>(this.commands);
}
/**
* Returns a handler by label/alias.
*
* @param label The command label.
* @return The command handler.
*/
......@@ -85,7 +99,8 @@ public final class CommandMap {
/**
* Invoke a command handler with the given arguments.
* @param player The player invoking the command or null for the server console.
*
* @param player The player invoking the command or null for the server console.
* @param rawMessage The messaged used to invoke the command.
*/
public void invoke(GenshinPlayer player, String rawMessage) {
......@@ -93,50 +108,35 @@ public final class CommandMap {
if(rawMessage.length() == 0) {
CommandHandler.sendMessage(player, "No command specified."); return;
}
// Remove prefix if present.
if(!Character.isLetter(rawMessage.charAt(0)))
if (!Character.isLetter(rawMessage.charAt(0)))
rawMessage = rawMessage.substring(1);
// Parse message.
String[] split = rawMessage.split(" ");
List<String> args = new LinkedList<>(Arrays.asList(split));
String label = args.remove(0);
// Get command handler.
CommandHandler handler = this.commands.get(label);
if(handler == null) {
CommandHandler.sendMessage(player, "Unknown command: " + label); return;
if (handler == null) {
CommandHandler.sendMessage(player, "Unknown command: " + label);
return;
}
// Check for permission.
if(player != null) {
if (player != null) {
String permissionNode = this.annotations.get(label).permission();
Account account = player.getAccount();
if(!permissionNode.isEmpty() && !account.hasPermission(permissionNode)) {
CommandHandler.sendMessage(player, "You do not have permission to run this command."); return;
CommandHandler.sendMessage(player, "You do not have permission to run this command.");
return;
}
}
// Execution power check.
Command.Execution executionPower = this.annotations.get(label).execution();
if(player == null && executionPower == Command.Execution.PLAYER) {
CommandHandler.sendMessage(null, "Run this command in-game."); return;
} else if (player != null && executionPower == Command.Execution.CONSOLE) {
CommandHandler.sendMessage(player, "This command can only be run from the console."); return;
}
// Invoke execute method for handler.
if(player == null) handler.execute(args);
else handler.execute(player, args);
}
public CommandMap() {
this(false);
}
public CommandMap(boolean scan) {
if(scan) this.scan();
handler.execute(player, args);
}
/**
......
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.GenshinPlayer;
import java.util.List;
@Command(label = "account", usage = "account <create|delete> <username> [uid]",
description = "Modify user accounts")
public final class AccountCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer sender, List<String> args) {
if (sender != null) {
CommandHandler.sendMessage(sender, "This command can only be run from the console.");
return;
}
if (args.size() < 2) {
CommandHandler.sendMessage(null, "Usage: account <create|delete> <username> [uid]");
return;
}
String action = args.get(0);
String username = args.get(1);
switch (action) {
default:
CommandHandler.sendMessage(null, "Usage: account <create|delete> <username> [uid]");
return;
case "create":
int uid = 0;
if (args.size() > 2) {
try {
uid = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(null, "Invalid UID.");
return;
}
}
emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithId(username, uid);
if (account == null) {
CommandHandler.sendMessage(null, "Account already exists.");
return;
} else {
CommandHandler.sendMessage(null, "Account created with UID " + account.getPlayerUid() + ".");
account.addPermission("*"); // Grant the player superuser permissions.
account.save(); // Save account to database.
}
return;
case "delete":
if (DatabaseHelper.deleteAccount(username)) {
CommandHandler.sendMessage(null, "Account deleted.");
} else {
CommandHandler.sendMessage(null, "Account not found.");
}
}
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.GenshinPlayer;
import java.util.List;
@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 {
@Override
public void execute(GenshinPlayer sender, List<String> args) {
if (args.size() < 1) {
CommandHandler.sendMessage(sender, "Usage: broadcast <message>");
return;
}
String message = String.join(" ", args.subList(0, args.size()));
for (GenshinPlayer p : Grasscutter.getGameServer().getPlayers().values()) {
CommandHandler.sendMessage(p, message);
}
CommandHandler.sendMessage(sender, "Message sent.");
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.GenshinPlayer;
import java.util.List;
@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(GenshinPlayer sender, List<String> args) {
if (sender == null) {
CommandHandler.sendMessage(null, "Run this command in-game.");
return;
}
if (args.size() < 1) {
CommandHandler.sendMessage(sender, "Usage: changescene <scene id>");
return;
}
try {
int sceneId = Integer.parseInt(args.get(0));
if (sceneId == sender.getSceneId()) {
CommandHandler.sendMessage(sender, "You are already in that scene");
return;
}
boolean result = sender.getWorld().transferPlayerToScene(sender, sceneId, sender.getPos());
CommandHandler.sendMessage(sender, "Changed to scene " + sceneId);
if (!result) {
CommandHandler.sendMessage(sender, "Scene does not exist");
}
} catch (Exception e) {
CommandHandler.sendMessage(sender, "Usage: changescene <scene id>");
}
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.inventory.Inventory;
import emu.grasscutter.game.inventory.ItemType;
import java.util.List;
@Command(label = "clearartifacts", usage = "clearartifacts",
description = "Deletes all unequipped and unlocked level 0 artifacts, including yellow rarity ones from your inventory",
aliases = {"clearart"}, permission = "player.clearartifacts")
public final class ClearArtifactsCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer sender, List<String> args) {
if (sender == null) {
CommandHandler.sendMessage(null, "Run this command in-game.");
return; // TODO: clear player's artifacts from console or other players
}
Inventory playerInventory = sender.getInventory();
playerInventory.getItems().values().stream()
.filter(item -> item.getItemType() == ItemType.ITEM_RELIQUARY)
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
.filter(item -> !item.isLocked() && !item.isEquipped())
.forEach(item -> playerInventory.removeItem(item, item.getCount()));
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GenshinData;
import emu.grasscutter.data.def.ItemData;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.utils.Position;
import java.util.List;
@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 {
@Override
public void execute(GenshinPlayer sender, List<String> args) {
if (sender == null) {
CommandHandler.sendMessage(null, "Run this command in-game.");
return;
}
if (args.size() < 1) {
CommandHandler.sendMessage(sender, "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));
ItemData itemData = GenshinData.getItemDataMap().get(item);
if (itemData == null) {
CommandHandler.sendMessage(sender, "Invalid item id.");
return;
}
if (itemData.isEquip()) {
float range = (5f + (.1f * amount));
for (int i = 0; i < amount; i++) {
Position pos = sender.getPos().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f).addZ((float) (Math.random() * range) - (range / 2));
EntityItem entity = new EntityItem(sender.getScene(), sender, itemData, pos, 1);
sender.getScene().addEntity(entity);
}
} else {
EntityItem entity = new EntityItem(sender.getScene(), sender, itemData, sender.getPos().clone().addY(3f), amount);
sender.getScene().addEntity(entity);
}
CommandHandler.sendMessage(sender, String.format("Dropped %s of %s.", amount, item));
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, "Invalid item or player ID.");
}
}
}
\ 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.data.GenshinData;
import emu.grasscutter.data.def.AvatarData;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.avatar.GenshinAvatar;
import java.util.List;
@Command(label = "givechar", usage = "givechar <playerId> <avatarId> [level]",
description = "Gives the player a specified character", aliases = {"givec"}, permission = "player.givechar")
public final class GiveCharCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer sender, List<String> args) {
int target, avatarId, level = 1, ascension;
if (sender == null && args.size() < 2) {
CommandHandler.sendMessage(null, "Usage: givechar <player> <itemId|itemName> [amount]");
return;
}
switch (args.size()) {
default:
CommandHandler.sendMessage(sender, "Usage: givechar <player> <avatarId> [level]");
return;
case 2:
try {
target = Integer.parseInt(args.get(0));
if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) {
target = sender.getUid();
level = Integer.parseInt(args.get(1));
avatarId = Integer.parseInt(args.get(0));
} else {
avatarId = Integer.parseInt(args.get(1));
}
} catch (NumberFormatException ignored) {
// TODO: Parse from avatar name using GM Handbook.
CommandHandler.sendMessage(sender, "Invalid avatar or player ID.");
return;
}
break;
case 3:
try {
target = Integer.parseInt(args.get(0));
if (Grasscutter.getGameServer().getPlayerByUid(target) == null) {
CommandHandler.sendMessage(sender, "Invalid player ID.");
return;
}
avatarId = Integer.parseInt(args.get(1));
level = Integer.parseInt(args.get(2));
} catch (NumberFormatException ignored) {
// TODO: Parse from avatar name using GM Handbook.
CommandHandler.sendMessage(sender, "Invalid avatar or player ID.");
return;
}
break;
}
GenshinPlayer targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, "Player not found.");
return;
}
AvatarData avatarData = GenshinData.getAvatarDataMap().get(avatarId);
if (avatarData == null) {
CommandHandler.sendMessage(sender, "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);
CommandHandler.sendMessage(sender, String.format("Given %s to %s.", avatarId, target));
}
}
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