Skip to content
Snippets Groups Projects
Commit e6402c31 authored by memetrollsXD's avatar memetrollsXD
Browse files

Merge branch 'stable' into development

parents d5d90564 1dfe8733
Branches
Tags
No related merge requests found
Showing
with 413 additions and 678 deletions
name: "Build"
on:
push:
branches:
- "stable"
jobs:
Build-Server-Jar:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: '8'
- name: Run Gradle
run: .\gradlew.bat && .\gradlew jar
- name: Upload build
uses: actions/upload-artifact@v3
with:
name: Grasscutter
path: grasscutter.jar
[submodule "Grasscutter-Protos"]
path = Grasscutter-Protos
url = https://github.com/Melledy/Grasscutter-Protos
Subproject commit 0537e9cc4c7856a7c6f88bbbaa908a80c4ee677e
# Grasscutter
A WIP server emulator for Genshin Impact 2.3-2.6
A WIP server reimplementation for *some anime game* 2.3-2.6
**Documentation**: [Grasscutter Wiki](https://github.com/Melledy/Grasscutter/wiki/)
**Note**: For support please join the [Discord server](https://discord.gg/T5vZU6UyeG).
# Current features
* Logging in
* Spawning monsters via console
* Combat
* Spawning monsters via console
* Inventory features (recieving items/characters, upgrading items/characters, etc)
* Co-op does work, but movement is kind of buggy and some player ults do not spawn properly
* Friends list
* Gacha system
* Friends list
* Co-op *partially* work
# Quick setup guide
* For more information, we now have [Grasscutter Wiki](https://github.com/Melledy/Grasscutter/wiki/) page !
### Note
* If you update from an older version, delete `config.json` for regeneration
### Prerequisites
* JDK-8u202 ([mirror link](https://mirrors.huaweicloud.com/java/jdk/8u202-b08/) since Oracle required an account to download old builds)
* Mongodb (recommended 4.0+)
......@@ -22,13 +23,13 @@ A WIP server emulator for Genshin Impact 2.3-2.6
### Starting up Grasscutter server (Assuming you are on Windows)
1. Setup compile environment `gradlew.bat`
2. Compile Grasscutter with `gradlew jar`
3. Create a folder named `resources` in your Grasscutter directory, bring your `BinOutput` and `ExcelBinOutput` folders into it *(Check the wiki for more details where to get those.)*
4. Run Grasscutter with `java -jar grasscutter.jar`. Make sure mongodb is running as well.
3. Create a folder named `resources` in your Grasscutter directory, bring your `BinOutput` and `ExcelBinOutput` folders into it *(Check the wiki for more details how to get those.)*
4. Run Grasscutter with `java -jar grasscutter.jar`. Make sure mongodb service is running as well.
### Connecting with the client
½. Create an account using command below
½. Create an account using *server console command* below
1. Run a proxy daemon: (choose either one)
- mitmdump: `mitmdump -s proxy.py --ssl-insecure`
- mitmdump: `mitmdump -s proxy.py -k`
- Fiddler Classic: Run Fiddler Classic, turn on `Decrypt https traffic` in setting and change the default port there (Tools -> Options -> Connections) to anything other than `8888`, and load [this script](https://github.lunatic.moe/fiddlerscript).
- [Hosts file](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map)
2. Trust CA certificate:
......@@ -39,35 +40,40 @@ A WIP server emulator for Genshin Impact 2.3-2.6
* or you can use `run.cmd` to start Server & Proxy daemon with one click
# Grasscutter commands
### Server console commands
There is a dummy user named "Server" in every player's friends list that you can message to use commands. Commands also work in other chat rooms, such as private/team chats.
`account create [username] {playerid}` - Creates an account with the specified username and the in-game uid for that account. The playerid parameter is optional and will be auto generated if not set.
### In-Game commands
There is a dummy user named "Server" in every player's friends list that you can message to use commands. Commands also work in other chat rooms, such as private/team chats.
`spawn [monster id] [level] [amount]`
`give [item id] [amount]`
`givechar [avatar id] [level]`
`drop [item id] [amount]`
`!spawn [monster id] [level] [amount]`
`killall`
`!give [item id] [amount]`
`setworldlevel [level]` - Relog to see effects properly
`!givechar [avatar id] [level]`
`godmode` - Prevents you from taking damage
`!drop [item id] [amount]`
`resetconst` - Resets the constellation level on your current active character, will need to relog after using the command to see any changes.
`!killall`
`setstats [stats] [amount]` - Changes the current character's specified stat.
`!setworldlevel [level]` - Relog to see effects properly
`clearartifacts` - Deletes all unequipped and unlocked level 0 artifacts, **including yellow rarity ones** from your inventory
`!godmode` - Prevents you from taking damage
`pos` - Gets your current coordinate.
`!resetconst` - Resets the constellation level on your current active character, will need to relog after using the command to see any changes.
`weather [weather id] [climate id]` - Changes the current weather.
`!sethp [hp]`
*More commands will be updated in the [wiki](https://github.com/Melledy/Grasscutter/wiki/).*
`!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
* 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
* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Client
* If `4206` error constantly prompt up, try to use [jdk-8u202-b08](https://mirrors.huaweicloud.com/java/jdk/8u202-b08/) instead of other versions of JDK
......@@ -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'
}
......
......@@ -17,39 +17,24 @@
"gachaType": 301,
"scheduleId": 903,
"bannerType": "EVENT",
"prefabPath": "GachaShowPanel_A076",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A076",
"titlePath": "UI_GACHA_SHOW_PANEL_A076_TITLE",
"prefabPath": "GachaShowPanel_A079",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A079",
"titlePath": "UI_GACHA_SHOW_PANEL_A048_TITLE",
"costItem": 223,
"beginTime": 0,
"endTime": 1924992000,
"sortId": 9998,
"maxItemType": 1,
"rateUpItems1": [1066],
"rateUpItems2": [1023, 1043, 1064]
},
{
"gachaType": 400,
"scheduleId": 913,
"bannerType": "EVENT",
"prefabPath": "GachaShowPanel_A077",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A077",
"titlePath": "UI_Tab_GachaShowPanel_A077",
"costItem": 223,
"beginTime": 0,
"endTime": 1924992000,
"sortId": 9998,
"maxItemType": 1,
"rateUpItems1": [1022],
"rateUpItems2": [1023, 1043, 1064]
"rateUpItems1": [1002],
"rateUpItems2": [1053, 1020, 1045]
},
{
"gachaType": 302,
"scheduleId": 923,
"scheduleId": 913,
"bannerType": "WEAPON",
"prefabPath": "GachaShowPanel_A078",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A078",
"titlePath": "UI_GACHA_SHOW_PANEL_A078_TITLE",
"prefabPath": "GachaShowPanel_A080",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A080",
"titlePath": "UI_GACHA_SHOW_PANEL_A021_TITLE",
"costItem": 223,
"beginTime": 0,
"endTime": 1924992000,
......@@ -58,7 +43,7 @@
"eventChance": 75,
"softPity": 80,
"hardPity": 80,
"rateUpItems1": [11510, 15503],
"rateUpItems2": [11402, 12403, 13401, 14402, 15405]
"rateUpItems1": [11509, 12504],
"rateUpItems2": [11401, 12402, 13407, 14401, 15401]
}
]
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,19 +16,17 @@
# - mitmdump from mitmproxy
#
# @author MlgmXyysd
# @version 1.0
# @version 1.1
#
##
from mitmproxy import ctx, http
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:
def request(self, flow: http.HTTPFlow) -> None:
# This can also be replaced with another IP address.
REMOTE_HOST = "localhost"
LIST_DOMAINS = [
"api-os-takumi.mihoyo.com",
"hk4e-api-os-static.mihoyo.com",
......@@ -53,15 +51,23 @@ class MlgmXyysd_Genshin_Impact_Proxy:
"hk4e-sdk-os-static.hoyoverse.com",
"sdk-os-static.hoyoverse.com",
"api-account-os.hoyoverse.com",
"hk4e-sdk-os.hoyoverse.com"
"hk4e-sdk-os.hoyoverse.com",
"overseauspider.yuanshen.com",
"gameapi-account.mihoyo.com",
"minor-api.mihoyo.com",
"public-data-api.mihoyo.com",
"uspider.yuanshen.com",
"sdk-static.mihoyo.com"
]
if flow.request.url.startswith("http://overseauspider.yuanshen.com:8888/log"):
ctx.log.info("Block overseauspider.yuanshen.com")
flow.response = http.HTTPResponse.make(404)
elif flow.request.host in LIST_DOMAINS:
ctx.log.info("Redirect " + flow.request.host)
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.
USE_SSL = True
REMOTE_HOST = "127.0.0.1"
REMOTE_PORT = 443
\ No newline at end of file
@echo off
::This will not work if your java is in a different location, plugin as necessary
::this just saves you from changing your PATH
"C:\Program Files\Java\jdk1.8.0_202\bin\java.exe" -jar ./grasscutter.jar
\ 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;
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;
import java.util.ArrayList;
public String GameServerName = "Test";
public String GameServerIp = "127.0.0.1";
public String GameServerPublicIp = "";
public int GameServerPort = 22102;
public int UploadLogPort = 80;
public final class Config {
public String DatabaseUrl = "mongodb://localhost:27017";
public String DatabaseCollection = "grasscutter";
......@@ -23,26 +12,52 @@ public final class Config {
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 String RunMode = "HYBRID"; // HYBRID, DISPATCH_ONLY, GAME_ONLY
public GameServerOptions GameServer = new GameServerOptions();
public DispatchServerOptions DispatchServer = new DispatchServerOptions();
public GameRates getGameRates() {
return Game;
public GameServerOptions getGameServerOptions() {
return GameServer;
}
public ServerOptions getServerOptions() {
return ServerOptions;
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 GameRates {
public float ADVENTURE_EXP_RATE = 1.0f;
public float MORA_RATE = 1.0f;
public float DOMAIN_DROP_RATE = 1.0f;
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 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 static class ServerOptions {
public int InventoryLimitWeapon = 2000;
public int InventoryLimitRelic = 2000;
public int InventoryLimitMaterial = 2000;
......@@ -51,7 +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 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.
if(getConfig().RunMode.equalsIgnoreCase("HYBRID")) {
dispatchServer = new DispatchServer();
dispatchServer.start();
gameServer = new GameServer(new InetSocketAddress(getConfig().GameServerIp, getConfig().GameServerPort));
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 message The message to send.
*/
static void sendMessage(GenshinPlayer player, String message) {
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,17 +7,25 @@ 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 command The command handler.
* @return Instance chaining.
......@@ -36,11 +44,13 @@ public final class CommandMap {
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.
*/
......@@ -66,14 +76,20 @@ public final class CommandMap {
/**
* Returns a list of all registered commands.
*
* @return All command handlers as a list.
*/
public List<CommandHandler> getHandlers() {
public List<CommandHandler> getHandlersAsList() {
return new LinkedList<>(this.commands.values());
}
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.
*/
......@@ -83,13 +99,14 @@ 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 rawMessage The messaged used to invoke the command.
*/
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.
......@@ -104,38 +121,22 @@ public final class CommandMap {
// Get command handler.
CommandHandler handler = this.commands.get(label);
if (handler == null) {
CommandHandler.sendMessage(player, "Unknown command: " + label); return;
CommandHandler.sendMessage(player, "Unknown command: " + label);
return;
}
// Check for permission.
if (player != null) {
String permissionNode = this.annotations.get(label).permission();
Account account = player.getAccount();
List<String> permissions = account.getPermissions();
if(!permissions.contains("*") && !permissions.contains(permissionNode)) {
CommandHandler.sendMessage(player, "You do not have permission to run this command."); return;
if(!permissionNode.isEmpty() && !account.hasPermission(permissionNode)) {
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.");
}
}
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