mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-01-08 08:12:57 +08:00
Merge branch 'development' into stable
This commit is contained in:
commit
a8293102cf
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@ -25,6 +25,16 @@ jobs:
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: '17'
|
||||
- name: Cache gradle files
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
./.gradle/loom-cache
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle', 'gradle.properties', '**/*.accesswidener') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Run Gradle
|
||||
run: ./gradlew && ./gradlew jar
|
||||
- name: Upload build
|
||||
|
36
.gitignore
vendored
36
.gitignore
vendored
@ -17,7 +17,7 @@
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
@ -52,20 +52,30 @@ tmp/
|
||||
.vscode
|
||||
|
||||
# Grasscutter
|
||||
resources/
|
||||
logs/
|
||||
plugins/
|
||||
data/AbilityEmbryos.json
|
||||
data/OpenConfig.json
|
||||
/resources
|
||||
/logs
|
||||
/plugins
|
||||
/data
|
||||
/keys
|
||||
/language
|
||||
/languages
|
||||
/src/generated
|
||||
|
||||
/*.jar
|
||||
/*.sh
|
||||
|
||||
GM Handbook.txt
|
||||
config.json
|
||||
mitmdump.exe
|
||||
*.jar
|
||||
!lib/*.jar
|
||||
mongod.exe
|
||||
/src/generated/
|
||||
/*.sh
|
||||
language/
|
||||
languages/
|
||||
|
||||
gacha-mapping.js
|
||||
data/gacha_mappings.js
|
||||
mappings.js
|
||||
BuildConfig.java
|
||||
|
||||
# lombok
|
||||
/.apt_generated/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
data/hk4e/announcement/
|
||||
|
60
README.md
60
README.md
@ -67,7 +67,7 @@ EN | [中文](README_zh-CN.md)
|
||||
|
||||
2. Set network proxy to `127.0.0.1:8080` or the proxy port you specified.
|
||||
|
||||
**you can also use `start.cmd` to start servers and proxy daemons automatically**
|
||||
**you can also use `start.cmd` to start servers and proxy daemons automatically, but you have to set up JAVA_HOME enviroment**
|
||||
|
||||
### Building
|
||||
|
||||
@ -98,61 +98,11 @@ chmod +x gradlew
|
||||
|
||||
You can find the output jar in the root of the project folder.
|
||||
|
||||
## Commands
|
||||
|
||||
You might want to use this command (`java -jar grasscutter.jar -handbook`) in a cmd that is in the grasscutter folder. It will create a handbook file (GM Handbook.txt) where you can find the item IDs for stuff you want.
|
||||
|
||||
You may want to use this command (`java -jar grasscutter.jar -gachamap`) to generate a mapping file for the gacha record subsystem. The file will be generated to `GRASSCUTTER_RESOURCE/gcstatic` folder. Otherwise you may only see number IDs in the gacha record page.
|
||||
|
||||
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. to run commands ingame, you need to add prefix `/` or `!` such as `/pos`
|
||||
|
||||
| Commands | Usage | Permission node | Availability | description | Alias |
|
||||
| -------------- | ------------------------------------------------- | ------------------------- | ------------ | ------------------------------------------------------------ | ----------------------------------------------- |
|
||||
| account | account <create\|delete> \<username> [UID] | | Server only | Creates an account with the specified username and the in-game UID for that account. The UID will be auto generated if not set. | |
|
||||
| broadcast | broadcast \<message> | server.broadcast | Both side | Sends a message to all the players. | b |
|
||||
| coop | coop \<playerId> \<target playerId> | server.coop | Both side | Forces someone to join the world of others. | |
|
||||
| changescene | changescene \<scene id> | player.changescene | Client only | Switch scenes by scene ID. | scene |
|
||||
| clear | clear <all\|wp\|art\|mat> [UID] | player.clearinv | Client only | Deletes all unequipped and unlocked level 0 artifacts(art)/weapons(wp)/material(all) or all, including 5-star rarity ones from your inventory. | clear |
|
||||
| drop | drop <itemID\|itemName> [amount] | server.drop | Client only | Drops an item around you. | `d` `dropitem` |
|
||||
| enterdungeon | enterdungeon \<dungeon id> | player.enterdungeon | Client only | Enter a dungeon by dungeon ID | |
|
||||
| give | give [player] <itemId\|itemName> [amount] [level] [finement] | player.give | Both side | Gives item(s) to you or the specified player. (finement option only weapon.) | `g` `item` `giveitem` |
|
||||
| givechar | givechar \<uid> \<avatarId> | player.givechar | Both side | Gives the player a specified character. | givec |
|
||||
| giveart | giveart [player] \<artifactId> \<mainPropId> [\<appendPropId>[,\<times>]]... [level] | player.giveart | Both side | Gives the player a specified artifact. | gart |
|
||||
| giveall | giveall [uid] [amount] | player.giveall | Both side | Gives all items. | givea |
|
||||
| godmode | godmode [uid] | player.godmode | Client only | Prevents you from taking damage. | |
|
||||
| heal | heal | player.heal | Client only | Heals all characters in your current team. | h |
|
||||
| help | help [command] | | Both side | Sends the help message or shows information about a specified command. | |
|
||||
| kick | kick \<player> | server.kick | Both side | Kicks the specified player from the server. (WIP) | k |
|
||||
| killall | killall [playerUid] [sceneId] | server.killall | Both side | Kills all entities in the current scene or specified scene of the corresponding player. | |
|
||||
| list | list | | Both side | Lists online players. | |
|
||||
| permission | permission <add\|remove> \<UID> \<permission> | * | Both side | Grants or removes a permission for a user. | |
|
||||
| position | position | | Client only | Sends your current coordinates. | pos |
|
||||
| reload | reload | server.reload | Both side | Reloads the server config | |
|
||||
| resetconst | resetconst [all] | player.resetconstellation | Client only | Resets the constellation level on your currently selected character, will need to relog after using the command to see any changes. | resetconstellation |
|
||||
| restart | | | Both side | Restarts the current session | |
|
||||
| say | say \<player> \<message> | server.sendmessage | Both side | Sends a message to a player as the server | `sendservmsg` `sendservermessage` `sendmessage` |
|
||||
| setfetterlevel | setfetterlevel \<level> | player.setfetterlevel | Client only | Sets the friendship level for your currently selected character | setfetterlvl |
|
||||
| setstats | setstats \<stat> \<value> | player.setstats | Client only | Sets a stat for your currently selected character | stats |
|
||||
| setworldlevel | setworldlevel \<level> | player.setworldlevel | Client only | Sets your world level (Relog to see proper effects) | setworldlvl |
|
||||
| spawn | spawn \<entityId> [amount] [level(monster only)] | server.spawn | Client only | Spawns some entities around you | |
|
||||
| stop | stop | server.stop | Both side | Stops the server | |
|
||||
| talent | talent \<talentID> \<value> | player.settalent | Client only | Sets talent level for your currently selected character | |
|
||||
| teleport | teleport [@playerUid] \<x> \<y> \<z> [sceneId] | player.teleport | Both side | Change the player's position. | tp |
|
||||
| tpall | | player.tpall | Client only | Teleports all players in your world to your position | |
|
||||
| weather | weather \<weatherID> \<climateID> | player.weather | Client only | Changes the weather | w |
|
||||
|
||||
### Bonus
|
||||
|
||||
- Teleporting
|
||||
- When you want to teleport somewhere, use the in-game marking function on the map.
|
||||
- Mark a point on the map using the fish hook marking (the last one.)
|
||||
- (Optional) rename the map marker to a number to override the default Y coordinate (height, default 300.)
|
||||
- Confirm and close the map.
|
||||
- You will see your character falling from a very high destination, exact location that you marked.
|
||||
### Commands have moved to the [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)!
|
||||
|
||||
# Quick Troubleshooting
|
||||
|
||||
* If compiling wasn't successful, please check your JDK installation (JDK 17 and validated JDK's bin PATH variable)
|
||||
* My client doesn't connect, doesn't login, 4206, etc... - Your proxy daemon setup is most likely *the issue*, if you are using Fiddler, make sure it running on another port other than 8888
|
||||
|
||||
* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Game
|
||||
* 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.) > Game
|
||||
|
@ -123,11 +123,13 @@ chmod +x gradlew
|
||||
| godmode | godmode [uid] | player.godmode | 仅客户端 | 保护你不受到任何伤害(依然会被击退) | |
|
||||
| heal | heal | player.heal | 仅客户端 | 治疗队伍中所有角色 | h |
|
||||
| help | help [命令] | | 均可使用 | 显示帮助或展示指定命令的帮助 | |
|
||||
| join | join [多个角色id] | player.join | 仅客户端 | 强制入队角色,跟config.json中的avatarLimits有关(跟队内角色数量上限有关)。用法:`join 10000021 10000022` | |
|
||||
| kick | kick \<uid> | server.kick | 均可使用 | 从服务器中踢出指定玩家 (WIP) | k |
|
||||
| killall | killall [uid] [场景ID] | server.killall | 均可使用 | 杀死指定玩家世界中所在或指定场景的全部生物 | |
|
||||
| list | list | | 均可使用 | 列出在线玩家 | |
|
||||
| permission | permission <add\|remove> <UID> <权限节点> | * | 均可使用 | 添加或移除玩家的权限 | |
|
||||
| position | position | | 仅客户端 | 获取当前坐标 | pos |
|
||||
| remove | remove [多个角色在队伍中的序号] | player.remove | 仅客户端 | 强制将某个角色从当前队伍中移除。例如`remove 1 2`表示将1号和2号角色移除 | |
|
||||
| reload | reload | server.reload | 均可使用 | 重载服务器配置 | |
|
||||
| resetconst | resetconst [all] | player.resetconstellation | 仅客户端 | 重置当前角色的命座,重新登录即可生效 | resetconstellation |
|
||||
| restart | restart | | 均可使用 | 重启服务端 | |
|
||||
@ -140,6 +142,7 @@ chmod +x gradlew
|
||||
| talent | talent <天赋ID> <等级> | player.settalent | 仅客户端 | 设置当前角色的天赋等级 | |
|
||||
| teleport | teleport [@playerUid] \<x> \<y> \<z> [sceneId] | player.teleport | 均可使用 | 传送玩家到指定坐标 | tp |
|
||||
| tpall | | player.tpall | 仅客户端 | 传送多人世界中所有的玩家到自身地点 | |
|
||||
| unlocktower | | player.tower | 仅客户端 | 解锁深渊全部层 | ut |
|
||||
| weather | weather <天气ID> <气候ID> | player.weather | 仅客户端 | 改变天气 | w |
|
||||
|
||||
### 额外功能
|
||||
|
25
build.gradle
25
build.gradle
@ -43,7 +43,8 @@ sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
group = 'xyz.grasscutters'
|
||||
version = '1.1.0'
|
||||
version = '1.1.2-dev'
|
||||
|
||||
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
@ -86,6 +87,9 @@ dependencies {
|
||||
implementation group: 'org.luaj', name: 'luaj-jse', version: '3.0.1'
|
||||
|
||||
protobuf files('proto/')
|
||||
|
||||
compileOnly 'org.projectlombok:lombok:1.18.24'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.24'
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
@ -97,12 +101,14 @@ application {
|
||||
mainClassName = 'emu.grasscutter.Grasscutter'
|
||||
}
|
||||
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes 'Main-Class': 'emu.grasscutter.Grasscutter'
|
||||
}
|
||||
|
||||
jar.baseName = 'grasscutter'
|
||||
jar.archiveName = project.hasProperty('jarFilename') ? "${jarFilename}.${extension}" : archiveName
|
||||
|
||||
from {
|
||||
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
@ -226,6 +232,23 @@ javadoc {
|
||||
}
|
||||
}
|
||||
|
||||
task injectGitHash {
|
||||
def gitCommitHash = {
|
||||
try {
|
||||
return 'git rev-parse --verify --short HEAD'.execute().text.trim()
|
||||
} catch (e) {
|
||||
return "GIT_NOT_FOUND"
|
||||
}
|
||||
}
|
||||
new File(projectDir, "src/main/java/emu/grasscutter/BuildConfig.java").text = """
|
||||
package emu.grasscutter;
|
||||
public class BuildConfig {
|
||||
public static final String VERSION = \"${version}\";
|
||||
public static final String GIT_HASH = \"${gitCommitHash()}\";
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
processResources {
|
||||
dependsOn "generateProto"
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
[
|
||||
{
|
||||
"gachaType": 200,
|
||||
"scheduleId": 893,
|
||||
"bannerType": "STANDARD",
|
||||
"prefabPath": "GachaShowPanel_A022",
|
||||
"previewPrefabPath": "UI_Tab_GachaShowPanel_A022",
|
||||
"titlePath": "UI_GACHA_SHOW_PANEL_A022_TITLE",
|
||||
"costItem": 224,
|
||||
"beginTime": 0,
|
||||
"endTime": 1924992000,
|
||||
"sortId": 1000,
|
||||
"rateUpItems1": [],
|
||||
"rateUpItems2": []
|
||||
},
|
||||
{
|
||||
"gachaType": 301,
|
||||
"scheduleId": 903,
|
||||
"bannerType": "EVENT",
|
||||
"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": [1002],
|
||||
"rateUpItems2": [1053, 1020, 1045]
|
||||
},
|
||||
{
|
||||
"gachaType": 302,
|
||||
"scheduleId": 913,
|
||||
"bannerType": "WEAPON",
|
||||
"prefabPath": "GachaShowPanel_A080",
|
||||
"previewPrefabPath": "UI_Tab_GachaShowPanel_A080",
|
||||
"titlePath": "UI_GACHA_SHOW_PANEL_A021_TITLE",
|
||||
"costItem": 223,
|
||||
"beginTime": 0,
|
||||
"endTime": 1924992000,
|
||||
"sortId": 9997,
|
||||
"minItemType": 2,
|
||||
"eventChance": 75,
|
||||
"softPity": 80,
|
||||
"hardPity": 80,
|
||||
"rateUpItems1": [11509, 12504],
|
||||
"rateUpItems2": [11401, 12402, 13407, 14401, 15401]
|
||||
}
|
||||
]
|
@ -1,29 +0,0 @@
|
||||
{
|
||||
"list": [
|
||||
{
|
||||
"ann_id": 1,
|
||||
"title": "<b>Welcome to Grasscutter!</b>",
|
||||
"subtitle": "<b>Welcome</b>",
|
||||
"banner": "https://uploadstatic-sea.mihoyo.com/announcement/2020/09/17/f4aa42d505822805eebf4a55d72a78d8_2755691727027973637.jpg",
|
||||
"content": "Hi there!<br>First of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! Check out our:<br><div><p style=\"white-space: pre-wrap;\"><strong>¡þDiscord¡þ</strong></p><p style=\"white-space: pre-wrap;\"><a href=\"https://discord.gg/T5vZU6UyeG\">https://discord.gg/T5vZU6UyeG</a></p><p style=\"white-space: pre-wrap;\"><strong>¡þGitHub¡þ</strong></p><p style=\"white-space: pre-wrap;\"><a href=\"https://github.com/Grasscutters/Grasscutter\">https://github.com/Grasscutters/Grasscutter</a></p></div>",
|
||||
"lang": "es-es"
|
||||
},
|
||||
{
|
||||
"ann_id": 2,
|
||||
"title": "<b>How to use announcements</b>",
|
||||
"subtitle": "<b>How to use</b>",
|
||||
"banner": "https://uploadstatic-sea.mihoyo.com/announcement/2020/09/17/f4aa42d505822805eebf4a55d72a78d8_2755691727027973637.jpg",
|
||||
"content": "<strong>Tips<br></strong>>How to use announcements<br><br>>Announcement content can use HTML<br><br>>The specific content of the announcement is stored in the program directory<code>data/GameAnnouncement.json</code>, while<code>GameAnnouncementList.json</code> stores the announcement list data<br><br><strong>How to use</strong><br>>In <code>GameAnnouncement</code><table><thead><thead><tr><th>Parameters</th><th>Description</th></thead></thead><thbody><thead><tr><th>ann_Id</th><th>Announcement unique id</th></thead><thead><tr><th>title</th><th>Show at the top of the content</th></thead><thead><tr><th>subtitle</th><th>title shown on the left</th></thead><thead><tr><th>banner</th><th>Display between content and title</th></thead><thead><tr><th>content</th><th>as u see</th></thead><thead><tr><th>lang</th><th>display language</th></thead><thead><tr><th>total</th><th>Announcement quantity</th></thead></thbody></table><br><br>>In <code>GameAnnouncementList</code><br>If you want to add an annouement, please add the list data in the announcement type corresponding to GameAnnouncementList, and finally add the announcement content in GameAnnouncement",
|
||||
"lang": "es-es"
|
||||
},
|
||||
{
|
||||
"ann_id": 3,
|
||||
"title": "<b>ÕâÊǻ¹«¸æ--This is the event announcement</b>",
|
||||
"subtitle": "<b>Welcome</b>",
|
||||
"banner":"https://uploadstatic-sea.mihoyo.com/announcement/2020/09/22/7d85f19b152d218e73224d7c138a0fd0_5818585260283672899.jpg",
|
||||
"content": "Welcome",
|
||||
"lang": "es-es"
|
||||
}
|
||||
],
|
||||
"total": 3
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
{
|
||||
"t": "System.currentTimeMillis()",
|
||||
"list": [
|
||||
{
|
||||
"list": [
|
||||
{
|
||||
"ann_id": 1,
|
||||
"title": "<b>Welcome to Grasscutter!</b>",
|
||||
"subtitle": "<b>Welcome</b>",
|
||||
"banner": "https://uploadstatic-sea.mihoyo.com/announcement/2020/09/22/7d85f19b152d218e73224d7c138a0fd0_5818585260283672899.jpg",
|
||||
"content": "",
|
||||
"type_label": "Juego",
|
||||
"tag_label": "1",
|
||||
"tag_icon": "https://uploadstatic-sea.mihoyo.com/announcement/2020/03/05/a2588f1a51faee9fa8dfe9aead649dd6_7237021399135895303.png",
|
||||
"login_alert": 1,
|
||||
"lang": "es-es",
|
||||
"start_time": "2020-09-25 04:05:30",
|
||||
"end_time": "2023-10-30 11:00:00",
|
||||
"type": 2,
|
||||
"remind": 0,
|
||||
"alert": 0,
|
||||
"tag_start_time": "2000-01-02 15:04:05",
|
||||
"tag_end_time": "2030-01-02 15:04:05",
|
||||
"remind_ver": 1,
|
||||
"has_content": true,
|
||||
"extra_remind": 0
|
||||
},
|
||||
{
|
||||
"ann_id": 2,
|
||||
"title": "<b>这是游戏公告 -- This is the game announcement</b>",
|
||||
"subtitle": "<b>This is the game announcement</b>",
|
||||
"banner": "https://uploadstatic-sea.mihoyo.com/announcement/2020/09/17/85b7163c95745a76d49b3d163d893592_6487108933004985049.jpg",
|
||||
"content": "",
|
||||
"type_label": "Juego",
|
||||
"tag_label": "1",
|
||||
"tag_icon": "https://uploadstatic-sea.mihoyo.com/announcement/2020/03/05/a2588f1a51faee9fa8dfe9aead649dd6_7237021399135895303.png",
|
||||
"login_alert": 1,
|
||||
"lang": "es-es",
|
||||
"start_time": "2020-09-25 15:12:09",
|
||||
"end_time": "2030-10-30 11:00:00",
|
||||
"type": 2,
|
||||
"remind": 0,
|
||||
"alert": 0,
|
||||
"tag_start_time": "2000-01-02 08:04:05",
|
||||
"tag_end_time": "2030-01-02 08:04:05",
|
||||
"remind_ver": 1,
|
||||
"has_content": true,
|
||||
"extra_remind": 0
|
||||
}
|
||||
],
|
||||
"type_id": 2,
|
||||
"type_label": "Juego"
|
||||
},
|
||||
{
|
||||
"list": [
|
||||
{
|
||||
"ann_id": 3,
|
||||
"title": "<b>这是活动公告--This is the event announcement</b>",
|
||||
"subtitle": "<b>Welcome</b>",
|
||||
"banner": "https://uploadstatic-sea.mihoyo.com/announcement/2020/09/22/7d85f19b152d218e73224d7c138a0fd0_5818585260283672899.jpg",
|
||||
"content": "",
|
||||
"type_label": "Eventos",
|
||||
"tag_label": "1",
|
||||
"tag_icon": "https://uploadstatic-sea.mihoyo.com/announcement/2020/03/05/a2588f1a51faee9fa8dfe9aead649dd6_7237021399135895303.png",
|
||||
"login_alert": 1,
|
||||
"lang": "es-es",
|
||||
"start_time": "2020-09-25 04:05:30",
|
||||
"end_time": "2022-05-02 00:51:00",
|
||||
"type": 2,
|
||||
"remind": 0,
|
||||
"alert": 0,
|
||||
"tag_start_time": "2000-01-02 15:04:05",
|
||||
"tag_end_time": "2022-05-02 00:51:00",
|
||||
"remind_ver": 1,
|
||||
"has_content": true,
|
||||
"extra_remind": 0
|
||||
}
|
||||
],
|
||||
"type_id": 1,
|
||||
"type_label": "Eventos"
|
||||
},
|
||||
{
|
||||
"list": [
|
||||
{}
|
||||
],
|
||||
"type_id": 3,
|
||||
"type_label": "Others"
|
||||
}
|
||||
],
|
||||
"total": 3,
|
||||
"type_list": [
|
||||
{
|
||||
"id": 2,
|
||||
"name": "游戏系统公告",
|
||||
"mi18n_name": "Juego"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "活动公告",
|
||||
"mi18n_name": "Eventos"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "其他",
|
||||
"mi18n_name": "Others"
|
||||
}
|
||||
],
|
||||
"alert": true,
|
||||
"alert_id": 2,
|
||||
"timezone": -5,
|
||||
"pic_list": [
|
||||
],
|
||||
"pic_total": 0,
|
||||
"pic_type_list": [
|
||||
],
|
||||
"pic_alert": false,
|
||||
"pic_alert_id": 0,
|
||||
"static_sign": ""
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
ElIKBm9zX3VzYRIHQW1lcmljYRoKREVWX1BVQkxJQyIzaHR0cHM6Ly9vc3VzYWRpc3BhdGNoLnl1YW5zaGVuLmNvbS9xdWVyeV9jdXJfcmVnaW9uElMKB29zX2V1cm8SBkV1cm9wZRoKREVWX1BVQkxJQyI0aHR0cHM6Ly9vc2V1cm9kaXNwYXRjaC55dWFuc2hlbi5jb20vcXVlcnlfY3VyX3JlZ2lvbhJRCgdvc19hc2lhEgRBc2lhGgpERVZfUFVCTElDIjRodHRwczovL29zYXNpYWRpc3BhdGNoLnl1YW5zaGVuLmNvbS9xdWVyeV9jdXJfcmVnaW9uElUKBm9zX2NodBIKVFcsIEhLLCBNTxoKREVWX1BVQkxJQyIzaHR0cHM6Ly9vc2NodGRpc3BhdGNoLnl1YW5zaGVuLmNvbS9xdWVyeV9jdXJfcmVnaW9uKpwQRWMyYhAAAABbrAvbhfIRHfaSCN24qQyVAAgAAMs68ZiMdPfEj41O2wBCYqGiC/WdovvJvaw4t3/m1zIYDrt3/ftK9GKFb7C+2E8FmaHqOnwjJYBg2wI1sXpGmuSxkeWw8Avr36wlNtQjhXNV9zoNKstuZYuheyLlpbPRbYZ3UA6/BzTVsjIhjR1lcqFrigQnpV6MgRR9KqxakCaffK6qIzMlodx4ZPKlqseQhCiyVAvLWQSRqCRcZipzotXsmgLQbpDFtRzhgukXPjfW5dAlzMwswPuu7ZQsf1AKipI34dVQLu6gtXthGgbjn89h/79VR5AokLCPGqIV7/2s+gHfykrjDtyp5rwCcmGQqwV3gHy5LGrHl8Zm12jNd7Qcng51ydqtX4xzet6J2iMF6Dw5nPd/hTyxn+i3Ttk6fop9rbCq3iNgEw3+0cSDal1I1ThYdVnMgPhZgQkZc5/SpTaR+8vfDzRIKbSSrrPSEgLnQvWZOOugXhNdyuiaBc8rJveno7vvktmnhDUF3xWi6osj75j2KghRrdHfDR3Zuh4COrGZDRBSKHft2AvfrxaMT9O8hPzzzYk0U2iicVCDlNP/8wqaT9Vqt1kHmruLxqh377iyp0mxKfNt0+SNRzLyRoyvOar/z3AT6TU9LRoCFrkcJpVsUN+2MVeT52PfMbv5O/Nw9sqsFDlofCJJ/EknY0wDc+tNarYOhDM67/ojn/p6W3ZPBJxb2wcF1TOh9dpAeZdCGJusqhMIj5lpoW8nENTFhkEgMUv2Lh5Z6WpeOAKAu9eDpBMhlRNCccDaNYUgo6TdVDtWxtPrS3NRYqtkvb2I2SEFP0apht954oKdG3ncxyOgHRUkwgtxbCMAngzWo9+VWV3H3OlqeEOv7DdO2o0y95EvlHYb/qtosXPI2jC+6FPa+yl4xmLqcENRTUrU23dsmX3SyBEmZvML4dNeyC53B+mh7DUFtPFJFndxj2tGO9mTSDgy8eCmKG90AiJOMoxaLB2HpnDXN1sTiIcd3WraiE6ZCt4E54hKXvXHPyN52CHkxq1y/TeXHEq4X4MyHyDSRLHmzVs9pnwHM0ZLthKFNyvGfTvjiYokAWtNEuh74syt+m6Wietb6JvgibnnDj6uFKI3BbH4GUT9blsnMgug323bJ6bFvV4iESvz1fNnnUSokWQy5+fWzxPDohULgFzhDCpwov78Bp0E3t6DXSWnrUdNqpLbYKmXO1Hdbn+QH4B90p85UB1V5eSZgxPpUvZbIO4GPScil8K+dkDLdsFa1zypWNmlUN0Ns5H/iuzMuJql2QFYz+SnV1R1T+qywwqCNP9oswcLiAR3XnSacs52vd3PI9+0PZuoF6tVMWlvutsQ34IFZaAwIkdKigZcHumLBt/0KyFASBfN674n8FnHrHOQHU6oCeXkQA9kC8MtkvMb7fOLdzbTsD6SVojzZ64i9mDXxF+iLR9o52OxjIFzwLGRy/ivT/aAnHLZ3AsbnvslDjlQl2ADBFvf7xjmvFu0xlfK58TUpfVEkScFFapWJyKVybB4CRz1wKKz6n/a9581LpCVOWRsJa5p+j0zYcS2PfhmRf3RzwsDHeBjEVlIARbhxNKvmjdZyIidSdMMcsJHDRLE3bvo9kKfag0vRVKmuPLPc9FrACsz3vlkApcVQvzieHWoiP+foEvfj9+7Ti2tLfKdzVkMUmugZiZ46+7PKvIciiiuBPlyld0CCPTtTFHUOMO5dUfrUblX8K3awWiaNQFBS0J3iK08t1bgWfLhsKzsS32fRWugaqecwO9Rji9oHn+UuN8Nz9SgNxodroq9q7y/KHFxbqjCl62g25HN9zUa/s5wnIRwVAiWgTuOe3qGqjwp5m/GR8YVSSK/8mV9EL4AaF8d1uifdVA6wWSH1e/1UB8vcdU83P8ne3u1ho+Y/57WB7KnQaGaiD/108+wiAxNqMb2ex8on01VxdLKV1makXV3gzsvWaRevW8t/K11ZwYfo9g+guWADsA0JO0jWooiaupq1kNWrEheBdSRXBO7Jnb+56cTjPGwLpp7ZOHe/bSCJ4MGzPF3lK66LXhVo+rxvNjhoKVRjhGYxN4T8+AiRo3r+1KwdIGSrtODp3ri3JWAy6Eajp1Ukp9GaCbHSJFnYml84nKew7zLLe//ExQpjd4QAjMTvnbm+Ff6a1jf69QEVo0I33gI7/buwqgjiuvjeL6EYaMolKrKlHZHf/HwWbFbdID8T9aoyZJuCUd6YHaMPRAS6n5nvTwkRLlJ/f6wgyypUGZ22Bb1qGIb9SoPgSgIJkifUoewQW2EexqfoAsHXJVABLy+jp/SC4xzHZOSh42zU1k80HIgrnSOmu6T56F6gqy4Y2cZuZU8LXbO/01u8ifEz8yaXfEFSFdxE0TWl92OLKFtJZr9nNOBQQQr5FDGf6zB1/0CziG/5+PrUDgG3irzho6+7wXkc2CpxlBKOLWdjs3V/Lab6cURz1QZY4HYgUkJtm4U5OKUeO2+murlhC7SrnwyUtGrsD8NbCmI4SRHKPoeLBJQO/m3dRze5Ltr8N9IS7/ukPeOYe1O2agrmhH/JjYfz/l8Gmq8PGY+oavYp8I+2yKvGLD9kCxEgKcTeRh9AW/xPTLGsacrGKQCY+M76DfyLKxCZDiDY9xkBIKchxsMsn7FqZvRMMyJBHbqa3AKQyAN73NCSuFF5f1qDjARU/xqJFhOaKoR64c78oqh1GqOqEFbfNQIRw6WeFCGyW6v6p10uLdR7KXnR7+wub9aG992MpIBk0+gru74yO/WcA0vLdDEQIBwc+M0lmLB53ylsPtde3nliaC5ROHR1IS4LO8Q+3o0BHMr0my0bqFwwCAvZVXOFBHxXyUgrrmUTnZYVSQXNV6+MALBmmRU5yOzhhyHoEdj9YHZeyPpZkYc6DkJWCRYbFfmczNIs133KB9rlfug40w/hHa8pXyRyLaKQUMIUYEvt3Y4AQ==
|
295
install.sh
Normal file
295
install.sh
Normal file
@ -0,0 +1,295 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Grasscutter install script for linux
|
||||
# Made by TurtleIdiot
|
||||
|
||||
# Stops the installer if any command has a non-zero exit status
|
||||
set -e
|
||||
|
||||
# Checks for root
|
||||
if [ $EUID != 0 ]; then
|
||||
echo "Please run the installer as root!"
|
||||
exit
|
||||
fi
|
||||
|
||||
is_command() {
|
||||
# Checks if a given command is available
|
||||
local check_command="$1"
|
||||
command -v "${check_command}" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# IP validation
|
||||
valid_ip() {
|
||||
local ip=$1
|
||||
local stat=1
|
||||
|
||||
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
OIFS=$IFS
|
||||
IFS="."
|
||||
ip=($ip)
|
||||
IFS=$OIFS
|
||||
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
|
||||
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
|
||||
stat=$?
|
||||
fi
|
||||
return $stat
|
||||
}
|
||||
|
||||
# Checks for supported installer(s) (only apt-get and pacman right now, might add more in the future)
|
||||
if is_command apt-get ; then
|
||||
echo -e "Supported package manager found (apt-get)\n"
|
||||
|
||||
GC_DEPS="mongodb openjdk-17-jre"
|
||||
INSTALLER_DEPS="wget openssl unzip git"
|
||||
SYSTEM="deb" # Debian-based (debian, ubuntu)
|
||||
elif is_command pacman ; then
|
||||
echo -e "supported package manager found (pacman)\n"
|
||||
|
||||
GC_DEPS="jre17-openjdk"
|
||||
INSTALLER_DEPS="curl wget openssl unzip git base-devel" # curl is still a dependency here in order to successfully build mongodb
|
||||
SYSTEM="arch" # Arch for the elitists :P
|
||||
else
|
||||
echo "No supported package manager found"
|
||||
exit
|
||||
fi
|
||||
|
||||
BRANCH="stable" # Stable by default
|
||||
# Allows choice between stable and dev branch
|
||||
echo "Please select the branch you wish to install"
|
||||
echo -e "!!NOTE!!: stable is the recommended branch.\nDo *NOT* use development unless you have a reason to and know what you're doing"
|
||||
select branch in "stable" "development" ; do
|
||||
case $branch in
|
||||
stable )
|
||||
BRANCH="stable"
|
||||
break;;
|
||||
development )
|
||||
BRANCH="development"
|
||||
break;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "The following packages will have to be installed in order to INSTALL grasscutter:"
|
||||
echo -e "$INSTALLER_DEPS \n"
|
||||
echo "The following packages will have to be installed to RUN grasscutter:"
|
||||
echo -e "$GC_DEPS \n"
|
||||
|
||||
echo "Do you wish to proceed and install grasscutter?"
|
||||
select yn in "Yes" "No" ; do
|
||||
case $yn in
|
||||
Yes ) break;;
|
||||
No ) exit;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Updating package cache..."
|
||||
case $SYSTEM in # More concise than if
|
||||
deb ) apt-get update -qq;;
|
||||
arch ) pacman -Syy;;
|
||||
esac
|
||||
|
||||
# Starts installing dependencies
|
||||
echo "Installing setup dependencies..."
|
||||
case $SYSTEM in # These are one-liners anyways
|
||||
deb ) apt-get -qq install $INSTALLER_DEPS -y;;
|
||||
arch ) pacman -Sq --noconfirm --needed $INSTALLER_DEPS > /dev/null;;
|
||||
esac
|
||||
echo "Done"
|
||||
|
||||
echo "Installing grasscutter dependencies..."
|
||||
case $SYSTEM in
|
||||
deb) apt-get -qq install $GC_DEPS -y > /dev/null;;
|
||||
arch ) pacman -Sq --noconfirm --needed $GC_DEPS > /dev/null;;
|
||||
esac
|
||||
# *sighs* here we go...
|
||||
INST_ARCH_MONGO="no"
|
||||
if [ $SYSTEM = "arch" ]; then
|
||||
echo -e "-=-=-=-=-=--- !! IMPORTANT !! ---=-=-=-=-=-\n"
|
||||
echo -e " Due to licensing issues with mongodb,\n it is no longer available on the official arch repositiries."
|
||||
echo -e " In order to install mongodb,\n it needs to be fetched from the Arch User Repository.\n"
|
||||
echo -e " As this script is running as root,\n a temporary user will need to be created to run makepkg."
|
||||
echo -e " The temporary user will be deleted once\n makepkg has finished.\n"
|
||||
echo -e " This will be handled automatically.\n"
|
||||
echo -e "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"
|
||||
echo -e "!!NOTE!!: Only select \"Skip\" if mongodb is already installed on this system"
|
||||
echo "Do you want to continue?"
|
||||
select yn in "Yes" "Skip" "No" ; do
|
||||
case $yn in
|
||||
Yes )
|
||||
INST_ARCH_MONGO="yes"
|
||||
break;;
|
||||
No ) exit;;
|
||||
Skip )
|
||||
INST_ARCH_MONGO="no"
|
||||
break;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if [ $INST_ARCH_MONGO = "yes" ]; then
|
||||
DIR=$(pwd)
|
||||
# Make temp user
|
||||
echo "Creating temporary user..."
|
||||
TEMPUSER="gctempuser"
|
||||
TEMPHOME="/home/$TEMPUSER"
|
||||
useradd -m $TEMPUSER
|
||||
cd $TEMPHOME
|
||||
|
||||
# Do the actual makepkg shenanigans
|
||||
echo "Building mongodb... (this will take a moment)"
|
||||
su $TEMPUSER<<EOF
|
||||
mkdir temp
|
||||
cd temp
|
||||
git clone https://aur.archlinux.org/mongodb-bin.git -q
|
||||
cd mongodb-bin
|
||||
makepkg -s > /dev/null
|
||||
exit
|
||||
EOF
|
||||
mv "$(find -name "mongodb-bin*.pkg.tar.zst" -type f)" ./mongodb-bin.pkg.tar.zst
|
||||
cd $DIR
|
||||
|
||||
# Snatch the file to current working directory
|
||||
mv "$TEMPHOME/mongodb-bin.pkg.tar.zst" ./mongodb-bin.pkg.tar.zst
|
||||
chown root ./mongodb-bin.pkg.tar.zst
|
||||
chgrp root ./mongodb-bin.pkg.tar.zst
|
||||
chmod 775 ./mongodb-bin.pkg.tar.zst
|
||||
|
||||
echo "Installing mongodb..."
|
||||
pacman -U mongodb-bin.pkg.tar.zst --noconfirm > /dev/null
|
||||
rm mongodb-bin.pkg.tar.zst
|
||||
|
||||
echo "Starting mongodb..."
|
||||
systemctl enable mongodb
|
||||
systemctl start mongodb
|
||||
|
||||
echo "Removing temporary account..."
|
||||
userdel -r $TEMPUSER
|
||||
fi
|
||||
echo "Done"
|
||||
|
||||
echo "Getting grasscutter..."
|
||||
|
||||
# Download and rename jar
|
||||
wget -q --show-progress "https://nightly.link/Grasscutters/Grasscutter/workflows/build/$BRANCH/Grasscutter.zip"
|
||||
echo "unzipping"
|
||||
unzip -qq Grasscutter.zip
|
||||
mv $(find -name "grasscutter*.jar" -type f) grasscutter.jar
|
||||
|
||||
# Download resources
|
||||
echo "Downloading resources... (this will take a moment)"
|
||||
wget -q --show-progress https://github.com/Koko-boya/Grasscutter_Resources/archive/refs/heads/main.zip -O resources.zip
|
||||
echo "Extracting..."
|
||||
unzip -qq resources.zip
|
||||
mv ./Grasscutter_Resources-main/Resources ./resources
|
||||
|
||||
# Here we do a sparse checkout to only pull /data and /keys
|
||||
echo "Downloading keys and data..."
|
||||
mkdir repo
|
||||
cd repo
|
||||
git init -q
|
||||
git remote add origin https://github.com/Grasscutters/Grasscutter.git
|
||||
git fetch -q
|
||||
git config core.sparseCheckout true
|
||||
echo "data/" >> .git/info/sparse-checkout
|
||||
echo "keys/" >> .git/info/sparse-checkout
|
||||
git pull origin stable -q
|
||||
cd ../
|
||||
mv ./repo/data ./data
|
||||
mv ./repo/keys ./keys
|
||||
|
||||
# Generate handbook/config
|
||||
echo "Please enter language when *NEXT* prompted (press enter/return to continue to language select)"
|
||||
read
|
||||
java -jar grasscutter.jar -handbook
|
||||
|
||||
# Prompt IP address for config.json and for generating new keystore.p12 file
|
||||
echo "Please enter the IP address that will be used to connect to the server"
|
||||
echo "This can be a local or a public IP address"
|
||||
echo "This IP address will be used to generate SSL certificates so it is important it is correct"
|
||||
|
||||
while : ; do
|
||||
read -p "Enter IP: " SERVER_IP
|
||||
if valid_ip $SERVER_IP; then
|
||||
break;
|
||||
else
|
||||
echo "Invalid IP address. Try again."
|
||||
fi
|
||||
done
|
||||
|
||||
# Replaces "127.0.0.1" with given IP
|
||||
sed -i "s/127.0.0.1/$SERVER_IP/g" config.json
|
||||
|
||||
# Generates new keystore.p12 with the server's IP address
|
||||
# This is done to prevent a "Connection Timed Out" error from appearing
|
||||
# after clicking to enter the door in the main menu/title screen
|
||||
# This issue only exists when connecting to a server *other* than localhost
|
||||
# since the default keystore.p12 has only been made for localhost
|
||||
|
||||
mkdir certs
|
||||
cd certs
|
||||
echo "Generating CA key and certificate pair..."
|
||||
openssl req -x509 -nodes -days 25202 -newkey rsa:2048 -subj "/C=GB/ST=Essex/L=London/O=Grasscutters/OU=Grasscutters/CN=$SERVER_IP" -keyout CAkey.key -out CAcert.crt
|
||||
echo "Generating SSL key and certificate pair..."
|
||||
|
||||
openssl genpkey -out ssl.key -algorithm rsa
|
||||
|
||||
# Creates a conf file in order to generate a csr
|
||||
cat > csr.conf <<EOF
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C = GB
|
||||
ST = Essex
|
||||
L = London
|
||||
O = Grasscutters
|
||||
OU = Grasscutters
|
||||
CN = $SERVER_IP
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = $SERVER_IP
|
||||
EOF
|
||||
|
||||
# Creates csr using key and conf
|
||||
openssl req -new -key ssl.key -out ssl.csr -config csr.conf
|
||||
|
||||
# Creates conf to finalise creation of certificate
|
||||
cat > cert.conf <<EOF
|
||||
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, keyAgreement, dataEncipherment
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
IP.1 = $SERVER_IP
|
||||
|
||||
EOF
|
||||
|
||||
# Creates ssl cert
|
||||
openssl x509 -req -in ssl.csr -CA CAcert.crt -CAkey CAkey.key -CAcreateserial -out ssl.crt -days 25202 -sha256 -extfile cert.conf
|
||||
|
||||
echo "Generating keystore.p12 from key and certificate..."
|
||||
openssl pkcs12 -export -out keystore.p12 -inkey ssl.key -in ssl.crt -certfile CAcert.crt -passout pass:123456
|
||||
|
||||
cd ../
|
||||
mv ./certs/keystore.p12 ./keystore.p12
|
||||
echo "Done"
|
||||
|
||||
echo -e "Asking Noelle to clean up...\n"
|
||||
rm -rf Grasscutter.zip resources.zip ./certs ./Grasscutter_Resources-main ./repo
|
||||
echo -e "All done!\n"
|
||||
echo -e "You can now uninstall the following packages if you wish:\n$INSTALLER_DEPS"
|
||||
echo -e "-=-=-=-=-=--- !! IMPORTANT !! ---=-=-=-=-=-\n"
|
||||
echo "Please make sure that ports 443 and 22102 are OPEN (both tcp and udp)"
|
||||
echo -e "In order to run the server, run the following command:\nsudo java -jar grasscutter.jar"
|
||||
echo "You must run it using sudo as port 443 is a privileged port"
|
||||
echo "To play, use the IP you provided earlier ($SERVER_IP) via GrassClipper or Fiddler"
|
||||
|
||||
exit
|
Binary file not shown.
49
plugin-schema.json
Normal file
49
plugin-schema.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "JSON schema for a Grasscutter Plugin",
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"definitions": {
|
||||
"plugin-name": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z\\d_.-]+$"
|
||||
}
|
||||
},
|
||||
"required": [ "name", "description", "mainClass" ],
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "The unique name of plugin.",
|
||||
"$ref": "#/definitions/plugin-name"
|
||||
},
|
||||
"mainClass": {
|
||||
"description": "The plugin's initial class file.",
|
||||
"type": "string",
|
||||
"pattern": "^(?!org\\.bukkit\\.)([a-zA-Z_$][a-zA-Z\\d_$]*\\.)*[a-zA-Z_$][a-zA-Z\\d_$]*$"
|
||||
},
|
||||
"version": {
|
||||
"description": "A plugin revision identifier.",
|
||||
"type": [ "string", "number" ]
|
||||
},
|
||||
"description": {
|
||||
"description": "Human readable plugin summary.",
|
||||
"type": "string"
|
||||
},
|
||||
"author": {
|
||||
"description": "The plugin author.",
|
||||
"type": "string"
|
||||
},
|
||||
"authors": {
|
||||
"description": "The plugin contributors.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"title": "Website",
|
||||
"description": "The URL to the plugin's site",
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
package emu.grasscutter;
|
||||
|
||||
import java.util.Locale;
|
||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||
import emu.grasscutter.game.mail.Mail;
|
||||
|
||||
public final class Config {
|
||||
public String DatabaseUrl = "mongodb://localhost:27017";
|
||||
public String DatabaseCollection = "grasscutter";
|
||||
|
||||
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 String SCRIPTS_FOLDER = "./resources/Scripts/";
|
||||
public String PLUGINS_FOLDER = "./plugins/";
|
||||
|
||||
public ServerDebugMode DebugMode = ServerDebugMode.NONE; // ALL, MISSING, NONE
|
||||
public ServerRunMode RunMode = ServerRunMode.HYBRID; // HYBRID, DISPATCH_ONLY, GAME_ONLY
|
||||
public GameServerOptions GameServer = new GameServerOptions();
|
||||
public DispatchServerOptions DispatchServer = new DispatchServerOptions();
|
||||
public Locale LocaleLanguage = Locale.getDefault();
|
||||
public Locale DefaultLanguage = Locale.ENGLISH;
|
||||
|
||||
public Boolean OpenStamina = true;
|
||||
public GameServerOptions getGameServerOptions() {
|
||||
return GameServer;
|
||||
}
|
||||
|
||||
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 int PublicPort = 0;
|
||||
public String KeystorePath = "./keystore.p12";
|
||||
public String KeystorePassword = "123456";
|
||||
public Boolean UseSSL = true;
|
||||
public Boolean FrontHTTPS = true;
|
||||
public Boolean CORS = false;
|
||||
public String[] CORSAllowedOrigins = new String[] { "*" };
|
||||
|
||||
public boolean AutomaticallyCreateAccounts = false;
|
||||
public String[] defaultPermissions = new String[] { "" };
|
||||
|
||||
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 GameServerOptions {
|
||||
public String Name = "Test";
|
||||
public String Ip = "0.0.0.0";
|
||||
public String PublicIp = "127.0.0.1";
|
||||
public int Port = 22102;
|
||||
public int PublicPort = 0;
|
||||
|
||||
public String DispatchServerDatabaseUrl = "mongodb://localhost:27017";
|
||||
public String DispatchServerDatabaseCollection = "grasscutter";
|
||||
|
||||
public int InventoryLimitWeapon = 2000;
|
||||
public int InventoryLimitRelic = 2000;
|
||||
public int InventoryLimitMaterial = 2000;
|
||||
public int InventoryLimitFurniture = 2000;
|
||||
public int InventoryLimitAll = 30000;
|
||||
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 String ServerNickname = "Server";
|
||||
public int ServerAvatarId = 10000007;
|
||||
public int ServerNameCardId = 210001;
|
||||
public int ServerLevel = 1;
|
||||
public int ServerWorldLevel = 1;
|
||||
public String ServerSignature = "Server Signature";
|
||||
public int[] WelcomeEmotes = {2007, 1002, 4010};
|
||||
public String WelcomeMotd = "Welcome to Grasscutter emu";
|
||||
public String WelcomeMailTitle = "Welcome to Grasscutter!";
|
||||
public String WelcomeMailSender = "Lawnmower";
|
||||
public String WelcomeMailContent = "Hi there!\r\nFirst of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r\n\r\nCheck out our:\r\n<type=\"browser\" text=\"Discord\" href=\"https://discord.gg/T5vZU6UyeG\"/>";
|
||||
public Mail.MailItem[] WelcomeMailItems = {
|
||||
new Mail.MailItem(13509, 1, 1),
|
||||
new Mail.MailItem(201, 10000, 1),
|
||||
};
|
||||
|
||||
public boolean EnableOfficialShop = true;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
111
src/main/java/emu/grasscutter/Configuration.java
Normal file
111
src/main/java/emu/grasscutter/Configuration.java
Normal file
@ -0,0 +1,111 @@
|
||||
package emu.grasscutter;
|
||||
|
||||
import emu.grasscutter.utils.ConfigContainer;
|
||||
import emu.grasscutter.utils.ConfigContainer.*;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static emu.grasscutter.Grasscutter.config;
|
||||
|
||||
|
||||
/**
|
||||
* A data container for the server's configuration.
|
||||
*
|
||||
* Use `import static emu.grasscutter.Configuration.*;`
|
||||
* to import all configuration constants.
|
||||
*/
|
||||
public final class Configuration extends ConfigContainer {
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
|
||||
// 'c' is short for 'config' and makes code look 'cleaner'.
|
||||
public static final ConfigContainer c = config;
|
||||
|
||||
public static final Locale LANGUAGE = config.language.language;
|
||||
public static final Locale FALLBACK_LANGUAGE = config.language.fallback;
|
||||
public static final String DOCUMENT_LANGUAGE = config.language.document;
|
||||
private static final String DATA_FOLDER = config.folderStructure.data;
|
||||
private static final String RESOURCES_FOLDER = config.folderStructure.resources;
|
||||
private static final String PLUGINS_FOLDER = config.folderStructure.plugins;
|
||||
private static final String SCRIPTS_FOLDER = config.folderStructure.scripts;
|
||||
private static final String PACKETS_FOLDER = config.folderStructure.packets;
|
||||
|
||||
public static final Server SERVER = config.server;
|
||||
public static final Database DATABASE = config.databaseInfo;
|
||||
public static final Account ACCOUNT = config.account;
|
||||
|
||||
public static final HTTP HTTP_INFO = config.server.http;
|
||||
public static final Game GAME_INFO = config.server.game;
|
||||
public static final Dispatch DISPATCH_INFO = config.server.dispatch;
|
||||
|
||||
public static final Encryption HTTP_ENCRYPTION = config.server.http.encryption;
|
||||
public static final Policies HTTP_POLICIES = config.server.http.policies;
|
||||
public static final Files HTTP_STATIC_FILES = config.server.http.files;
|
||||
|
||||
public static final GameOptions GAME_OPTIONS = config.server.game.gameOptions;
|
||||
public static final GameOptions.InventoryLimits INVENTORY_LIMITS = config.server.game.gameOptions.inventoryLimits;
|
||||
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
public static String DATA() {
|
||||
return DATA_FOLDER;
|
||||
}
|
||||
|
||||
public static String DATA(String path) {
|
||||
return Paths.get(DATA_FOLDER, path).toString();
|
||||
}
|
||||
|
||||
public static String RESOURCE(String path) {
|
||||
return Paths.get(RESOURCES_FOLDER, path).toString();
|
||||
}
|
||||
|
||||
public static String PLUGIN() {
|
||||
return PLUGINS_FOLDER;
|
||||
}
|
||||
|
||||
public static String PLUGIN(String path) {
|
||||
return Paths.get(PLUGINS_FOLDER, path).toString();
|
||||
}
|
||||
|
||||
public static String SCRIPT(String path) {
|
||||
return Paths.get(SCRIPTS_FOLDER, path).toString();
|
||||
}
|
||||
|
||||
public static String PACKET(String path) {
|
||||
return Paths.get(PACKETS_FOLDER, path).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback method.
|
||||
* @param left Attempt to use.
|
||||
* @param right Use if left is undefined.
|
||||
* @return Left or right.
|
||||
*/
|
||||
public static <T> T lr(T left, T right) {
|
||||
return left == null ? right : left;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Configuration#lr(Object, Object)} for {@link String}s.
|
||||
* @param left Attempt to use.
|
||||
* @param right Use if left is empty.
|
||||
* @return Left or right.
|
||||
*/
|
||||
public static String lr(String left, String right) {
|
||||
return left.isEmpty() ? right : left;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Configuration#lr(Object, Object)} for {@link Integer}s.
|
||||
* @param left Attempt to use.
|
||||
* @param right Use if left is 0.
|
||||
* @return Left or right.
|
||||
*/
|
||||
public static int lr(int left, int right) {
|
||||
return left == 0 ? right : left;
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
|
||||
public final class GameConstants {
|
||||
public static String VERSION = "2.6.0";
|
||||
public static String VERSION = "2.7.0";
|
||||
|
||||
public static final int MAX_TEAMS = 4;
|
||||
public static final int MAIN_CHARACTER_MALE = 10000005;
|
||||
|
@ -1,15 +1,22 @@
|
||||
package emu.grasscutter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOError;
|
||||
import java.io.*;
|
||||
import java.util.Calendar;
|
||||
|
||||
import emu.grasscutter.auth.AuthenticationSystem;
|
||||
import emu.grasscutter.auth.DefaultAuthentication;
|
||||
import emu.grasscutter.command.CommandMap;
|
||||
import emu.grasscutter.game.managers.EnergyManager.EnergyManager;
|
||||
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
||||
import emu.grasscutter.plugin.PluginManager;
|
||||
import emu.grasscutter.plugin.api.ServerHook;
|
||||
import emu.grasscutter.scripts.ScriptLoader;
|
||||
import emu.grasscutter.server.http.HttpServer;
|
||||
import emu.grasscutter.server.http.dispatch.DispatchHandler;
|
||||
import emu.grasscutter.server.http.handlers.*;
|
||||
import emu.grasscutter.server.http.dispatch.RegionHandler;
|
||||
import emu.grasscutter.server.http.documentation.DocumentationServerHandler;
|
||||
import emu.grasscutter.utils.ConfigContainer;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import org.jline.reader.EndOfFileException;
|
||||
import org.jline.reader.LineReader;
|
||||
@ -27,30 +34,33 @@ import ch.qos.logback.classic.Logger;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.database.DatabaseManager;
|
||||
import emu.grasscutter.utils.Language;
|
||||
import emu.grasscutter.server.dispatch.DispatchServer;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.tools.Tools;
|
||||
import emu.grasscutter.utils.Crypto;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
|
||||
public final class Grasscutter {
|
||||
private static final Logger log = (Logger) LoggerFactory.getLogger(Grasscutter.class);
|
||||
private static LineReader consoleLineReader = null;
|
||||
|
||||
private static Config config;
|
||||
|
||||
private static Language language;
|
||||
|
||||
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
private static final File configFile = new File("./config.json");
|
||||
public static final File configFile = new File("./config.json");
|
||||
|
||||
private static int day; // Current day of week.
|
||||
|
||||
private static DispatchServer dispatchServer;
|
||||
private static HttpServer httpServer;
|
||||
private static GameServer gameServer;
|
||||
private static PluginManager pluginManager;
|
||||
private static AuthenticationSystem authenticationSystem;
|
||||
|
||||
public static final Reflections reflector = new Reflections("emu.grasscutter");
|
||||
public static ConfigContainer config;
|
||||
|
||||
static {
|
||||
// Declare logback configuration.
|
||||
@ -58,6 +68,8 @@ public final class Grasscutter {
|
||||
|
||||
// Load server configuration.
|
||||
Grasscutter.loadConfig();
|
||||
// Attempt to update configuration.
|
||||
ConfigContainer.updateConfig();
|
||||
|
||||
// Load translation files.
|
||||
Grasscutter.loadLanguage();
|
||||
@ -66,9 +78,9 @@ public final class Grasscutter {
|
||||
Utils.startupCheck();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Crypto.loadKeys(); // Load keys from buffers.
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Crypto.loadKeys(); // Load keys from buffers.
|
||||
|
||||
// Parse arguments.
|
||||
boolean exitEarly = false;
|
||||
for (String arg : args) {
|
||||
@ -77,57 +89,81 @@ public final class Grasscutter {
|
||||
Tools.createGmHandbook(); exitEarly = true;
|
||||
}
|
||||
case "-gachamap" -> {
|
||||
Tools.createGachaMapping(Grasscutter.getConfig().DATA_FOLDER + "/gacha_mappings.js"); exitEarly = true;
|
||||
Tools.createGachaMapping(DATA("gacha_mappings.js")); exitEarly = true;
|
||||
}
|
||||
case "-version" -> {
|
||||
System.out.println("Grasscutter version: " + BuildConfig.VERSION + "-" + BuildConfig.GIT_HASH); exitEarly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exit early if argument sets it.
|
||||
if(exitEarly) System.exit(0);
|
||||
|
||||
|
||||
// Initialize server.
|
||||
Grasscutter.getLogger().info(translate("messages.status.starting"));
|
||||
|
||||
Grasscutter.getLogger().info(translate("messages.status.game_version", GameConstants.VERSION));
|
||||
Grasscutter.getLogger().info(translate("messages.status.version", BuildConfig.VERSION, BuildConfig.GIT_HASH));
|
||||
|
||||
// Load all resources.
|
||||
Grasscutter.updateDayOfWeek();
|
||||
ResourceLoader.loadAll();
|
||||
ScriptLoader.init();
|
||||
|
||||
EnergyManager.initialize();
|
||||
|
||||
// Initialize database.
|
||||
DatabaseManager.initialize();
|
||||
|
||||
|
||||
// Initialize the default authentication system.
|
||||
authenticationSystem = new DefaultAuthentication();
|
||||
|
||||
// Create server instances.
|
||||
dispatchServer = new DispatchServer();
|
||||
httpServer = new HttpServer();
|
||||
gameServer = new GameServer();
|
||||
// Create a server hook instance with both servers.
|
||||
new ServerHook(gameServer, dispatchServer);
|
||||
new ServerHook(gameServer, httpServer);
|
||||
|
||||
// Create plugin manager instance.
|
||||
pluginManager = new PluginManager();
|
||||
|
||||
// Add HTTP routes after loading plugins.
|
||||
httpServer.addRouter(HttpServer.UnhandledRequestRouter.class);
|
||||
httpServer.addRouter(HttpServer.DefaultRequestRouter.class);
|
||||
httpServer.addRouter(RegionHandler.class);
|
||||
httpServer.addRouter(LogHandler.class);
|
||||
httpServer.addRouter(GenericHandler.class);
|
||||
httpServer.addRouter(AnnouncementsHandler.class);
|
||||
httpServer.addRouter(DispatchHandler.class);
|
||||
httpServer.addRouter(GachaHandler.class);
|
||||
httpServer.addRouter(DocumentationServerHandler.class);
|
||||
|
||||
// TODO: find a better place?
|
||||
StaminaManager.initialize();
|
||||
|
||||
// Start servers.
|
||||
if (getConfig().RunMode == ServerRunMode.HYBRID) {
|
||||
dispatchServer.start();
|
||||
var runMode = SERVER.runMode;
|
||||
if (runMode == ServerRunMode.HYBRID) {
|
||||
httpServer.start();
|
||||
gameServer.start();
|
||||
} else if (getConfig().RunMode == ServerRunMode.DISPATCH_ONLY) {
|
||||
dispatchServer.start();
|
||||
} else if (getConfig().RunMode == ServerRunMode.GAME_ONLY) {
|
||||
} else if (runMode == ServerRunMode.DISPATCH_ONLY) {
|
||||
httpServer.start();
|
||||
} else if (runMode == ServerRunMode.GAME_ONLY) {
|
||||
gameServer.start();
|
||||
} else {
|
||||
getLogger().error(translate("messages.status.run_mode_error", getConfig().RunMode));
|
||||
getLogger().error(translate("messages.status.run_mode_error", runMode));
|
||||
getLogger().error(translate("messages.status.run_mode_help"));
|
||||
getLogger().error(translate("messages.status.shutdown"));
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
|
||||
// Enable all plugins.
|
||||
pluginManager.enablePlugins();
|
||||
|
||||
|
||||
// Hook into shutdown event.
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(Grasscutter::onShutdown));
|
||||
|
||||
|
||||
// Open console.
|
||||
startConsole();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Server shutdown event.
|
||||
@ -137,75 +173,61 @@ public final class Grasscutter {
|
||||
pluginManager.disablePlugins();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods for the language system component.
|
||||
*/
|
||||
|
||||
public static void loadLanguage() {
|
||||
var locale = config.LocaleLanguage;
|
||||
var languageTag = locale.toLanguageTag();
|
||||
|
||||
if (languageTag.equals("und")) {
|
||||
Grasscutter.getLogger().error("Illegal locale language, using 'en-US' instead.");
|
||||
language = Language.getLanguage("en-US");
|
||||
} else {
|
||||
language = Language.getLanguage(languageTag);
|
||||
}
|
||||
var locale = config.language.language;
|
||||
language = Language.getLanguage(Utils.getLanguageCode(locale));
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods for the configuration system component.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Attempts to load the configuration from a file.
|
||||
*/
|
||||
public static void loadConfig() {
|
||||
// Check if config.json exists. If not, we generate a new config.
|
||||
if (!configFile.exists()) {
|
||||
getLogger().info("config.json could not be found. Generating a default configuration ...");
|
||||
config = new ConfigContainer();
|
||||
Grasscutter.saveConfig(config);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the file already exists, we attempt to load it.
|
||||
try (FileReader file = new FileReader(configFile)) {
|
||||
config = gson.fromJson(file, ConfigContainer.class);
|
||||
} catch (Exception exception) {
|
||||
getLogger().error("There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json.");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveConfig() {
|
||||
/**
|
||||
* Saves the provided server configuration.
|
||||
* @param config The configuration to save, or null for a new one.
|
||||
*/
|
||||
public static void saveConfig(@Nullable ConfigContainer config) {
|
||||
if(config == null) config = new ConfigContainer();
|
||||
|
||||
try (FileWriter file = new FileWriter(configFile)) {
|
||||
file.write(gson.toJson(config));
|
||||
} catch (IOException ignored) {
|
||||
Grasscutter.getLogger().error("Unable to write to config file.");
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error("Unable to save config file.");
|
||||
Grasscutter.getLogger().error("Unable to save config file.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startConsole() {
|
||||
// Console should not start in dispatch only mode.
|
||||
if (getConfig().RunMode == ServerRunMode.DISPATCH_ONLY) {
|
||||
getLogger().info(translate("messages.dispatch.no_commands_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
getLogger().info(translate("messages.status.done"));
|
||||
String input = null;
|
||||
boolean isLastInterrupted = false;
|
||||
while (true) {
|
||||
try {
|
||||
input = consoleLineReader.readLine("> ");
|
||||
} catch (UserInterruptException e) {
|
||||
if (!isLastInterrupted) {
|
||||
isLastInterrupted = true;
|
||||
Grasscutter.getLogger().info("Press Ctrl-C again to shutdown.");
|
||||
continue;
|
||||
} else {
|
||||
Runtime.getRuntime().exit(0);
|
||||
}
|
||||
} catch (EndOfFileException e) {
|
||||
Grasscutter.getLogger().info("EOF detected.");
|
||||
continue;
|
||||
} catch (IOError e) {
|
||||
Grasscutter.getLogger().error("An IO error occurred.", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
isLastInterrupted = false;
|
||||
try {
|
||||
CommandMap.getInstance().invoke(null, null, input);
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error(translate("messages.game.command_error"), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Config getConfig() {
|
||||
/*
|
||||
* Getters for the various server components.
|
||||
*/
|
||||
|
||||
public static ConfigContainer getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@ -213,6 +235,14 @@ public final class Grasscutter {
|
||||
return language;
|
||||
}
|
||||
|
||||
public static void setLanguage(Language language) {
|
||||
Grasscutter.language = language;
|
||||
}
|
||||
|
||||
public static Language getLanguage(String langCode) {
|
||||
return Language.getLanguage(langCode);
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
return log;
|
||||
}
|
||||
@ -241,8 +271,8 @@ public final class Grasscutter {
|
||||
return gson;
|
||||
}
|
||||
|
||||
public static DispatchServer getDispatchServer() {
|
||||
return dispatchServer;
|
||||
public static HttpServer getHttpServer() {
|
||||
return httpServer;
|
||||
}
|
||||
|
||||
public static GameServer getGameServer() {
|
||||
@ -252,16 +282,74 @@ public final class Grasscutter {
|
||||
public static PluginManager getPluginManager() {
|
||||
return pluginManager;
|
||||
}
|
||||
|
||||
public static void updateDayOfWeek() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
day = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
|
||||
public static AuthenticationSystem getAuthenticationSystem() {
|
||||
return authenticationSystem;
|
||||
}
|
||||
|
||||
public static int getCurrentDayOfWeek() {
|
||||
return day;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility methods.
|
||||
*/
|
||||
|
||||
public static void updateDayOfWeek() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
day = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
}
|
||||
|
||||
public static void startConsole() {
|
||||
// Console should not start in dispatch only mode.
|
||||
if (SERVER.runMode == ServerRunMode.DISPATCH_ONLY) {
|
||||
getLogger().info(translate("messages.dispatch.no_commands_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
getLogger().info(translate("messages.status.done"));
|
||||
String input = null;
|
||||
boolean isLastInterrupted = false;
|
||||
while (config.server.game.enableConsole) {
|
||||
try {
|
||||
input = consoleLineReader.readLine("> ");
|
||||
} catch (UserInterruptException e) {
|
||||
if (!isLastInterrupted) {
|
||||
isLastInterrupted = true;
|
||||
Grasscutter.getLogger().info("Press Ctrl-C again to shutdown.");
|
||||
continue;
|
||||
} else {
|
||||
Runtime.getRuntime().exit(0);
|
||||
}
|
||||
} catch (EndOfFileException e) {
|
||||
Grasscutter.getLogger().info("EOF detected.");
|
||||
continue;
|
||||
} catch (IOError e) {
|
||||
Grasscutter.getLogger().error("An IO error occurred.", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
isLastInterrupted = false;
|
||||
try {
|
||||
CommandMap.getInstance().invoke(null, null, input);
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error(translate("messages.game.command_error"), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authentication system for the server.
|
||||
* @param authenticationSystem The authentication system to use.
|
||||
*/
|
||||
public static void setAuthenticationSystem(AuthenticationSystem authenticationSystem) {
|
||||
Grasscutter.authenticationSystem = authenticationSystem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enums for the configuration.
|
||||
*/
|
||||
|
||||
public enum ServerRunMode {
|
||||
HYBRID, DISPATCH_ONLY, GAME_ONLY
|
||||
}
|
||||
|
134
src/main/java/emu/grasscutter/auth/AuthenticationSystem.java
Normal file
134
src/main/java/emu/grasscutter/auth/AuthenticationSystem.java
Normal file
@ -0,0 +1,134 @@
|
||||
package emu.grasscutter.auth;
|
||||
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.server.http.objects.*;
|
||||
import express.http.Request;
|
||||
import express.http.Response;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Defines an authenticator for the server.
|
||||
* Can be changed by plugins.
|
||||
*/
|
||||
public interface AuthenticationSystem {
|
||||
|
||||
/**
|
||||
* Called when a user requests to make an account.
|
||||
* @param username The provided username.
|
||||
* @param password The provided password. (SHA-256'ed)
|
||||
*/
|
||||
void createAccount(String username, String password);
|
||||
|
||||
/**
|
||||
* Called when a user requests to reset their password.
|
||||
* @param username The username of the account to reset.
|
||||
*/
|
||||
void resetPassword(String username);
|
||||
|
||||
/**
|
||||
* Called by plugins to internally verify a user's identity.
|
||||
* @param details A unique identifier to identify the user. (For example: a JWT token)
|
||||
* @return The user's account if the verification was successful, null if the user was unable to be verified.
|
||||
*/
|
||||
Account verifyUser(String details);
|
||||
|
||||
/**
|
||||
* This is the authenticator used for password authentication.
|
||||
* @return An authenticator.
|
||||
*/
|
||||
Authenticator<LoginResultJson> getPasswordAuthenticator();
|
||||
|
||||
/**
|
||||
* This is the authenticator used for token authentication.
|
||||
* @return An authenticator.
|
||||
*/
|
||||
Authenticator<LoginResultJson> getTokenAuthenticator();
|
||||
|
||||
/**
|
||||
* This is the authenticator used for session authentication.
|
||||
* @return An authenticator.
|
||||
*/
|
||||
Authenticator<ComboTokenResJson> getSessionKeyAuthenticator();
|
||||
|
||||
/**
|
||||
* This is the authenticator used for handling external authentication requests.
|
||||
* @return An authenticator.
|
||||
*/
|
||||
ExternalAuthenticator getExternalAuthenticator();
|
||||
|
||||
/**
|
||||
* This is the authenticator used for handling OAuth authentication requests.
|
||||
* @return An authenticator.
|
||||
*/
|
||||
OAuthAuthenticator getOAuthAuthenticator();
|
||||
|
||||
/**
|
||||
* A data container that holds relevant data for authenticating a client.
|
||||
*/
|
||||
@Builder @AllArgsConstructor @Getter
|
||||
class AuthenticationRequest {
|
||||
private final Request request;
|
||||
@Nullable private final Response response;
|
||||
|
||||
@Nullable private final LoginAccountRequestJson passwordRequest;
|
||||
@Nullable private final LoginTokenRequestJson tokenRequest;
|
||||
@Nullable private final ComboTokenReqJson sessionKeyRequest;
|
||||
@Nullable private final ComboTokenReqJson.LoginTokenData sessionKeyData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an authentication request from a {@link LoginAccountRequestJson} object.
|
||||
* @param request The Express request.
|
||||
* @param jsonData The JSON data.
|
||||
* @return An authentication request.
|
||||
*/
|
||||
static AuthenticationRequest fromPasswordRequest(Request request, LoginAccountRequestJson jsonData) {
|
||||
return AuthenticationRequest.builder()
|
||||
.request(request)
|
||||
.passwordRequest(jsonData)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an authentication request from a {@link LoginTokenRequestJson} object.
|
||||
* @param request The Express request.
|
||||
* @param jsonData The JSON data.
|
||||
* @return An authentication request.
|
||||
*/
|
||||
static AuthenticationRequest fromTokenRequest(Request request, LoginTokenRequestJson jsonData) {
|
||||
return AuthenticationRequest.builder()
|
||||
.request(request)
|
||||
.tokenRequest(jsonData)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an authentication request from a {@link ComboTokenReqJson} object.
|
||||
* @param request The Express request.
|
||||
* @param jsonData The JSON data.
|
||||
* @return An authentication request.
|
||||
*/
|
||||
static AuthenticationRequest fromComboTokenRequest(Request request, ComboTokenReqJson jsonData,
|
||||
ComboTokenReqJson.LoginTokenData tokenData) {
|
||||
return AuthenticationRequest.builder()
|
||||
.request(request)
|
||||
.sessionKeyRequest(jsonData)
|
||||
.sessionKeyData(tokenData)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an authentication request from a {@link Response} object.
|
||||
* @param request The Express request.
|
||||
* @param response the Express response.
|
||||
* @return An authentication request.
|
||||
*/
|
||||
static AuthenticationRequest fromExternalRequest(Request request, Response response) {
|
||||
return AuthenticationRequest.builder().request(request)
|
||||
.response(response).build();
|
||||
}
|
||||
}
|
17
src/main/java/emu/grasscutter/auth/Authenticator.java
Normal file
17
src/main/java/emu/grasscutter/auth/Authenticator.java
Normal file
@ -0,0 +1,17 @@
|
||||
package emu.grasscutter.auth;
|
||||
|
||||
import emu.grasscutter.server.http.objects.*;
|
||||
|
||||
/**
|
||||
* Handles username/password authentication from the client.
|
||||
* @param <T> The response object type. Should be {@link LoginResultJson} or {@link ComboTokenResJson}
|
||||
*/
|
||||
public interface Authenticator<T> {
|
||||
|
||||
/**
|
||||
* Attempt to authenticate the client with the provided credentials.
|
||||
* @param request The authentication request wrapped in a {@link AuthenticationSystem.AuthenticationRequest} object.
|
||||
* @return The result of the login in an object.
|
||||
*/
|
||||
T authenticate(AuthenticationSystem.AuthenticationRequest request);
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package emu.grasscutter.auth;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.auth.DefaultAuthenticators.*;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.server.http.objects.ComboTokenResJson;
|
||||
import emu.grasscutter.server.http.objects.LoginResultJson;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
/**
|
||||
* The default Grasscutter authentication implementation.
|
||||
* Allows all users to access any account.
|
||||
*/
|
||||
public final class DefaultAuthentication implements AuthenticationSystem {
|
||||
private final Authenticator<LoginResultJson> passwordAuthenticator = new PasswordAuthenticator();
|
||||
private final Authenticator<LoginResultJson> tokenAuthenticator = new TokenAuthenticator();
|
||||
private final Authenticator<ComboTokenResJson> sessionKeyAuthenticator = new SessionKeyAuthenticator();
|
||||
private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication();
|
||||
private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication();
|
||||
|
||||
@Override
|
||||
public void createAccount(String username, String password) {
|
||||
// Unhandled. The default authenticator doesn't store passwords.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPassword(String username) {
|
||||
// Unhandled. The default authenticator doesn't store passwords.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verifyUser(String details) {
|
||||
Grasscutter.getLogger().info(translate("dispatch.authentication.default_unable_to_verify"));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<LoginResultJson> getPasswordAuthenticator() {
|
||||
return this.passwordAuthenticator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<LoginResultJson> getTokenAuthenticator() {
|
||||
return this.tokenAuthenticator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<ComboTokenResJson> getSessionKeyAuthenticator() {
|
||||
return this.sessionKeyAuthenticator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalAuthenticator getExternalAuthenticator() {
|
||||
return this.externalAuthenticator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuthAuthenticator getOAuthAuthenticator() {
|
||||
return this.oAuthAuthenticator;
|
||||
}
|
||||
}
|
228
src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java
Normal file
228
src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java
Normal file
@ -0,0 +1,228 @@
|
||||
package emu.grasscutter.auth;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.server.http.objects.*;
|
||||
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
/**
|
||||
* A class containing default authenticators.
|
||||
*/
|
||||
public final class DefaultAuthenticators {
|
||||
|
||||
/**
|
||||
* Handles the authentication request from the username and password form.
|
||||
*/
|
||||
public static class PasswordAuthenticator implements Authenticator<LoginResultJson> {
|
||||
@Override public LoginResultJson authenticate(AuthenticationRequest request) {
|
||||
var response = new LoginResultJson();
|
||||
|
||||
var requestData = request.getPasswordRequest();
|
||||
assert requestData != null; // This should never be null.
|
||||
int playerCount = Grasscutter.getGameServer().getPlayers().size();
|
||||
|
||||
boolean successfulLogin = false;
|
||||
String address = request.getRequest().ip();
|
||||
String responseMessage = translate("messages.dispatch.account.username_error");
|
||||
String loggerMessage = "";
|
||||
|
||||
// Get account from database.
|
||||
Account account = DatabaseHelper.getAccountByName(requestData.account);
|
||||
if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) {
|
||||
// Check if account exists.
|
||||
if(account == null && ACCOUNT.autoCreate) {
|
||||
// This account has been created AUTOMATICALLY. There will be no permissions added.
|
||||
account = DatabaseHelper.createAccountWithUid(requestData.account, 0);
|
||||
|
||||
// Check if the account was created successfully.
|
||||
if(account == null) {
|
||||
responseMessage = translate("messages.dispatch.account.username_create_error");
|
||||
Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_error", address));
|
||||
} else {
|
||||
// Continue with login.
|
||||
successfulLogin = true;
|
||||
|
||||
// Log the creation.
|
||||
Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid));
|
||||
}
|
||||
} else if(account != null)
|
||||
successfulLogin = true;
|
||||
else
|
||||
loggerMessage = translate("messages.dispatch.account.account_login_exist_error", address);
|
||||
|
||||
} else {
|
||||
responseMessage = translate("messages.dispatch.account.server_max_player_limit");
|
||||
loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address);
|
||||
}
|
||||
|
||||
|
||||
// Set response data.
|
||||
if(successfulLogin) {
|
||||
response.message = "OK";
|
||||
response.data.account.uid = account.getId();
|
||||
response.data.account.token = account.generateSessionKey();
|
||||
response.data.account.email = account.getEmail();
|
||||
|
||||
loggerMessage = translate("messages.dispatch.account.login_success", address, account.getId());
|
||||
} else {
|
||||
response.retcode = -201;
|
||||
response.message = responseMessage;
|
||||
|
||||
}
|
||||
Grasscutter.getLogger().info(loggerMessage);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the authentication request from the game when using a registry token.
|
||||
*/
|
||||
public static class TokenAuthenticator implements Authenticator<LoginResultJson> {
|
||||
@Override public LoginResultJson authenticate(AuthenticationRequest request) {
|
||||
var response = new LoginResultJson();
|
||||
|
||||
var requestData = request.getTokenRequest();
|
||||
assert requestData != null;
|
||||
|
||||
boolean successfulLogin;
|
||||
String address = request.getRequest().ip();
|
||||
String loggerMessage;
|
||||
int playerCount = Grasscutter.getGameServer().getPlayers().size();
|
||||
|
||||
// Log the attempt.
|
||||
Grasscutter.getLogger().info(translate("messages.dispatch.account.login_token_attempt", address));
|
||||
|
||||
if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) {
|
||||
|
||||
// Get account from database.
|
||||
Account account = DatabaseHelper.getAccountById(requestData.uid);
|
||||
|
||||
// Check if account exists/token is valid.
|
||||
successfulLogin = account != null && account.getSessionKey().equals(requestData.token);
|
||||
|
||||
// Set response data.
|
||||
if(successfulLogin) {
|
||||
response.message = "OK";
|
||||
response.data.account.uid = account.getId();
|
||||
response.data.account.token = account.getSessionKey();
|
||||
response.data.account.email = account.getEmail();
|
||||
|
||||
// Log the login.
|
||||
loggerMessage = translate("messages.dispatch.account.login_token_success", address, requestData.uid);
|
||||
} else {
|
||||
response.retcode = -201;
|
||||
response.message = translate("messages.dispatch.account.account_cache_error");
|
||||
|
||||
// Log the failure.
|
||||
loggerMessage = translate("messages.dispatch.account.login_token_error", address);
|
||||
}
|
||||
|
||||
} else {
|
||||
response.retcode = -201;
|
||||
response.message = translate("messages.dispatch.account.server_max_player_limit");
|
||||
|
||||
loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address);
|
||||
}
|
||||
|
||||
Grasscutter.getLogger().info(loggerMessage);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the authentication request from the game when using a combo token/session key.
|
||||
*/
|
||||
public static class SessionKeyAuthenticator implements Authenticator<ComboTokenResJson> {
|
||||
@Override public ComboTokenResJson authenticate(AuthenticationRequest request) {
|
||||
var response = new ComboTokenResJson();
|
||||
|
||||
var requestData = request.getSessionKeyRequest();
|
||||
var loginData = request.getSessionKeyData();
|
||||
assert requestData != null; assert loginData != null;
|
||||
|
||||
boolean successfulLogin;
|
||||
String address = request.getRequest().ip();
|
||||
String loggerMessage;
|
||||
int playerCount = Grasscutter.getGameServer().getPlayers().size();
|
||||
|
||||
if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) {
|
||||
// Get account from database.
|
||||
Account account = DatabaseHelper.getAccountById(loginData.uid);
|
||||
|
||||
// Check if account exists/token is valid.
|
||||
successfulLogin = account != null && account.getSessionKey().equals(loginData.token);
|
||||
|
||||
// Set response data.
|
||||
if(successfulLogin) {
|
||||
response.message = "OK";
|
||||
response.data.open_id = account.getId();
|
||||
response.data.combo_id = "157795300";
|
||||
response.data.combo_token = account.generateLoginToken();
|
||||
|
||||
// Log the login.
|
||||
loggerMessage = translate("messages.dispatch.account.combo_token_success", address);
|
||||
|
||||
} else {
|
||||
response.retcode = -201;
|
||||
response.message = translate("messages.dispatch.account.session_key_error");
|
||||
|
||||
// Log the failure.
|
||||
loggerMessage = translate("messages.dispatch.account.combo_token_error", address);
|
||||
}
|
||||
} else {
|
||||
response.retcode = -201;
|
||||
response.message = translate("messages.dispatch.account.server_max_player_limit");
|
||||
|
||||
loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address);
|
||||
}
|
||||
|
||||
Grasscutter.getLogger().info(loggerMessage);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles authentication requests from external sources.
|
||||
*/
|
||||
public static class ExternalAuthentication implements ExternalAuthenticator {
|
||||
@Override public void handleLogin(AuthenticationRequest request) {
|
||||
assert request.getResponse() != null;
|
||||
request.getResponse().send("Authentication is not available with the default authentication method.");
|
||||
}
|
||||
|
||||
@Override public void handleAccountCreation(AuthenticationRequest request) {
|
||||
assert request.getResponse() != null;
|
||||
request.getResponse().send("Authentication is not available with the default authentication method.");
|
||||
}
|
||||
|
||||
@Override public void handlePasswordReset(AuthenticationRequest request) {
|
||||
assert request.getResponse() != null;
|
||||
request.getResponse().send("Authentication is not available with the default authentication method.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles authentication requests from OAuth sources.
|
||||
*/
|
||||
public static class OAuthAuthentication implements OAuthAuthenticator {
|
||||
@Override public void handleLogin(AuthenticationRequest request) {
|
||||
assert request.getResponse() != null;
|
||||
request.getResponse().send("Authentication is not available with the default authentication method.");
|
||||
}
|
||||
|
||||
@Override public void handleRedirection(AuthenticationRequest request, ClientType type) {
|
||||
assert request.getResponse() != null;
|
||||
request.getResponse().send("Authentication is not available with the default authentication method.");
|
||||
}
|
||||
|
||||
@Override public void handleTokenProcess(AuthenticationRequest request) {
|
||||
assert request.getResponse() != null;
|
||||
request.getResponse().send("Authentication is not available with the default authentication method.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package emu.grasscutter.auth;
|
||||
|
||||
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
|
||||
|
||||
/**
|
||||
* Handles authentication via external routes.
|
||||
*/
|
||||
public interface ExternalAuthenticator {
|
||||
|
||||
/**
|
||||
* Called when an external login request is made.
|
||||
* @param request The authentication request.
|
||||
*/
|
||||
void handleLogin(AuthenticationRequest request);
|
||||
|
||||
/**
|
||||
* Called when an external account creation request is made.
|
||||
* @param request The authentication request.
|
||||
*
|
||||
* For developers: Use {@link AuthenticationRequest#getRequest()} to get the request body.
|
||||
* Use {@link AuthenticationRequest#getResponse()} to get the response body.
|
||||
*/
|
||||
void handleAccountCreation(AuthenticationRequest request);
|
||||
|
||||
/**
|
||||
* Called when an external password reset request is made.
|
||||
* @param request The authentication request.
|
||||
*
|
||||
* For developers: Use {@link AuthenticationRequest#getRequest()} to get the request body.
|
||||
* Use {@link AuthenticationRequest#getResponse()} to get the response body.
|
||||
*/
|
||||
void handlePasswordReset(AuthenticationRequest request);
|
||||
}
|
35
src/main/java/emu/grasscutter/auth/OAuthAuthenticator.java
Normal file
35
src/main/java/emu/grasscutter/auth/OAuthAuthenticator.java
Normal file
@ -0,0 +1,35 @@
|
||||
package emu.grasscutter.auth;
|
||||
|
||||
import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest;
|
||||
|
||||
/**
|
||||
* Handles authentication via OAuth routes.
|
||||
*/
|
||||
public interface OAuthAuthenticator {
|
||||
|
||||
/**
|
||||
* Called when an OAuth login request is made.
|
||||
* @param request The authentication request.
|
||||
*/
|
||||
void handleLogin(AuthenticationRequest request);
|
||||
|
||||
/**
|
||||
* Called when a client requests to redirect to login page.
|
||||
* @param request The authentication request.
|
||||
*/
|
||||
void handleRedirection(AuthenticationRequest request, ClientType clientType);
|
||||
|
||||
/**
|
||||
* Called when an OAuth login requests callback.
|
||||
* @param request The authentication request.
|
||||
*/
|
||||
void handleTokenProcess(AuthenticationRequest request);
|
||||
|
||||
/**
|
||||
* The type of the client.
|
||||
* Used for handling redirection.
|
||||
*/
|
||||
enum ClientType {
|
||||
DESKTOP, MOBILE
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ public @interface Command {
|
||||
|
||||
String usage() default "No usage specified";
|
||||
|
||||
String description() default "No description specified";
|
||||
String description() default "commands.generic.no_description_specified";
|
||||
|
||||
String[] aliases() default {};
|
||||
|
||||
@ -17,5 +17,13 @@ public @interface Command {
|
||||
|
||||
String permissionTargeted() default "";
|
||||
|
||||
public enum TargetRequirement {
|
||||
NONE, // targetPlayer is not required
|
||||
OFFLINE, // targetPlayer must be offline
|
||||
PLAYER, // targetPlayer can be online or offline
|
||||
ONLINE // targetPlayer must be online
|
||||
}
|
||||
TargetRequirement targetRequirement() default TargetRequirement.ONLINE;
|
||||
|
||||
boolean threading() default false;
|
||||
}
|
||||
|
@ -2,10 +2,14 @@ package emu.grasscutter.command;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.server.event.game.CommandResponseEvent;
|
||||
import emu.grasscutter.server.event.types.ServerEvent;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CommandHandler {
|
||||
|
||||
/**
|
||||
* Send a message to the target.
|
||||
*
|
||||
@ -18,6 +22,12 @@ public interface CommandHandler {
|
||||
} else {
|
||||
player.dropMessage(message);
|
||||
}
|
||||
CommandResponseEvent event = new CommandResponseEvent(ServerEvent.Type.GAME,player, message);
|
||||
event.call();
|
||||
}
|
||||
|
||||
static void sendTranslatedMessage(Player player, String messageKey, Object... args) {
|
||||
sendMessage(player, translate(player, messageKey, args));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,8 +8,6 @@ import org.reflections.Reflections;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@SuppressWarnings({"UnusedReturnValue", "unused"})
|
||||
public final class CommandMap {
|
||||
private final Map<String, CommandHandler> commands = new HashMap<>();
|
||||
@ -117,7 +115,7 @@ public final class CommandMap {
|
||||
public void invoke(Player player, Player targetPlayer, String rawMessage) {
|
||||
rawMessage = rawMessage.trim();
|
||||
if (rawMessage.length() == 0) {
|
||||
CommandHandler.sendMessage(player, translate("commands.generic.not_specified"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.generic.not_specified");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -144,19 +142,20 @@ public final class CommandMap {
|
||||
if (targetUidStr != null) {
|
||||
if (targetUidStr.equals("")) { // Clears the default targetPlayer.
|
||||
targetPlayerIds.remove(playerId);
|
||||
CommandHandler.sendMessage(player, translate("commands.execution.clear_target"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.clear_target");
|
||||
} else { // Sets default targetPlayer to the UID provided.
|
||||
try {
|
||||
int uid = Integer.parseInt(targetUidStr);
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid);
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(player, translate("commands.generic.execution.player_exist_offline_error"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
} else {
|
||||
targetPlayerIds.put(playerId, uid);
|
||||
CommandHandler.sendMessage(player, translate("commands.execution.set_target", targetUidStr));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", targetUidStr);
|
||||
CommandHandler.sendTranslatedMessage(player, targetPlayer.isOnline()? "commands.execution.set_target_online" : "commands.execution.set_target_offline", targetUidStr);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
CommandHandler.sendMessage(player, translate("commands.execution.uid_error"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -165,7 +164,7 @@ public final class CommandMap {
|
||||
// Get command handler.
|
||||
CommandHandler handler = this.commands.get(label);
|
||||
if (handler == null) {
|
||||
CommandHandler.sendMessage(player, translate("commands.generic.unknown_command", label));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.generic.unknown_command", label);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -176,14 +175,14 @@ public final class CommandMap {
|
||||
arg = args.remove(i).substring(1);
|
||||
try {
|
||||
int uid = Integer.parseInt(arg);
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid);
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(player, translate("commands.generic.execution.player_exist_offline_error"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
} catch (NumberFormatException e) {
|
||||
CommandHandler.sendMessage(player, translate("commands.execution.uid_error"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -192,9 +191,9 @@ public final class CommandMap {
|
||||
// If there's still no targetPlayer at this point, use previously-set target
|
||||
if (targetPlayer == null) {
|
||||
if (targetPlayerIds.containsKey(playerId)) {
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(targetPlayerIds.get(playerId)); // We check every time in case the target goes offline after being targeted
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(targetPlayerIds.get(playerId), true); // We check every time in case the target is deleted after being targeted
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(player, translate("commands.generic.execution.player_exist_offline_error"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@ -210,12 +209,29 @@ public final class CommandMap {
|
||||
Account account = player.getAccount();
|
||||
if (player != targetPlayer) { // Additional permission required for targeting another player
|
||||
if (!permissionNodeTargeted.isEmpty() && !account.hasPermission(permissionNodeTargeted)) {
|
||||
CommandHandler.sendMessage(player, translate("commands.generic.permission_error"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.generic.permission_error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!permissionNode.isEmpty() && !account.hasPermission(permissionNode)) {
|
||||
CommandHandler.sendMessage(player, translate("commands.generic.permission_error"));
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.generic.permission_error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if command has unfulfilled constraints on targetPlayer
|
||||
Command.TargetRequirement targetRequirement = this.annotations.get(label).targetRequirement();
|
||||
if (targetRequirement != Command.TargetRequirement.NONE) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.need_target");
|
||||
return;
|
||||
}
|
||||
if ((targetRequirement == Command.TargetRequirement.ONLINE) && !targetPlayer.isOnline()) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.need_target_online");
|
||||
return;
|
||||
}
|
||||
if ((targetRequirement == Command.TargetRequirement.OFFLINE) && targetPlayer.isOnline()) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.need_target_offline");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,28 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "account", usage = "account <create|delete> <username> [uid]", description = "Modify user accounts")
|
||||
@Command(label = "account", usage = "account <create|delete> <username> [uid]", description = "commands.account.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class AccountCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (sender != null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.console_execute_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.console_execute_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() < 2) {
|
||||
CommandHandler.sendMessage(null, translate("commands.account.command_usage"));
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.account.command_usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -29,7 +31,7 @@ public final class AccountCommand implements CommandHandler {
|
||||
|
||||
switch (action) {
|
||||
default:
|
||||
CommandHandler.sendMessage(null, translate("commands.account.command_usage"));
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.account.command_usage"));
|
||||
return;
|
||||
case "create":
|
||||
int uid = 0;
|
||||
@ -37,28 +39,41 @@ public final class AccountCommand implements CommandHandler {
|
||||
try {
|
||||
uid = Integer.parseInt(args.get(2));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(null, translate("commands.account.invalid"));
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.account.invalid"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithId(username, uid);
|
||||
emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithUid(username, uid);
|
||||
if (account == null) {
|
||||
CommandHandler.sendMessage(null, translate("commands.account.exists"));
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.account.exists"));
|
||||
return;
|
||||
} else {
|
||||
account.addPermission("*");
|
||||
account.save(); // Save account to database.
|
||||
|
||||
CommandHandler.sendMessage(null, translate("commands.account.create", Integer.toString(account.getPlayerUid())));
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.account.create", Integer.toString(account.getReservedPlayerUid())));
|
||||
}
|
||||
return;
|
||||
case "delete":
|
||||
if (DatabaseHelper.deleteAccount(username)) {
|
||||
CommandHandler.sendMessage(null, translate("commands.account.delete"));
|
||||
} else {
|
||||
CommandHandler.sendMessage(null, translate("commands.account.no_account"));
|
||||
// Get the account we want to delete.
|
||||
Account toDelete = DatabaseHelper.getAccountByName(username);
|
||||
|
||||
if (toDelete == null) {
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.account.no_account"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the player for the account.
|
||||
// If that player is currently online, we kick them before proceeding with the deletion.
|
||||
Player player = Grasscutter.getGameServer().getPlayerByAccountId(toDelete.getId());
|
||||
if (player != null) {
|
||||
player.getSession().close();
|
||||
}
|
||||
|
||||
// Finally, we do the actual deletion.
|
||||
DatabaseHelper.deleteAccount(toDelete);
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.account.delete"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,13 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "broadcast", usage = "broadcast <message>",
|
||||
description = "Sends a message to all the players", aliases = {"b"}, permission = "server.broadcast")
|
||||
@Command(label = "broadcast", usage = "broadcast <message>", aliases = {"b"}, permission = "server.broadcast", description = "commands.broadcast.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class BroadcastCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.broadcast.command_usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.command_usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -26,6 +25,6 @@ public final class BroadcastCommand implements CommandHandler {
|
||||
CommandHandler.sendMessage(p, message);
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate("commands.broadcast.message_sent"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.message_sent"));
|
||||
}
|
||||
}
|
||||
|
@ -8,36 +8,32 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "changescene", usage = "changescene <scene id>",
|
||||
description = "Changes your scene", aliases = {"scene"}, permission = "player.changescene")
|
||||
@Command(label = "changescene", usage = "changescene <sceneId>", aliases = {"scene"}, permission = "player.changescene", permissionTargeted = "player.changescene.others", description = "commands.changescene.description")
|
||||
public final class ChangeSceneCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() != 1) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.changescene.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int sceneId = Integer.parseInt(args.get(0));
|
||||
if (sceneId == targetPlayer.getSceneId()) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.changescene.already_in_scene"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.already_in_scene"));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, targetPlayer.getPos());
|
||||
CommandHandler.sendMessage(sender, translate("commands.changescene.result", Integer.toString(sceneId)));
|
||||
|
||||
if (!result) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.changescene.exists_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.exists_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.success", Integer.toString(sceneId)));
|
||||
} catch (Exception e) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,19 +13,15 @@ import java.util.List;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "clear", usage = "clear <all|wp|art|mat>", //Merged /clearartifacts and /clearweapons to /clear <args> [uid]
|
||||
description = "Deletes unequipped unlocked items, including yellow rarity ones from your inventory",
|
||||
aliases = {"clear"}, permission = "player.clearinv")
|
||||
description = "commands.clear.description",
|
||||
aliases = {"clear"}, permission = "player.clearinv", permissionTargeted = "player.clearinv.others")
|
||||
|
||||
public final class ClearCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.command_usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.command_usage"));
|
||||
return;
|
||||
}
|
||||
Inventory playerInventory = targetPlayer.getInventory();
|
||||
@ -37,7 +33,7 @@ public final class ClearCommand implements CommandHandler {
|
||||
.filter(item -> item.getItemType() == ItemType.ITEM_WEAPON)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.toList();
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.weapons", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.weapons", targetPlayer.getNickname()));
|
||||
}
|
||||
case "art" -> {
|
||||
toDelete = playerInventory.getItems().values().stream()
|
||||
@ -45,7 +41,7 @@ public final class ClearCommand implements CommandHandler {
|
||||
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.toList();
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.artifacts", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.artifacts", targetPlayer.getNickname()));
|
||||
}
|
||||
case "mat" -> {
|
||||
toDelete = playerInventory.getItems().values().stream()
|
||||
@ -53,7 +49,7 @@ public final class ClearCommand implements CommandHandler {
|
||||
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.toList();
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.materials", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.materials", targetPlayer.getNickname()));
|
||||
}
|
||||
case "all" -> {
|
||||
toDelete = playerInventory.getItems().values().stream()
|
||||
@ -61,7 +57,7 @@ public final class ClearCommand implements CommandHandler {
|
||||
.filter(item1 -> item1.getLevel() == 1 && item1.getExp() == 0)
|
||||
.filter(item1 -> !item1.isLocked() && !item1.isEquipped())
|
||||
.toList();
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.artifacts", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.artifacts", targetPlayer.getNickname()));
|
||||
playerInventory.removeItems(toDelete);
|
||||
|
||||
toDelete = playerInventory.getItems().values().stream()
|
||||
@ -69,7 +65,7 @@ public final class ClearCommand implements CommandHandler {
|
||||
.filter(item2 -> !item2.isLocked() && !item2.isEquipped())
|
||||
.toList();
|
||||
playerInventory.removeItems(toDelete);
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.materials", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.materials", targetPlayer.getNickname()));
|
||||
|
||||
toDelete = playerInventory.getItems().values().stream()
|
||||
.filter(item3 -> item3.getItemType() == ItemType.ITEM_WEAPON)
|
||||
@ -77,28 +73,28 @@ public final class ClearCommand implements CommandHandler {
|
||||
.filter(item3 -> !item3.isLocked() && !item3.isEquipped())
|
||||
.toList();
|
||||
playerInventory.removeItems(toDelete);
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.weapons", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.weapons", targetPlayer.getNickname()));
|
||||
|
||||
toDelete = playerInventory.getItems().values().stream()
|
||||
.filter(item4 -> item4.getItemType() == ItemType.ITEM_FURNITURE)
|
||||
.filter(item4 -> !item4.isLocked() && !item4.isEquipped())
|
||||
.toList();
|
||||
playerInventory.removeItems(toDelete);
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.furniture", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.furniture", targetPlayer.getNickname()));
|
||||
|
||||
toDelete = playerInventory.getItems().values().stream()
|
||||
.filter(item5 -> item5.getItemType() == ItemType.ITEM_DISPLAY)
|
||||
.filter(item5 -> !item5.isLocked() && !item5.isEquipped())
|
||||
.toList();
|
||||
playerInventory.removeItems(toDelete);
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.displays", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.displays", targetPlayer.getNickname()));
|
||||
|
||||
toDelete = playerInventory.getItems().values().stream()
|
||||
.filter(item6 -> item6.getItemType() == ItemType.ITEM_VIRTUAL)
|
||||
.filter(item6 -> !item6.isLocked() && !item6.isEquipped())
|
||||
.toList();
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.virtuals", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate("commands.clear.everything", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.virtuals", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.clear.everything", targetPlayer.getNickname()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,20 +9,15 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "coop", usage = "coop [host UID]",
|
||||
description = "Forces someone to join the world of others", permission = "server.coop")
|
||||
@Command(label = "coop", usage = "coop [host uid]", permission = "server.coop", permissionTargeted = "server.coop.others", description = "commands.coop.description")
|
||||
public final class CoopCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
Player host = sender;
|
||||
switch (args.size()) {
|
||||
case 0: // Summon target to self
|
||||
CommandHandler.sendMessage(sender, translate("commands.coop.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.coop.usage"));
|
||||
if (sender == null) // Console doesn't have a self to summon to
|
||||
return;
|
||||
break;
|
||||
@ -31,16 +26,16 @@ public final class CoopCommand implements CommandHandler {
|
||||
int hostId = Integer.parseInt(args.get(0));
|
||||
host = Grasscutter.getGameServer().getPlayerByUid(hostId);
|
||||
if (host == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.player_offline_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.player_offline_error"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.uid_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.uid_error"));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate("commands.coop.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.coop.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -50,6 +45,6 @@ public final class CoopCommand implements CommandHandler {
|
||||
}
|
||||
host.getServer().getMultiplayerManager().applyEnterMp(targetPlayer, host.getUid());
|
||||
targetPlayer.getServer().getMultiplayerManager().applyEnterMpReply(host, targetPlayer.getUid(), true);
|
||||
CommandHandler.sendMessage(sender, translate("commands.coop.success", targetPlayer.getNickname(), host.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.coop.success", targetPlayer.getNickname(), host.getNickname()));
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.entity.EntityItem;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.utils.Position;
|
||||
@ -13,17 +13,11 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "drop", usage = "drop <itemId|itemName> [amount]",
|
||||
description = "Drops an item near you", aliases = {"d", "dropitem"}, permission = "server.drop")
|
||||
@Command(label = "drop", usage = "drop <itemId|itemName> [amount]", aliases = {"d", "dropitem"}, permission = "server.drop", permissionTargeted = "server.drop.others", description = "commands.drop.description")
|
||||
public final class DropCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(null, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
int item = 0;
|
||||
int amount = 1;
|
||||
|
||||
@ -32,25 +26,25 @@ public final class DropCommand implements CommandHandler {
|
||||
try {
|
||||
amount = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
|
||||
return;
|
||||
} // Slightly cheeky here: no break, so it falls through to initialize the first argument too
|
||||
case 1:
|
||||
try {
|
||||
item = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate("commands.drop.command_usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.drop.command_usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
ItemData itemData = GameData.getItemDataMap().get(item);
|
||||
if (itemData == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
return;
|
||||
}
|
||||
if (itemData.isEquip()) {
|
||||
@ -64,6 +58,6 @@ public final class DropCommand implements CommandHandler {
|
||||
EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, targetPlayer.getPos().clone().addY(3f), amount);
|
||||
targetPlayer.getScene().addEntity(entity);
|
||||
}
|
||||
CommandHandler.sendMessage(sender, translate("commands.drop.success", Integer.toString(amount), Integer.toString(item)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.drop.success", Integer.toString(amount), Integer.toString(item)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,36 +8,31 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "enterdungeon", usage = "enterdungeon <dungeon id>",
|
||||
description = "Enter a dungeon", aliases = {"dungeon"}, permission = "player.enterdungeon")
|
||||
@Command(label = "enterdungeon", usage = "enterdungeon <dungeonId>", aliases = {"dungeon"}, permission = "player.enterdungeon", permissionTargeted = "player.enterdungeon.others", description = "commands.enter_dungeon.description")
|
||||
public final class EnterDungeonCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(null, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int dungeonId = Integer.parseInt(args.get(0));
|
||||
if (dungeonId == targetPlayer.getSceneId()) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.in_dungeon_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.in_dungeon_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean result = targetPlayer.getServer().getDungeonManager().enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId);
|
||||
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.changed", dungeonId));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.changed", dungeonId));
|
||||
|
||||
if (!result) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.not_found_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.not_found_error"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.enter_dungeon.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.usage"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.AvatarData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.data.excels.AvatarData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
@ -15,16 +15,11 @@ import java.util.*;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "giveall", usage = "giveall [amount]",
|
||||
description = "Gives all items", aliases = {"givea"}, permission = "player.giveall", threading = true)
|
||||
@Command(label = "giveall", usage = "giveall [amount]", aliases = {"givea"}, permission = "player.giveall", permissionTargeted = "player.giveall.others", threading = true, description = "commands.giveAll.description")
|
||||
public final class GiveAllCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
int amount = 99999;
|
||||
|
||||
switch (args.size()) {
|
||||
@ -34,21 +29,21 @@ public final class GiveAllCommand implements CommandHandler {
|
||||
try {
|
||||
amount = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: // invalid
|
||||
CommandHandler.sendMessage(sender, translate("commands.giveAll.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveAll.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.giveAllItems(targetPlayer, amount);
|
||||
CommandHandler.sendMessage(sender, translate("commands.giveAll.success", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(targetPlayer, "commands.giveAll.success", targetPlayer.getNickname()));
|
||||
}
|
||||
|
||||
public void giveAllItems(Player player, int amount) {
|
||||
CommandHandler.sendMessage(player, translate("commands.giveAll.started"));
|
||||
CommandHandler.sendMessage(player, translate(player, "commands.giveAll.started"));
|
||||
|
||||
for (AvatarData avatarData: GameData.getAvatarDataMap().values()) {
|
||||
//Exclude test avatar
|
||||
@ -62,7 +57,8 @@ public final class GiveAllCommand implements CommandHandler {
|
||||
}
|
||||
// This will handle stats and talents
|
||||
avatar.recalcStats();
|
||||
player.addAvatar(avatar);
|
||||
// Don't try to add each avatar to the current team
|
||||
player.addAvatar(avatar, false);
|
||||
}
|
||||
|
||||
//some test items
|
||||
@ -159,7 +155,7 @@ public final class GiveAllCommand implements CommandHandler {
|
||||
private static final Integer[] testItemsIds = new Integer[] {
|
||||
210, 211, 314, 315, 317, 1005, 1007, 1105, 1107, 1201, 1202,10366,
|
||||
101212, 11411, 11506, 11507, 11508, 12505, 12506, 12508, 12509, 13503,
|
||||
13506, 14411, 14503, 14505, 14508, 15411, 15504, 15505, 15506, 15508,
|
||||
13506, 14411, 14503, 14505, 14508, 15504, 15505, 15506,
|
||||
20001, 10002, 10003, 10004, 10005, 10006, 10008,100231,100232,100431,
|
||||
101689,105001,105004, 106000,106001,108000,110000
|
||||
};
|
||||
|
@ -4,53 +4,158 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.inventory.EquipType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import static java.util.Map.entry;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "giveart", usage = "giveart <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]", description = "Gives the player a specified artifact", aliases = {"gart"}, permission = "player.giveart")
|
||||
@Command(label = "giveart", usage = "giveart <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]", aliases = {"gart"}, permission = "player.giveart", permissionTargeted = "player.giveart.others", description = "commands.giveArtifact.description")
|
||||
public final class GiveArtifactCommand implements CommandHandler {
|
||||
private static final Map<String, Map<EquipType, Integer>> mainPropMap = Map.ofEntries(
|
||||
entry("hp", Map.ofEntries(entry(EquipType.EQUIP_BRACER, 14001))),
|
||||
entry("hp%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10980), entry(EquipType.EQUIP_RING, 50980), entry(EquipType.EQUIP_DRESS, 30980))),
|
||||
entry("atk", Map.ofEntries(entry(EquipType.EQUIP_NECKLACE, 12001))),
|
||||
entry("atk%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10990), entry(EquipType.EQUIP_RING, 50990), entry(EquipType.EQUIP_DRESS, 30990))),
|
||||
entry("def%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10970), entry(EquipType.EQUIP_RING, 50970), entry(EquipType.EQUIP_DRESS, 30970))),
|
||||
entry("er", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10960))),
|
||||
entry("em", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10950), entry(EquipType.EQUIP_RING, 50880), entry(EquipType.EQUIP_DRESS, 30930))),
|
||||
entry("hb", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30940))),
|
||||
entry("cdmg", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30950))),
|
||||
entry("cr", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30960))),
|
||||
entry("phys%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50890))),
|
||||
entry("dendro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50900))),
|
||||
entry("geo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50910))),
|
||||
entry("anemo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50920))),
|
||||
entry("hydro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50930))),
|
||||
entry("cryo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50940))),
|
||||
entry("electro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50950))),
|
||||
entry("pyro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50960)))
|
||||
);
|
||||
private static final Map<String, String> appendPropMap = Map.ofEntries(
|
||||
entry("hp", "0102"),
|
||||
entry("hp%", "0103"),
|
||||
entry("atk", "0105"),
|
||||
entry("atk%", "0106"),
|
||||
entry("def", "0108"),
|
||||
entry("def%", "0109"),
|
||||
entry("er", "0123"),
|
||||
entry("em", "0124"),
|
||||
entry("cr", "0120"),
|
||||
entry("cdmg", "0122")
|
||||
);
|
||||
|
||||
private int getAppendPropId(String substatText, ItemData itemData) {
|
||||
int res;
|
||||
|
||||
// If the given substat text is an integer, we just use that
|
||||
// as the append prop ID.
|
||||
try {
|
||||
res = Integer.parseInt(substatText);
|
||||
return res;
|
||||
}
|
||||
catch (NumberFormatException ignores) {
|
||||
// No need to handle this here. We just continue with the
|
||||
// possibility of the argument being a substat string.
|
||||
}
|
||||
|
||||
// If the argument was not an integer, we try to determine
|
||||
// the append prop ID from the given text + artifact information.
|
||||
// A substat string has the format `substat_tier`, with the
|
||||
// `_tier` part being optional.
|
||||
String[] substatArgs = substatText.split("_");
|
||||
String substatType;
|
||||
int substatTier;
|
||||
|
||||
if (substatArgs.length == 1) {
|
||||
substatType = substatArgs[0];
|
||||
substatTier =
|
||||
itemData.getRankLevel() == 1 ? 2
|
||||
: itemData.getRankLevel() == 2 ? 3
|
||||
: 4;
|
||||
}
|
||||
else if (substatArgs.length == 2) {
|
||||
substatType = substatArgs[0];
|
||||
substatTier = Integer.parseInt(substatArgs[1]);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Check if the specified tier is legal for the artifact rarity.
|
||||
if (substatTier < 1 || substatTier > 4) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (itemData.getRankLevel() == 1 && substatTier > 2) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (itemData.getRankLevel() == 2 && substatTier > 3) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Check if the given substat type string is a legal stat.
|
||||
if (!appendPropMap.containsKey(substatType)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Build the append prop ID.
|
||||
return Integer.parseInt(Integer.toString(itemData.getRankLevel()) + appendPropMap.get(substatType) + Integer.toString(substatTier));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (args.size() < 2) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.giveArtifact.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the artifact piece ID from the arguments.
|
||||
int itemId;
|
||||
try {
|
||||
itemId = Integer.parseInt(args.remove(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.giveArtifact.id_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.id_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
ItemData itemData = GameData.getItemDataMap().get(itemId);
|
||||
if (itemData.getItemType() != ItemType.ITEM_RELIQUARY) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.giveArtifact.id_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.id_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the main stat from the arguments.
|
||||
// If the given argument is an integer, we use that.
|
||||
// If not, we check if the argument string is in the main prop map.
|
||||
String mainPropIdString = args.remove(0);
|
||||
int mainPropId;
|
||||
|
||||
try {
|
||||
mainPropId = Integer.parseInt(args.remove(0));
|
||||
mainPropId = Integer.parseInt(mainPropIdString);
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.execution.argument_error"));
|
||||
mainPropId = -1;
|
||||
}
|
||||
|
||||
if (mainPropMap.containsKey(mainPropIdString) && mainPropMap.get(mainPropIdString).containsKey(itemData.getEquipType())) {
|
||||
mainPropId = mainPropMap.get(mainPropIdString).get(itemData.getEquipType());
|
||||
}
|
||||
|
||||
if (mainPropId == -1) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the level from the arguments.
|
||||
int level = 1;
|
||||
try {
|
||||
int last = Integer.parseInt(args.get(args.size()-1));
|
||||
@ -61,9 +166,13 @@ public final class GiveArtifactCommand implements CommandHandler {
|
||||
} catch (NumberFormatException ignored) { // Could be a stat,times string so no need to panic
|
||||
}
|
||||
|
||||
List<Integer> appendPropIdList = new ArrayList<>();
|
||||
// Get substats.
|
||||
ArrayList<Integer> appendPropIdList = new ArrayList<>();
|
||||
try {
|
||||
// Every remaining argument is a substat.
|
||||
args.forEach(it -> {
|
||||
// The substat syntax permits specifying a number of rolls for the given
|
||||
// substat. Split the string into stat and number if that is the case here.
|
||||
String[] arr;
|
||||
int n = 1;
|
||||
if ((arr = it.split(",")).length == 2) {
|
||||
@ -73,13 +182,19 @@ public final class GiveArtifactCommand implements CommandHandler {
|
||||
n = 200;
|
||||
}
|
||||
}
|
||||
appendPropIdList.addAll(Collections.nCopies(n, Integer.parseInt(it)));
|
||||
|
||||
// Determine the substat ID.
|
||||
int appendPropId = getAppendPropId(it, itemData);
|
||||
|
||||
// Add the current substat.
|
||||
appendPropIdList.addAll(Collections.nCopies(n, appendPropId));
|
||||
});
|
||||
} catch (Exception ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Create item for the artifact.
|
||||
GameItem item = new GameItem(itemData);
|
||||
item.setLevel(level);
|
||||
item.setMainPropId(mainPropId);
|
||||
@ -87,7 +202,7 @@ public final class GiveArtifactCommand implements CommandHandler {
|
||||
item.getAppendPropIdList().addAll(appendPropIdList);
|
||||
targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop);
|
||||
|
||||
CommandHandler.sendMessage(sender, translate("commands.giveArtifact.success", Integer.toString(itemId), Integer.toString(targetPlayer.getUid())));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.success", Integer.toString(itemId), Integer.toString(targetPlayer.getUid())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.AvatarData;
|
||||
import emu.grasscutter.data.excels.AvatarData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
@ -12,17 +12,11 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "givechar", usage = "givechar <avatarId> [level]",
|
||||
description = "Gives the player a specified character", aliases = {"givec"}, permission = "player.givechar")
|
||||
@Command(label = "givechar", usage = "givechar <avatarId> [level]", aliases = {"givec"}, permission = "player.givechar", permissionTargeted = "player.givechar.others", description = "commands.giveChar.description")
|
||||
public final class GiveCharCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
int avatarId;
|
||||
int level = 1;
|
||||
|
||||
@ -32,7 +26,7 @@ public final class GiveCharCommand implements CommandHandler {
|
||||
level = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from avatar name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarLevel"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarLevel"));
|
||||
return;
|
||||
} // Cheeky fall-through to parse first argument too
|
||||
case 1:
|
||||
@ -40,33 +34,34 @@ public final class GiveCharCommand implements CommandHandler {
|
||||
avatarId = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from avatar name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarId"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate("commands.giveChar.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveChar.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
|
||||
if (avatarData == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarId"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check level.
|
||||
if (level > 90) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.invalid.avatarLevel"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarLevel"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate ascension level.
|
||||
int ascension;
|
||||
if (level <= 40) {
|
||||
ascension = (int) Math.ceil(level / 20f);
|
||||
ascension = (int) Math.ceil(level / 20f) - 1;
|
||||
} else {
|
||||
ascension = (int) Math.ceil(level / 10f) - 3;
|
||||
ascension = Math.min(ascension, 6);
|
||||
}
|
||||
|
||||
Avatar avatar = new Avatar(avatarId);
|
||||
@ -77,6 +72,6 @@ public final class GiveCharCommand implements CommandHandler {
|
||||
avatar.recalcStats();
|
||||
|
||||
targetPlayer.addAvatar(avatar);
|
||||
CommandHandler.sendMessage(sender, translate("commands.giveChar.given", Integer.toString(avatarId), Integer.toString(level), Integer.toString(targetPlayer.getUid())));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveChar.given", Integer.toString(avatarId), Integer.toString(level), Integer.toString(targetPlayer.getUid())));
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
@ -12,13 +11,13 @@ import emu.grasscutter.game.props.ActionReason;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "give", usage = "give <itemId|itemName> [amount] [level]", description = "Gives an item to you or the specified player", aliases = {
|
||||
"g", "item", "giveitem"}, permission = "player.give")
|
||||
@Command(label = "give", usage = "give <itemId|itemName> [amount] [level]", aliases = {
|
||||
"g", "item", "giveitem"}, permission = "player.give", permissionTargeted = "player.give.others", description = "commands.give.description")
|
||||
public final class GiveCommand implements CommandHandler {
|
||||
Pattern lvlRegex = Pattern.compile("l(?:vl?)?(\\d+)"); // Java is a joke of a proglang that doesn't have raw string literals
|
||||
Pattern refineRegex = Pattern.compile("r(\\d+)");
|
||||
@ -34,10 +33,6 @@ public final class GiveCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
int item;
|
||||
int lvl = 1;
|
||||
int amount = 1;
|
||||
@ -69,21 +64,21 @@ public final class GiveCommand implements CommandHandler {
|
||||
try {
|
||||
refinement = Integer.parseInt(args.get(3));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemRefinement"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemRefinement"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 3: // <itemId|itemName> [amount] [level]
|
||||
try {
|
||||
lvl = Integer.parseInt(args.get(2));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemLevel"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemLevel"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 2: // <itemId|itemName> [amount]
|
||||
try {
|
||||
amount = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 1: // <itemId|itemName>
|
||||
@ -91,28 +86,28 @@ public final class GiveCommand implements CommandHandler {
|
||||
item = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from item name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: // *No args*
|
||||
CommandHandler.sendMessage(sender, translate("commands.give.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
ItemData itemData = GameData.getItemDataMap().get(item);
|
||||
if (itemData == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
return;
|
||||
}
|
||||
if (refinement != 0) {
|
||||
if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (refinement < 1 || refinement > 5) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.give.refinement_must_between_1_and_5"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.refinement_must_between_1_and_5"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate("commands.give.refinement_only_applicable_weapons"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.refinement_only_applicable_weapons"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -120,11 +115,11 @@ public final class GiveCommand implements CommandHandler {
|
||||
this.item(targetPlayer, itemData, amount, lvl, refinement);
|
||||
|
||||
if (!itemData.isEquip()) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.give.given", Integer.toString(amount), Integer.toString(item), Integer.toString(targetPlayer.getUid())));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.given", Integer.toString(amount), Integer.toString(item), Integer.toString(targetPlayer.getUid())));
|
||||
} else if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.give.given_with_level_and_refinement", Integer.toString(item), Integer.toString(lvl), Integer.toString(refinement), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.given_with_level_and_refinement", Integer.toString(item), Integer.toString(lvl), Integer.toString(refinement), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate("commands.give.given_level", Integer.toString(item), Integer.toString(lvl), Integer.toString(amount)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.given_level", Integer.toString(item), Integer.toString(lvl), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
@ -9,17 +8,11 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "godmode", usage = "godmode [on|off|toggle]",
|
||||
description = "Prevents you from taking damage. Defaults to toggle.", permission = "player.godmode")
|
||||
@Command(label = "godmode", usage = "godmode [on|off|toggle]", permission = "player.godmode", permissionTargeted = "player.godmode.others", description = "commands.godmode.description")
|
||||
public final class GodModeCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean enabled = !targetPlayer.inGodmode();
|
||||
if (args.size() == 1) {
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
@ -37,6 +30,6 @@ public final class GodModeCommand implements CommandHandler {
|
||||
}
|
||||
|
||||
targetPlayer.setGodmode(enabled);
|
||||
CommandHandler.sendMessage(sender, translate("commands.godmode.success", (enabled ? translate("commands.status.enabled") : translate("commands.status.disabled")), targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.godmode.success", (enabled ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
|
||||
}
|
||||
}
|
||||
|
@ -11,16 +11,11 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "heal", usage = "heal|h", aliases = {"h"},
|
||||
description = "Heal all characters in your current team.", permission = "player.heal")
|
||||
@Command(label = "heal", usage = "heal|h", aliases = {"h"}, permission = "player.heal", permissionTargeted = "player.heal.others", description = "commands.heal.description")
|
||||
public final class HealCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
targetPlayer.getTeamManager().getActiveTeam().forEach(entity -> {
|
||||
boolean isAlive = entity.isAlive();
|
||||
entity.setFightProperty(
|
||||
@ -32,6 +27,6 @@ public final class HealCommand implements CommandHandler {
|
||||
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
|
||||
}
|
||||
});
|
||||
CommandHandler.sendMessage(sender, translate("commands.heal.success"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.heal.success"));
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,7 @@ import java.util.*;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "help", usage = "help [command]",
|
||||
description = "Sends the help message or shows information about a specified command")
|
||||
@Command(label = "help", usage = "help [command]", description = "commands.help.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class HelpCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
@ -33,16 +32,16 @@ public final class HelpCommand implements CommandHandler {
|
||||
} else {
|
||||
String command = args.get(0);
|
||||
CommandHandler handler = CommandMap.getInstance().getHandler(command);
|
||||
StringBuilder builder = new StringBuilder(player == null ? "\n" + translate("commands.status.help") + " - " : translate("commands.status.help") + " - ").append(command).append(": \n");
|
||||
StringBuilder builder = new StringBuilder(player == null ? "\n" + translate(player, "commands.status.help") + " - " : translate(player, "commands.status.help") + " - ").append(command).append(": \n");
|
||||
if (handler == null) {
|
||||
builder.append(translate("commands.generic.command_exist_error"));
|
||||
builder.append(translate(player, "commands.generic.command_exist_error"));
|
||||
} else {
|
||||
Command annotation = handler.getClass().getAnnotation(Command.class);
|
||||
|
||||
builder.append(" ").append(annotation.description()).append("\n");
|
||||
builder.append(translate("commands.help.usage")).append(annotation.usage());
|
||||
builder.append(" ").append(translate(player, annotation.description())).append("\n");
|
||||
builder.append(translate(player, "commands.help.usage")).append(annotation.usage());
|
||||
if (annotation.aliases().length >= 1) {
|
||||
builder.append("\n").append(translate("commands.help.aliases"));
|
||||
builder.append("\n").append(translate(player, "commands.help.aliases"));
|
||||
for (String alias : annotation.aliases()) {
|
||||
builder.append(alias).append(" ");
|
||||
}
|
||||
@ -58,13 +57,13 @@ public final class HelpCommand implements CommandHandler {
|
||||
|
||||
void SendAllHelpMessage(Player player, List<Command> annotations) {
|
||||
if (player == null) {
|
||||
StringBuilder builder = new StringBuilder("\n" + translate("commands.help.available_commands") + "\n");
|
||||
StringBuilder builder = new StringBuilder("\n" + translate(player, "commands.help.available_commands") + "\n");
|
||||
annotations.forEach(annotation -> {
|
||||
builder.append(annotation.label()).append("\n");
|
||||
builder.append(" ").append(annotation.description()).append("\n");
|
||||
builder.append(translate("commands.help.usage")).append(annotation.usage());
|
||||
builder.append(" ").append(translate(player, annotation.description())).append("\n");
|
||||
builder.append(translate(player, "commands.help.usage")).append(annotation.usage());
|
||||
if (annotation.aliases().length >= 1) {
|
||||
builder.append("\n").append(translate("commands.help.aliases"));
|
||||
builder.append("\n").append(translate(player, "commands.help.aliases"));
|
||||
for (String alias : annotation.aliases()) {
|
||||
builder.append(alias).append(" ");
|
||||
}
|
||||
@ -75,13 +74,13 @@ public final class HelpCommand implements CommandHandler {
|
||||
|
||||
CommandHandler.sendMessage(null, builder.toString());
|
||||
} else {
|
||||
CommandHandler.sendMessage(player, translate("commands.help.available_commands"));
|
||||
CommandHandler.sendMessage(player, translate(player, "commands.help.available_commands"));
|
||||
annotations.forEach(annotation -> {
|
||||
StringBuilder builder = new StringBuilder(annotation.label()).append("\n");
|
||||
builder.append(" ").append(annotation.description()).append("\n");
|
||||
builder.append(translate("commands.help.usage")).append(annotation.usage());
|
||||
builder.append(" ").append(translate(player, annotation.description())).append("\n");
|
||||
builder.append(translate(player, "commands.help.usage")).append(annotation.usage());
|
||||
if (annotation.aliases().length >= 1) {
|
||||
builder.append("\n").append(translate("commands.help.aliases"));
|
||||
builder.append("\n").append(translate(player, "commands.help.aliases"));
|
||||
for (String alias : annotation.aliases()) {
|
||||
builder.append(alias).append(" ");
|
||||
}
|
||||
|
@ -8,23 +8,17 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "kick", usage = "kick",
|
||||
description = "Kicks the specified player from the server (WIP)", permission = "server.kick")
|
||||
@Command(label = "kick", usage = "kick", permission = "server.kick", description = "commands.kick.description")
|
||||
public final class KickCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender != null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.kick.player_kick_player",
|
||||
Integer.toString(sender.getAccount().getPlayerUid()), sender.getAccount().getUsername(),
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player",
|
||||
Integer.toString(sender.getUid()), sender.getAccount().getUsername(),
|
||||
Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
|
||||
} else {
|
||||
CommandHandler.sendMessage(null, translate("commands.kick.server_kick_player", Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.kick.server_kick_player", Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
|
||||
}
|
||||
|
||||
targetPlayer.getSession().close();
|
||||
|
@ -12,17 +12,11 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "killall", usage = "killall [sceneId]",
|
||||
description = "Kill all entities", permission = "server.killall")
|
||||
@Command(label = "killall", usage = "killall [sceneId]", permission = "server.killall", permissionTargeted = "server.killall.others", description = "commands.killall.description")
|
||||
public final class KillAllCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
Scene scene = targetPlayer.getScene();
|
||||
try {
|
||||
switch (args.size()) {
|
||||
@ -32,14 +26,14 @@ public final class KillAllCommand implements CommandHandler {
|
||||
scene = targetPlayer.getWorld().getSceneById(Integer.parseInt(args.get(0)));
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate("commands.kill.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.usage"));
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
}
|
||||
if (scene == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.kill.scene_not_found_in_player_world"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.scene_not_found_in_player_world"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -49,6 +43,6 @@ public final class KillAllCommand implements CommandHandler {
|
||||
.filter(entity -> entity instanceof EntityMonster)
|
||||
.toList();
|
||||
toKill.forEach(entity -> sceneF.killEntity(entity, 0));
|
||||
CommandHandler.sendMessage(sender, translate("commands.kill.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
|
||||
}
|
||||
}
|
||||
|
@ -13,14 +13,13 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "killcharacter", usage = "killcharacter", aliases = {"suicide", "kill"},
|
||||
description = "Kills the players current character", permission = "player.killcharacter")
|
||||
@Command(label = "killcharacter", usage = "killcharacter", aliases = {"suicide", "kill"}, permission = "player.killcharacter", permissionTargeted = "player.killcharacter.others", description = "commands.killCharacter.description")
|
||||
public final class KillCharacterCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
if (args.isEmpty()) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killCharacter.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -33,6 +32,6 @@ public final class KillCharacterCommand implements CommandHandler {
|
||||
targetPlayer.getScene().removeEntity(entity);
|
||||
entity.onDeath(0);
|
||||
|
||||
CommandHandler.sendMessage(sender, translate("commands.killCharacter.success", targetPlayer.getNickname()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killCharacter.success", targetPlayer.getNickname()));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "language", usage = "language [language code]", description = "commands.language.description", aliases = {"lang"}, targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class LanguageCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.isEmpty()) {
|
||||
String curLangCode = null;
|
||||
if (sender != null) {
|
||||
curLangCode = Utils.getLanguageCode(sender.getAccount().getLocale());
|
||||
}
|
||||
else {
|
||||
curLangCode = Grasscutter.getLanguage().getLanguageCode();
|
||||
}
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.language.current_language", curLangCode));
|
||||
return;
|
||||
}
|
||||
|
||||
String langCode = args.get(0);
|
||||
|
||||
var languageInst = Grasscutter.getLanguage(langCode);
|
||||
var actualLangCode = languageInst.getLanguageCode();
|
||||
var locale = Locale.forLanguageTag(actualLangCode);
|
||||
if (sender != null) {
|
||||
var account = sender.getAccount();
|
||||
account.setLocale(locale);
|
||||
account.save();
|
||||
}
|
||||
else {
|
||||
Grasscutter.setLanguage(languageInst);
|
||||
var config = Grasscutter.getConfig();
|
||||
config.language.language = locale;
|
||||
Grasscutter.saveConfig(config);
|
||||
}
|
||||
|
||||
if (!langCode.equals(actualLangCode)) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.language.language_not_found", langCode));
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.language.language_changed", actualLangCode));
|
||||
|
||||
}
|
||||
}
|
@ -10,8 +10,7 @@ import java.util.Map;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "list", usage = "list [uid]",
|
||||
description = "List online players", aliases = {"players"})
|
||||
@Command(label = "list", usage = "list [uid]", aliases = {"players"}, description = "commands.list.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class ListCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
@ -23,7 +22,7 @@ public final class ListCommand implements CommandHandler {
|
||||
needUID = args.get(0).equals("uid");
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate("commands.list.success", Integer.toString(playersMap.size())));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.list.success", Integer.toString(playersMap.size())));
|
||||
|
||||
if (playersMap.size() != 0) {
|
||||
StringBuilder playerSet = new StringBuilder();
|
||||
|
@ -0,0 +1,34 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
|
||||
@Command(label = "nostamina", usage = "nostamina [on|off|toggle]", aliases = {"ns"}, permission = "player.nostamina", permissionTargeted = "player.nostamina.others", description = "commands.nostamina.description")
|
||||
public final class NoStaminaCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
boolean stamina = !targetPlayer.getStamina();
|
||||
if (args.size() == 1) {
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
case "on":
|
||||
stamina = true;
|
||||
break;
|
||||
case "off":
|
||||
stamina = false;
|
||||
break;
|
||||
default:
|
||||
// toggled
|
||||
break;
|
||||
}
|
||||
}
|
||||
targetPlayer.setStamina(stamina); //Set
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.nostamina.success", (stamina ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
|
||||
}
|
||||
}
|
@ -10,19 +10,13 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "permission", usage = "permission <add|remove> <permission>",
|
||||
description = "Grants or removes a permission for a user", permission = "*")
|
||||
@Command(label = "permission", usage = "permission <add|remove> <permission>", permission = "permission", description = "commands.permission.description")
|
||||
public final class PermissionCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() != 2) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.permission.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -31,26 +25,26 @@ public final class PermissionCommand implements CommandHandler {
|
||||
|
||||
Account account = targetPlayer.getAccount();
|
||||
if (account == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.permission.account_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.account_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate("commands.permission.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.usage"));
|
||||
break;
|
||||
case "add":
|
||||
if (account.addPermission(permission)) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.permission.add"));
|
||||
} else CommandHandler.sendMessage(sender, translate("commands.permission.has_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.add"));
|
||||
} else CommandHandler.sendMessage(sender, translate(sender, "commands.permission.has_error"));
|
||||
break;
|
||||
case "remove":
|
||||
if (account.removePermission(permission)) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.permission.remove"));
|
||||
} else CommandHandler.sendMessage(sender, translate("commands.permission.not_have_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.permission.remove"));
|
||||
} else CommandHandler.sendMessage(sender, translate(sender, "commands.permission.not_have_error"));
|
||||
break;
|
||||
}
|
||||
|
||||
account.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,19 +9,13 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "position", usage = "position", aliases = {"pos"},
|
||||
description = "Get coordinates.")
|
||||
@Command(label = "position", usage = "position", aliases = {"pos"}, description = "commands.position.description")
|
||||
public final class PositionCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
Position pos = targetPlayer.getPos();
|
||||
CommandHandler.sendMessage(sender, translate("commands.position.success",
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.position.success",
|
||||
Float.toString(pos.getX()), Float.toString(pos.getY()), Float.toString(pos.getZ()),
|
||||
Integer.toString(targetPlayer.getSceneId())));
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.quest.GameQuest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "quest", usage = "quest <add|finish> [questId]", permission = "player.quest", permissionTargeted = "player.quest.others", description = "commands.quest.description")
|
||||
public final class QuestCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() != 2) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
String cmd = args.get(0).toLowerCase();
|
||||
int questId;
|
||||
|
||||
try {
|
||||
questId = Integer.parseInt(args.get(1));
|
||||
} catch (Exception e) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.invalid_id"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case "add" -> {
|
||||
GameQuest quest = targetPlayer.getQuestManager().addQuest(questId);
|
||||
|
||||
if (quest != null) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.added", questId));
|
||||
return;
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.not_found"));
|
||||
}
|
||||
case "finish" -> {
|
||||
GameQuest quest = targetPlayer.getQuestManager().getQuestById(questId);
|
||||
|
||||
if (quest == null) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.not_found"));
|
||||
return;
|
||||
}
|
||||
|
||||
quest.finish();
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.finished", questId));
|
||||
}
|
||||
default -> {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.quest.usage"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,21 +9,19 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "reload", usage = "reload",
|
||||
description = "Reload server config", permission = "server.reload")
|
||||
@Command(label = "reload", usage = "reload", permission = "server.reload", description = "commands.reload.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class ReloadCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.reload.reload_start"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.reload.reload_start"));
|
||||
|
||||
Grasscutter.loadConfig();
|
||||
Grasscutter.loadLanguage();
|
||||
Grasscutter.getGameServer().getGachaManager().load();
|
||||
Grasscutter.getGameServer().getDropManager().load();
|
||||
Grasscutter.getGameServer().getShopManager().load();
|
||||
Grasscutter.getDispatchServer().loadQueries();
|
||||
|
||||
CommandHandler.sendMessage(sender, translate("commands.reload.reload_done"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.reload.reload_done"));
|
||||
}
|
||||
}
|
||||
|
@ -11,20 +11,14 @@ import java.util.List;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "resetconst", usage = "resetconst [all]",
|
||||
description = "Resets the constellation level on your current active character, will need to relog after using the command to see any changes.",
|
||||
aliases = {"resetconstellation"}, permission = "player.resetconstellation")
|
||||
aliases = {"resetconstellation"}, permission = "player.resetconstellation", permissionTargeted = "player.resetconstellation.others", description = "commands.resetConst.description")
|
||||
public final class ResetConstCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() > 0 && args.get(0).equalsIgnoreCase("all")) {
|
||||
targetPlayer.getAvatars().forEach(this::resetConstellation);
|
||||
CommandHandler.sendMessage(sender, translate("commands.resetConst.reset_all"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.resetConst.reset_all"));
|
||||
} else {
|
||||
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
|
||||
if (entity == null) {
|
||||
@ -34,7 +28,7 @@ public final class ResetConstCommand implements CommandHandler {
|
||||
Avatar avatar = entity.getAvatar();
|
||||
this.resetConstellation(avatar);
|
||||
|
||||
CommandHandler.sendMessage(sender, translate("commands.resetConst.success", avatar.getAvatarData().getName()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.resetConst.success", avatar.getAvatarData().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,4 +38,4 @@ public final class ResetConstCommand implements CommandHandler {
|
||||
avatar.recalcStats();
|
||||
avatar.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,18 +9,18 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "resetshop", usage = "resetshop",
|
||||
description = "Reset target player's shop refresh time.", permission = "server.resetshop")
|
||||
@Command(label = "resetshop", usage = "resetshop", permission = "server.resetshop", permissionTargeted = "server.resetshop.others", description = "commands.resetShopLimit.description")
|
||||
public final class ResetShopLimitCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
if (args.isEmpty()) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.resetShopLimit.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
targetPlayer.getShopLimit().forEach(x -> x.setNextRefreshTime(0));
|
||||
targetPlayer.save();
|
||||
CommandHandler.sendMessage(sender, translate("commands.status.success"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.resetShopLimit.success"));
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,9 @@ import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Command(label = "restart", usage = "restart - Restarts the current session")
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "restart", usage = "restart", description = "commands.restart.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class RestartCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
|
@ -13,8 +13,7 @@ import java.util.List;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Command(label = "sendmail", usage = "sendmail <userId|all|help> [templateId]",
|
||||
description = "Sends mail to the specified user. The usage of this command changes based on it's composition state.", permission = "server.sendmail")
|
||||
@Command(label = "sendmail", usage = "sendmail <userId|all|help> [templateId]", permission = "server.sendmail", description = "commands.sendMail.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class SendMailCommand implements CommandHandler {
|
||||
|
||||
// TODO: You should be able to do /sendmail and then just send subsequent messages until you finish
|
||||
@ -40,24 +39,24 @@ public final class SendMailCommand implements CommandHandler {
|
||||
MailBuilder mailBuilder;
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
case "help" -> {
|
||||
CommandHandler.sendMessage(sender, this.getClass().getAnnotation(Command.class).description() + "\nUsage: " + this.getClass().getAnnotation(Command.class).usage());
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.usage"));
|
||||
return;
|
||||
}
|
||||
case "all" -> mailBuilder = new MailBuilder(true, new Mail());
|
||||
default -> {
|
||||
if (DatabaseHelper.getPlayerById(Integer.parseInt(args.get(0))) != null) {
|
||||
if (DatabaseHelper.getPlayerByUid(Integer.parseInt(args.get(0))) != null) {
|
||||
mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail());
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.user_not_exist", args.get(0)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.user_not_exist", args.get(0)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mailBeingConstructed.put(senderId, mailBuilder);
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.start_composition"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.start_composition"));
|
||||
}
|
||||
case 2 -> CommandHandler.sendMessage(sender, translate("commands.sendMail.templates"));
|
||||
default -> CommandHandler.sendMessage(sender, translate("commands.sendMail.invalid_arguments"));
|
||||
case 2 -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.templates"));
|
||||
default -> CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.invalid_arguments"));
|
||||
}
|
||||
} else {
|
||||
MailBuilder mailBuilder = mailBeingConstructed.get(senderId);
|
||||
@ -66,28 +65,28 @@ public final class SendMailCommand implements CommandHandler {
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
case "stop" -> {
|
||||
mailBeingConstructed.remove(senderId);
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.sendCancel"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.sendCancel"));
|
||||
return;
|
||||
}
|
||||
case "finish" -> {
|
||||
if (mailBuilder.constructionStage == 3) {
|
||||
if (!mailBuilder.sendToAll) {
|
||||
Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail);
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.send_done", Integer.toString(mailBuilder.recipient)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", Integer.toString(mailBuilder.recipient)));
|
||||
} else {
|
||||
for (Player player : DatabaseHelper.getAllPlayers()) {
|
||||
Grasscutter.getGameServer().getPlayerByUid(player.getUid(), true).sendMail(mailBuilder.mail);
|
||||
}
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.send_all_done"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_all_done"));
|
||||
}
|
||||
mailBeingConstructed.remove(senderId);
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.not_composition_end", getConstructionArgs(mailBuilder.constructionStage)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.not_composition_end", getConstructionArgs(mailBuilder.constructionStage, sender)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "help" -> {
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.please_use", getConstructionArgs(mailBuilder.constructionStage)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.please_use", getConstructionArgs(mailBuilder.constructionStage, sender)));
|
||||
return;
|
||||
}
|
||||
default -> {
|
||||
@ -95,19 +94,19 @@ public final class SendMailCommand implements CommandHandler {
|
||||
case 0 -> {
|
||||
String title = String.join(" ", args.subList(0, args.size()));
|
||||
mailBuilder.mail.mailContent.title = title;
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.set_title", title));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_title", title));
|
||||
mailBuilder.constructionStage++;
|
||||
}
|
||||
case 1 -> {
|
||||
String contents = String.join(" ", args.subList(0, args.size()));
|
||||
mailBuilder.mail.mailContent.content = contents;
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.set_contents", contents));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_contents", contents));
|
||||
mailBuilder.constructionStage++;
|
||||
}
|
||||
case 2 -> {
|
||||
String msgSender = String.join(" ", args.subList(0, args.size()));
|
||||
mailBuilder.mail.mailContent.sender = msgSender;
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.set_message_sender", msgSender));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.set_message_sender", msgSender));
|
||||
mailBuilder.constructionStage++;
|
||||
}
|
||||
case 3 -> {
|
||||
@ -120,21 +119,21 @@ public final class SendMailCommand implements CommandHandler {
|
||||
try {
|
||||
refinement = Integer.parseInt(args.get(3));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemRefinement"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemRefinement"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 3: // <itemId|itemName> [amount] [level]
|
||||
try {
|
||||
lvl = Integer.parseInt(args.get(2));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemLevel"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemLevel"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 2: // <itemId|itemName> [amount]
|
||||
try {
|
||||
amount = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 1: // <itemId|itemName>
|
||||
@ -142,33 +141,33 @@ public final class SendMailCommand implements CommandHandler {
|
||||
item = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from item name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.invalid.itemId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: // *No args*
|
||||
CommandHandler.sendMessage(sender, translate("commands.give.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.usage"));
|
||||
return;
|
||||
}
|
||||
mailBuilder.mail.itemList.add(new Mail.MailItem(item, amount, lvl));
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.send", Integer.toString(amount), Integer.toString(item), Integer.toString(lvl)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send", Integer.toString(amount), Integer.toString(item), Integer.toString(lvl)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMail.invalid_arguments_please_use", getConstructionArgs(mailBuilder.constructionStage)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.invalid_arguments_please_use", getConstructionArgs(mailBuilder.constructionStage, sender)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getConstructionArgs(int stage) {
|
||||
private String getConstructionArgs(int stage, Player sender) {
|
||||
return switch(stage) {
|
||||
case 0 -> translate("commands.sendMail.title");
|
||||
case 1 -> translate("commands.sendMail.message");
|
||||
case 2 -> translate("commands.sendMail.sender");
|
||||
case 3 -> translate("commands.sendMail.arguments");
|
||||
default -> translate("commands.sendMail.error", Integer.toString(stage));
|
||||
case 0 -> translate(sender, "commands.sendMail.title");
|
||||
case 1 -> translate(sender, "commands.sendMail.message");
|
||||
case 2 -> translate(sender, "commands.sendMail.sender");
|
||||
case 3 -> translate(sender, "commands.sendMail.arguments");
|
||||
default -> translate(sender, "commands.sendMail.error", Integer.toString(stage));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -8,23 +8,19 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "say", usage = "say <message>", description = "Sends a message to a player as the server",
|
||||
aliases = {"sendservmsg", "sendservermessage", "sendmessage"}, permission = "server.sendmessage")
|
||||
@Command(label = "sendmessage", usage = "sendmessage <message>",
|
||||
aliases = {"say", "sendservmsg", "sendservermessage"}, permission = "server.sendmessage", permissionTargeted = "server.sendmessage.others", description = "commands.sendMessage.description")
|
||||
public final class SendMessageCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
if (args.size() == 0) {
|
||||
CommandHandler.sendMessage(null, translate("commands.sendMessage.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMessage.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
String message = String.join(" ", args);
|
||||
CommandHandler.sendMessage(targetPlayer, message);
|
||||
CommandHandler.sendMessage(sender, translate("commands.sendMessage.success"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMessage.success"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,26 +12,20 @@ import emu.grasscutter.server.packet.send.PacketAvatarFetterDataNotify;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "setfetterlevel", usage = "setfetterlevel <level>",
|
||||
description = "Sets your fetter level for your current active character",
|
||||
aliases = {"setfetterlvl", "setfriendship"}, permission = "player.setfetterlevel")
|
||||
aliases = {"setfetterlvl", "setfriendship"}, permission = "player.setfetterlevel", permissionTargeted = "player.setfetterlevel.others", description = "commands.setFetterLevel.description")
|
||||
public final class SetFetterLevelCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() != 1) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int fetterLevel = Integer.parseInt(args.get(0));
|
||||
if (fetterLevel < 0 || fetterLevel > 10) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.range_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.range_error"));
|
||||
return;
|
||||
}
|
||||
Avatar avatar = targetPlayer.getTeamManager().getCurrentAvatarEntity().getAvatar();
|
||||
@ -43,9 +37,9 @@ public final class SetFetterLevelCommand implements CommandHandler {
|
||||
avatar.save();
|
||||
|
||||
targetPlayer.sendPacket(new PacketAvatarFetterDataNotify(avatar));
|
||||
CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.success", fetterLevel));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.success", fetterLevel));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.setFetterLevel.level_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setFetterLevel.level_error"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,7 @@ import emu.grasscutter.utils.Language;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "setstats", usage = "setstats|stats <stat> <value>",
|
||||
description = "Set fight property for your current active character", aliases = {"stats"}, permission = "player.setstats")
|
||||
@Command(label = "setstats", usage = "setstats|stats <stat> <value>", aliases = {"stats"}, permission = "player.setstats", permissionTargeted = "player.setstats.others", description = "commands.setStats.description")
|
||||
public final class SetStatsCommand implements CommandHandler {
|
||||
static class Stat {
|
||||
String name;
|
||||
@ -176,16 +175,11 @@ public final class SetStatsCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
String syntax = sender == null ? translate("commands.setStats.usage_console") : translate("commands.setStats.ingame");
|
||||
String usage = syntax + translate("commands.setStats.help_message");
|
||||
String syntax = sender == null ? translate(sender, "commands.setStats.usage_console") : translate(sender, "commands.setStats.usage_ingame");
|
||||
String usage = syntax + translate(sender, "commands.setStats.help_message");
|
||||
String statStr;
|
||||
String valueStr;
|
||||
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() == 2) {
|
||||
statStr = args.get(0).toLowerCase();
|
||||
valueStr = args.get(1);
|
||||
@ -204,7 +198,7 @@ public final class SetStatsCommand implements CommandHandler {
|
||||
value = Float.parseFloat(valueStr);
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.setStats.value_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.value_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -218,10 +212,10 @@ public final class SetStatsCommand implements CommandHandler {
|
||||
valueStr = String.format("%.0f", value);
|
||||
}
|
||||
if (targetPlayer == sender) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.setStats.set_self", stat.name, valueStr));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.set_self", stat.name, valueStr));
|
||||
} else {
|
||||
String uidStr = targetPlayer.getAccount().getId();
|
||||
CommandHandler.sendMessage(sender, translate("commands.setStats.set_self", stat.name, uidStr, valueStr));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.set_for_uid", stat.name, uidStr, valueStr));
|
||||
}
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, usage);
|
||||
|
@ -10,26 +10,20 @@ import java.util.List;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "setworldlevel", usage = "setworldlevel <level>",
|
||||
description = "Sets your world level (Relog to see proper effects)",
|
||||
aliases = {"setworldlvl"}, permission = "player.setworldlevel")
|
||||
aliases = {"setworldlvl"}, permission = "player.setworldlevel", permissionTargeted = "player.setworldlevel.others", description = "commands.setWorldLevel.description")
|
||||
public final class SetWorldLevelCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.setWorldLevel.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int level = Integer.parseInt(args.get(0));
|
||||
if (level > 8 || level < 0) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.setWorldLevel.value_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.value_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -37,9 +31,9 @@ public final class SetWorldLevelCommand implements CommandHandler {
|
||||
targetPlayer.getWorld().setWorldLevel(level);
|
||||
targetPlayer.setWorldLevel(level);
|
||||
|
||||
CommandHandler.sendMessage(sender, translate("commands.setWorldLevel.success", Integer.toString(level)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.success", Integer.toString(level)));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(null, translate("commands.setWorldLevel.invalid_world_level"));
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.setWorldLevel.invalid_world_level"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.AvatarData;
|
||||
import emu.grasscutter.data.def.GadgetData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.data.excels.AvatarData;
|
||||
import emu.grasscutter.data.excels.GadgetData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.data.excels.MonsterData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.*;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
@ -20,59 +20,75 @@ import javax.swing.text.html.parser.Entity;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "spawn", usage = "spawn <entityId> [amount] [level(monster only)]",
|
||||
description = "Spawns an entity near you", permission = "server.spawn")
|
||||
@Command(label = "spawn", usage = "spawn <entityId> [amount] [level(monster only)] [<x> <y> <z>(monster only, optional)]", permission = "server.spawn", permissionTargeted = "server.spawn.others", description = "commands.spawn.description")
|
||||
public final class SpawnCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
int id = 0; // This is just to shut up the linter, it's not a real default
|
||||
int amount = 1;
|
||||
int level = 1;
|
||||
float x = 0, y = 0, z = 0;
|
||||
switch (args.size()) {
|
||||
case 6:
|
||||
try {
|
||||
x = Float.parseFloat(args.get(3));
|
||||
y = Float.parseFloat(args.get(4));
|
||||
z = Float.parseFloat(args.get(5));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
} // Fallthrough
|
||||
case 3:
|
||||
try {
|
||||
level = Integer.parseInt(args.get(2));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
} // Fallthrough
|
||||
case 2:
|
||||
try {
|
||||
amount = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.error.amount"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
|
||||
} // Fallthrough
|
||||
case 1:
|
||||
try {
|
||||
id = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.error.entityId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.entityId"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate("commands.spawn.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
MonsterData monsterData = GameData.getMonsterDataMap().get(id);
|
||||
GadgetData gadgetData = GameData.getGadgetDataMap().get(id);
|
||||
ItemData itemData = GameData.getItemDataMap().get(id);
|
||||
if (monsterData == null && gadgetData == null && itemData == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.generic.error.entityId"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.entityId"));
|
||||
return;
|
||||
}
|
||||
|
||||
Scene scene = targetPlayer.getScene();
|
||||
|
||||
if (scene.getEntities().size() + amount > GAME_OPTIONS.sceneEntityLimit) {
|
||||
amount = Math.max(Math.min(GAME_OPTIONS.sceneEntityLimit - scene.getEntities().size(), amount), 0);
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.limit_reached", amount));
|
||||
if (amount <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
double maxRadius = Math.sqrt(amount * 0.2 / Math.PI);
|
||||
for (int i = 0; i < amount; i++) {
|
||||
Position pos = GetRandomPositionInCircle(targetPlayer.getPos(), maxRadius).addY(3);
|
||||
if(x != 0 && y != 0 && z != 0) {
|
||||
pos = GetRandomPositionInCircle(new Position(x, y, z), maxRadius).addY(3);
|
||||
}
|
||||
GameEntity entity = null;
|
||||
if (itemData != null) {
|
||||
entity = new EntityItem(scene, null, itemData, pos, 1, true);
|
||||
@ -101,7 +117,7 @@ public final class SpawnCommand implements CommandHandler {
|
||||
|
||||
scene.addEntity(entity);
|
||||
}
|
||||
CommandHandler.sendMessage(sender, translate("commands.spawn.success", Integer.toString(amount), Integer.toString(id)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.success", Integer.toString(amount), Integer.toString(id)));
|
||||
}
|
||||
|
||||
private Position GetRandomPositionInCircle(Position origin, double radius){
|
||||
|
@ -9,15 +9,14 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "stop", usage = "stop",
|
||||
description = "Stops the server", permission = "server.stop")
|
||||
@Command(label = "stop", usage = "stop", permission = "server.stop", description = "commands.stop.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class StopCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
CommandHandler.sendMessage(null, translate("commands.stop.success"));
|
||||
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
|
||||
CommandHandler.sendMessage(p, translate("commands.stop.success"));
|
||||
CommandHandler.sendMessage(p, translate(p, "commands.stop.success"));
|
||||
}
|
||||
|
||||
System.exit(1000);
|
||||
|
@ -3,7 +3,7 @@ package emu.grasscutter.command.commands;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.data.excels.AvatarSkillDepotData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
@ -14,18 +14,17 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "talent", usage = "talent <talentID> <value>",
|
||||
description = "Set talent level for your current active character", permission = "player.settalent")
|
||||
@Command(label = "talent", usage = "talent <talentId> <value>", permission = "player.settalent", permissionTargeted = "player.settalent.others", description = "commands.talent.description")
|
||||
public final class TalentCommand implements CommandHandler {
|
||||
private void setTalentLevel(Player sender, Player player, Avatar avatar, int talentId, int talentLevel) {
|
||||
int oldLevel = avatar.getSkillLevelMap().get(talentId);
|
||||
if (talentLevel < 0 || talentLevel > 15) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.lower_16"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.lower_16"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Upgrade skill
|
||||
avatar.getSkillLevelMap().put(talentLevel, talentLevel);
|
||||
avatar.getSkillLevelMap().put(talentId, talentLevel);
|
||||
avatar.save();
|
||||
|
||||
// Packet
|
||||
@ -41,20 +40,15 @@ public final class TalentCommand implements CommandHandler {
|
||||
} else if (talentId == depot.getEnergySkill()) {
|
||||
successMessage = "commands.talent.set_q";
|
||||
}
|
||||
CommandHandler.sendMessage(sender, translate(successMessage, talentLevel));
|
||||
CommandHandler.sendMessage(sender, translate(sender, successMessage, talentLevel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.size() < 1){
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -63,15 +57,15 @@ public final class TalentCommand implements CommandHandler {
|
||||
String cmdSwitch = args.get(0);
|
||||
switch (cmdSwitch) {
|
||||
default -> {
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
|
||||
return;
|
||||
}
|
||||
case "set" -> {
|
||||
if (args.size() < 3) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_1"));
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_3"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_1"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_3"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@ -79,13 +73,13 @@ public final class TalentCommand implements CommandHandler {
|
||||
int newLevel = Integer.parseInt(args.get(2));
|
||||
setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel);
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.invalid_skill_id"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.invalid_skill_id"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
case "n", "e", "q" -> {
|
||||
if (args.size() < 2) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.usage_2"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.usage_2"));
|
||||
return;
|
||||
}
|
||||
AvatarSkillDepotData SkillDepot = avatar.getData().getSkillDepot();
|
||||
@ -98,7 +92,7 @@ public final class TalentCommand implements CommandHandler {
|
||||
int newLevel = Integer.parseInt(args.get(1));
|
||||
setTalentLevel(sender, targetPlayer, avatar, skillId, newLevel);
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.invalid_level"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.invalid_level"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -106,9 +100,9 @@ public final class TalentCommand implements CommandHandler {
|
||||
int skillIdNorAtk = avatar.getData().getSkillDepot().getSkills().get(0);
|
||||
int skillIdE = avatar.getData().getSkillDepot().getSkills().get(1);
|
||||
int skillIdQ = avatar.getData().getSkillDepot().getEnergySkill();
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.normal_attack_id", Integer.toString(skillIdNorAtk)));
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.e_skill_id", Integer.toString(skillIdE)));
|
||||
CommandHandler.sendMessage(sender, translate("commands.talent.q_skill_id", Integer.toString(skillIdQ)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.normal_attack_id", Integer.toString(skillIdNorAtk)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.e_skill_id", Integer.toString(skillIdE)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.talent.q_skill_id", Integer.toString(skillIdQ)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
254
src/main/java/emu/grasscutter/command/commands/TeamCommand.java
Normal file
254
src/main/java/emu/grasscutter/command/commands/TeamCommand.java
Normal file
@ -0,0 +1,254 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
|
||||
@Command(label = "team", usage = "team <add|remove|set> [avatarId,...] [index|first|last|index-index,...]",
|
||||
permission = "player.team", permissionTargeted = "player.team.others", description = "commands.team.description")
|
||||
public final class TeamCommand implements CommandHandler {
|
||||
private static final int BASE_AVATARID = 10000000;
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.isEmpty()) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.usage");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args.get(0)) {
|
||||
case "add":
|
||||
if (!addCommand(sender, targetPlayer, args)) return;
|
||||
break;
|
||||
|
||||
case "remove":
|
||||
if (!removeCommand(sender, targetPlayer, args)) return;
|
||||
break;
|
||||
|
||||
case "set":
|
||||
if (!setCommand(sender, targetPlayer, args)) return;
|
||||
break;
|
||||
|
||||
default:
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage");
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.usage");
|
||||
return;
|
||||
}
|
||||
|
||||
targetPlayer.getTeamManager().updateTeamEntities(
|
||||
new PacketChangeMpTeamAvatarRsp(targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo()));
|
||||
}
|
||||
|
||||
private boolean addCommand(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 2) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage");
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.add_usage");
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = -1;
|
||||
if (args.size() > 2) {
|
||||
try {
|
||||
index = Integer.parseInt(args.get(2)) - 1;
|
||||
if (index < 0) index = 0;
|
||||
} catch (Exception e) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_index");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var avatarIds = args.get(1).split(",");
|
||||
var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars();
|
||||
|
||||
if (currentTeamAvatars.size() + avatarIds.length > GAME_OPTIONS.avatarLimits.singlePlayerTeam) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.add_too_much", GAME_OPTIONS.avatarLimits.singlePlayerTeam);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var avatarId: avatarIds) {
|
||||
int id = Integer.parseInt(avatarId);
|
||||
var success = addAvatar(sender, targetPlayer, id, index);
|
||||
if (index > 0) ++index;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean removeCommand(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 2) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage");
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.remove_usage");
|
||||
return false;
|
||||
}
|
||||
|
||||
var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars();
|
||||
var avatarCount = currentTeamAvatars.size();
|
||||
|
||||
var metaIndexList = args.get(1).split(",");
|
||||
var indexes = new HashSet<Integer>();
|
||||
var ignoreList = new ArrayList<Integer>();
|
||||
for (var metaIndex: metaIndexList) {
|
||||
// step 1: parse metaIndex to indexes
|
||||
var subIndexes = transformToIndexes(metaIndex, avatarCount);
|
||||
if (subIndexes == null) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", metaIndex);
|
||||
continue;
|
||||
}
|
||||
|
||||
// step 2: get all of the avatar id through indexes
|
||||
for (var avatarIndex: subIndexes) {
|
||||
try {
|
||||
indexes.add(currentTeamAvatars.get(avatarIndex - 1));
|
||||
} catch (Exception e) {
|
||||
ignoreList.add(avatarIndex);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 3: check if user remove all of the avatar
|
||||
if (indexes.size() >= avatarCount) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.remove_too_much");
|
||||
return false;
|
||||
}
|
||||
|
||||
// step 4: hint user for ignore index
|
||||
if (!ignoreList.isEmpty()) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.ignore_index", ignoreList);
|
||||
}
|
||||
|
||||
// step 5: remove
|
||||
currentTeamAvatars.removeAll(indexes);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean setCommand(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 3) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage");
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.set_usage");
|
||||
return false;
|
||||
}
|
||||
|
||||
var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars();
|
||||
|
||||
int index;
|
||||
try {
|
||||
index = Integer.parseInt(args.get(1)) - 1;
|
||||
if (index < 0) index = 0;
|
||||
} catch(Exception e) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", args.get(1));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index + 1 > currentTeamAvatars.size()) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.index_out_of_range");
|
||||
return false;
|
||||
}
|
||||
|
||||
int avatarId;
|
||||
try {
|
||||
avatarId = Integer.parseInt(args.get(2));
|
||||
} catch(Exception e) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_parse_avatar_id", args.get(2));
|
||||
return false;
|
||||
}
|
||||
if (avatarId < BASE_AVATARID) {
|
||||
avatarId += BASE_AVATARID;
|
||||
}
|
||||
|
||||
if (currentTeamAvatars.contains(avatarId)) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_already_in_team", avatarId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!targetPlayer.getAvatars().hasAvatar(avatarId)) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_not_found", avatarId);
|
||||
return false;
|
||||
}
|
||||
|
||||
currentTeamAvatars.set(index, avatarId);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean addAvatar(Player sender, Player targetPlayer, int avatarId, int index) {
|
||||
if (avatarId < BASE_AVATARID) {
|
||||
avatarId += BASE_AVATARID;
|
||||
}
|
||||
var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars();
|
||||
if (currentTeamAvatars.contains(avatarId)) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_already_in_team", avatarId);
|
||||
return false;
|
||||
}
|
||||
if (!targetPlayer.getAvatars().hasAvatar(avatarId)) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_not_found", avatarId);
|
||||
return false;
|
||||
}
|
||||
if (index < 0) {
|
||||
currentTeamAvatars.add(avatarId);
|
||||
} else {
|
||||
currentTeamAvatars.add(index, avatarId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<Integer> transformToIndexes(String metaIndexes, int listLength) {
|
||||
// step 1: check if metaIndexes is a special constants
|
||||
if (metaIndexes.equals("first")) {
|
||||
return List.of(1);
|
||||
} else if (metaIndexes.equals("last")) {
|
||||
return List.of(listLength);
|
||||
}
|
||||
|
||||
// step 2: check if metaIndexes is a range
|
||||
if (metaIndexes.contains("-")) {
|
||||
var range = metaIndexes.split("-");
|
||||
if (range.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int min, max;
|
||||
try {
|
||||
min = switch (range[0]) {
|
||||
case "first" -> 1;
|
||||
case "last" -> listLength;
|
||||
default -> Integer.parseInt(range[0]);
|
||||
};
|
||||
|
||||
max = switch (range[1]) {
|
||||
case "first" -> 1;
|
||||
case "last" -> listLength;
|
||||
default -> Integer.parseInt(range[1]);
|
||||
};
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (min > max) {
|
||||
min ^= max;
|
||||
max ^= min;
|
||||
min ^= max;
|
||||
}
|
||||
|
||||
var indexes = new ArrayList<Integer>();
|
||||
for (int i = min; i <= max; ++i) {
|
||||
indexes.add(i);
|
||||
}
|
||||
return indexes;
|
||||
}
|
||||
|
||||
// step 3: index is a value, simply return
|
||||
try {
|
||||
int index = Integer.parseInt(metaIndexes);
|
||||
return List.of(index);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -10,18 +10,13 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "tpall", usage = "tpall",
|
||||
description = "Teleports all players in your world to your position", permission = "player.tpall")
|
||||
@Command(label = "tpall", usage = "tpall", permission = "player.tpall", permissionTargeted = "player.tpall.others", description = "commands.teleportAll.description")
|
||||
public final class TeleportAllCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!targetPlayer.getWorld().isMultiplayer()) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.teleportAll.error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.error"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -33,6 +28,6 @@ public final class TeleportAllCommand implements CommandHandler {
|
||||
player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), pos);
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate("commands.teleportAll.success"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success"));
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,7 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "teleport", usage = "teleport <x> <y> <z> [scene id]", aliases = {"tp"},
|
||||
description = "Change the player's position.", permission = "player.teleport")
|
||||
@Command(label = "teleport", usage = "teleport <x> <y> <z> [sceneId]", aliases = {"tp"}, permission = "player.teleport", permissionTargeted = "player.teleport.others", description = "commands.teleport.description")
|
||||
public final class TeleportCommand implements CommandHandler {
|
||||
|
||||
private float parseRelative(String input, Float current) { // TODO: Maybe this will be useful elsewhere later
|
||||
@ -27,11 +26,6 @@ public final class TeleportCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
Position pos = targetPlayer.getPos();
|
||||
float x = pos.getX();
|
||||
float y = pos.getY();
|
||||
@ -43,7 +37,7 @@ public final class TeleportCommand implements CommandHandler {
|
||||
try {
|
||||
sceneId = Integer.parseInt(args.get(3));
|
||||
}catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.argument_error"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
} // Fallthrough
|
||||
case 3:
|
||||
try {
|
||||
@ -51,20 +45,20 @@ public final class TeleportCommand implements CommandHandler {
|
||||
y = parseRelative(args.get(1), y);
|
||||
z = parseRelative(args.get(2), z);
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.teleport.invalid_position"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate("commands.teleport.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
Position target_pos = new Position(x, y, z);
|
||||
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos);
|
||||
if (!result) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.teleport.invalid_position"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate("commands.teleport.success",
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success",
|
||||
targetPlayer.getNickname(), Float.toString(x), Float.toString(y),
|
||||
Float.toString(z), Integer.toString(sceneId))
|
||||
);
|
||||
|
@ -0,0 +1,55 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.managers.EnergyManager.EnergyManager;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.TeamManager;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "unlimitenergy", usage = "unlimitenergy [on|off|toggle]", aliases = {"ule"}, permission = "player.unlimitenergy", permissionTargeted = "player.unlimitenergy.others", description = "commands.unlimitenergy.description")
|
||||
public final class UnlimitEnergyCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if(!GAME_OPTIONS.energyUsage){
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unlimitenergy.config_error"));
|
||||
return;
|
||||
}
|
||||
Boolean status = targetPlayer.getEnergyManager().getEnergyUsage();
|
||||
if (args.size() == 1) {
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
case "on":
|
||||
status = true;
|
||||
break;
|
||||
case "off":
|
||||
status = false;
|
||||
break;
|
||||
default:
|
||||
status = !status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EnergyManager energyManager=targetPlayer.getEnergyManager();
|
||||
energyManager.setEnergyUsage(!status);
|
||||
// if unlimitEnergy is enable , make currentActiveTeam's Avatar full-energy
|
||||
if (status) {
|
||||
for (EntityAvatar entityAvatar : targetPlayer.getTeamManager().getActiveTeam()) {
|
||||
entityAvatar.addEnergy(1000,
|
||||
PropChangeReasonOuterClass.PropChangeReason.PROP_CHANGE_REASON_GM,true);
|
||||
}
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unlimitenergy.success", (status ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.tower.TowerLevelRecord;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "unlocktower", usage = "unlocktower", aliases = {"ut"},
|
||||
description = "commands.unlocktower.description", permission = "player.tower")
|
||||
public class UnlockTowerCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
unlockFloor(targetPlayer, targetPlayer.getServer().getTowerScheduleManager()
|
||||
.getCurrentTowerScheduleData().getEntranceFloorId());
|
||||
|
||||
unlockFloor(targetPlayer, targetPlayer.getServer().getTowerScheduleManager()
|
||||
.getScheduleFloors());
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unlocktower.success"));
|
||||
}
|
||||
|
||||
public void unlockFloor(Player player, List<Integer> floors){
|
||||
floors.stream()
|
||||
.filter(id -> !player.getTowerManager().getRecordMap().containsKey(id))
|
||||
.forEach(id -> player.getTowerManager().getRecordMap().put(id, new TowerLevelRecord(id)));
|
||||
}
|
||||
}
|
@ -11,17 +11,11 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "weather", usage = "weather <weatherId> [climateId]",
|
||||
description = "Changes the weather.", aliases = {"w"}, permission = "player.weather")
|
||||
@Command(label = "weather", usage = "weather <climate type(weatherId)> <weather type(climateId)>", aliases = {"w"}, permission = "player.weather", permissionTargeted = "player.weather.others", description = "commands.weather.description")
|
||||
public final class WeatherCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
int weatherId = 0;
|
||||
int climateId = 1;
|
||||
switch (args.size()) {
|
||||
@ -29,17 +23,17 @@ public final class WeatherCommand implements CommandHandler {
|
||||
try {
|
||||
climateId = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.weather.invalid_id"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.weather.invalid_id"));
|
||||
}
|
||||
case 1:
|
||||
try {
|
||||
weatherId = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate("commands.weather.invalid_id"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.weather.invalid_id"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate("commands.weather.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.weather.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -48,6 +42,6 @@ public final class WeatherCommand implements CommandHandler {
|
||||
targetPlayer.getScene().setWeather(weatherId);
|
||||
targetPlayer.getScene().setClimate(climate);
|
||||
targetPlayer.getScene().broadcastPacket(new PacketSceneAreaWeatherNotify(targetPlayer));
|
||||
CommandHandler.sendMessage(sender, translate("commands.weather.success", Integer.toString(weatherId), Integer.toString(climateId)));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.weather.success", Integer.toString(weatherId), Integer.toString(climateId)));
|
||||
}
|
||||
}
|
||||
|
106
src/main/java/emu/grasscutter/data/DataLoader.java
Normal file
106
src/main/java/emu/grasscutter/data/DataLoader.java
Normal file
@ -0,0 +1,106 @@
|
||||
package emu.grasscutter.data;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.server.http.handlers.GachaHandler;
|
||||
import emu.grasscutter.tools.Tools;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static emu.grasscutter.Configuration.DATA;
|
||||
|
||||
public class DataLoader {
|
||||
|
||||
/**
|
||||
* Load a data file by its name. If the file isn't found within the /data directory then it will fallback to the default within the jar resources
|
||||
* @see #load(String, boolean)
|
||||
* @param resourcePath The path to the data file to be loaded.
|
||||
* @return InputStream of the data file.
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public static InputStream load(String resourcePath) throws FileNotFoundException {
|
||||
return load(resourcePath, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a data file by its name.
|
||||
* @param resourcePath The path to the data file to be loaded.
|
||||
* @param useFallback If the file does not exist in the /data directory, should it use the default file in the jar?
|
||||
* @return InputStream of the data file.
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public static InputStream load(String resourcePath, boolean useFallback) throws FileNotFoundException {
|
||||
if(Utils.fileExists(DATA(resourcePath))) {
|
||||
// Data is in the resource directory
|
||||
return new FileInputStream(DATA(resourcePath));
|
||||
} else {
|
||||
if(useFallback) {
|
||||
return FileUtils.readResourceAsStream("/defaults/data/" + resourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void CheckAllFiles() {
|
||||
try {
|
||||
List<Path> filenames = FileUtils.getPathsFromResource("/defaults/data/");
|
||||
|
||||
if (filenames == null) {
|
||||
Grasscutter.getLogger().error("We were unable to locate your default data files.");
|
||||
}
|
||||
|
||||
for (Path file : filenames) {
|
||||
String relativePath = String.valueOf(file).split("defaults[\\\\\\/]data[\\\\\\/]")[1];
|
||||
|
||||
CheckAndCopyData(relativePath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error("An error occurred while trying to check the data folder.", e);
|
||||
}
|
||||
|
||||
GenerateGachaMappings();
|
||||
}
|
||||
|
||||
private static void CheckAndCopyData(String name) {
|
||||
String filePath = Utils.toFilePath(DATA(name));
|
||||
|
||||
if (!Utils.fileExists(filePath)) {
|
||||
// Check if file is in subdirectory
|
||||
if (name.indexOf("/") != -1) {
|
||||
String[] path = name.split("/");
|
||||
|
||||
String folder = "";
|
||||
for(int i = 0; i < (path.length - 1); i++) {
|
||||
folder += path[i] + "/";
|
||||
|
||||
// Make sure the current folder exists
|
||||
String folderToCreate = Utils.toFilePath(DATA(folder));
|
||||
if(!Utils.fileExists(folderToCreate)) {
|
||||
Grasscutter.getLogger().info("Creating data folder '" + folder + "'");
|
||||
Utils.createFolder(folderToCreate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Grasscutter.getLogger().info("Creating default '" + name + "' data");
|
||||
FileUtils.copyResource("/defaults/data/" + name, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateGachaMappings() {
|
||||
if (!Utils.fileExists(GachaHandler.gachaMappings)) {
|
||||
try {
|
||||
Grasscutter.getLogger().info("Creating default '" + GachaHandler.gachaMappings + "' data");
|
||||
Tools.createGachaMapping(GachaHandler.gachaMappings);
|
||||
} catch (Exception exception) {
|
||||
Grasscutter.getLogger().warn("Failed to create gacha mappings. \n" + exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,10 +8,12 @@ import java.util.Map;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import emu.grasscutter.data.custom.AbilityEmbryoEntry;
|
||||
import emu.grasscutter.data.custom.OpenConfigEntry;
|
||||
import emu.grasscutter.data.custom.ScenePointEntry;
|
||||
import emu.grasscutter.data.def.*;
|
||||
import emu.grasscutter.data.binout.AbilityEmbryoEntry;
|
||||
import emu.grasscutter.data.binout.AbilityModifierEntry;
|
||||
import emu.grasscutter.data.binout.MainQuestData;
|
||||
import emu.grasscutter.data.binout.OpenConfigEntry;
|
||||
import emu.grasscutter.data.binout.ScenePointEntry;
|
||||
import emu.grasscutter.data.excels.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
@ -22,8 +24,10 @@ public class GameData {
|
||||
// BinOutputs
|
||||
private static final Int2ObjectMap<String> abilityHashes = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, AbilityEmbryoEntry> abilityEmbryos = new HashMap<>();
|
||||
private static final Map<String, AbilityModifierEntry> abilityModifiers = new HashMap<>();
|
||||
private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
|
||||
private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>();
|
||||
private static final Int2ObjectMap<MainQuestData> mainQuestData = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// ExcelConfigs
|
||||
private static final Int2ObjectMap<PlayerLevelData> playerLevelDataMap = new Int2ObjectOpenHashMap<>();
|
||||
@ -47,7 +51,8 @@ public class GameData {
|
||||
private static final Int2ObjectMap<WeaponPromoteData> weaponPromoteDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<WeaponCurveData> weaponCurveDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
|
||||
private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<MonsterData> monsterDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<NpcData> npcDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<GadgetData> gadgetDataMap = new Int2ObjectOpenHashMap<>();
|
||||
@ -60,16 +65,28 @@ public class GameData {
|
||||
|
||||
private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>();
|
||||
private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexQuestData> codexQuestDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexQuestData> codexQuestDataIdMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexAnimalData> codexAnimalDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexWeaponData> codexWeaponDataIdMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexMaterialData> codexMaterialDataIdMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CodexReliquaryData> codexReliquaryDataIdMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final ArrayList<CodexReliquaryData> codexReliquaryArrayList = new ArrayList<>();
|
||||
private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<QuestData> questDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<ShopGoodsData> shopGoodsDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CombineData> combineDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<RewardPreviewData> rewardPreviewDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<TowerScheduleData> towerScheduleDataMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// Cache
|
||||
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
|
||||
@ -101,6 +118,10 @@ public class GameData {
|
||||
return abilityEmbryos;
|
||||
}
|
||||
|
||||
public static Map<String, AbilityModifierEntry> getAbilityModifiers() {
|
||||
return abilityModifiers;
|
||||
}
|
||||
|
||||
public static Map<String, OpenConfigEntry> getOpenConfigEntries() {
|
||||
return openConfigEntries;
|
||||
}
|
||||
@ -114,6 +135,10 @@ public class GameData {
|
||||
return getScenePointEntries().get(sceneId + "_" + pointId);
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<MainQuestData> getMainQuestDataMap() {
|
||||
return mainQuestData;
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<AvatarData> getAvatarDataMap() {
|
||||
return avatarDataMap;
|
||||
}
|
||||
@ -216,6 +241,9 @@ public class GameData {
|
||||
public static Int2ObjectMap<MonsterData> getMonsterDataMap() {
|
||||
return monsterDataMap;
|
||||
}
|
||||
public static Int2ObjectMap<EnvAnimalGatherConfigData> getEnvAnimalGatherConfigDataMap() {
|
||||
return envAnimalGatherConfigDataMap;
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<NpcData> getNpcDataMap() {
|
||||
return npcDataMap;
|
||||
@ -278,6 +306,18 @@ public class GameData {
|
||||
return fetters;
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<CodexQuestData> getCodexQuestDataIdMap(){return codexQuestDataIdMap;}
|
||||
|
||||
public static Int2ObjectMap<CodexAnimalData> getCodexAnimalDataMap(){return codexAnimalDataMap;}
|
||||
|
||||
public static Int2ObjectMap<CodexWeaponData> getCodexWeaponDataIdMap(){return codexWeaponDataIdMap;}
|
||||
|
||||
public static Int2ObjectMap<CodexMaterialData> getCodexMaterialDataIdMap(){return codexMaterialDataIdMap;}
|
||||
|
||||
public static Int2ObjectMap<CodexReliquaryData> getcodexReliquaryIdMap(){return codexReliquaryDataIdMap;}
|
||||
|
||||
public static ArrayList<CodexReliquaryData> getcodexReliquaryArrayList(){return codexReliquaryArrayList;}
|
||||
|
||||
public static Int2ObjectMap<WorldLevelData> getWorldLevelDataMap() {
|
||||
return worldLevelDataMap;
|
||||
}
|
||||
@ -320,4 +360,11 @@ public class GameData {
|
||||
public static Int2ObjectMap<TowerLevelData> getTowerLevelDataMap(){
|
||||
return towerLevelDataMap;
|
||||
}
|
||||
public static Int2ObjectMap<TowerScheduleData> getTowerScheduleDataMap(){
|
||||
return towerScheduleDataMap;
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<QuestData> getQuestDataMap() {
|
||||
return questDataMap;
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import org.danilopianini.util.FlexibleQuadTree;
|
||||
import org.danilopianini.util.SpatialIndex;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.def.ReliquaryAffixData;
|
||||
import emu.grasscutter.data.def.ReliquaryMainPropData;
|
||||
import emu.grasscutter.data.excels.ReliquaryAffixData;
|
||||
import emu.grasscutter.data.excels.ReliquaryMainPropData;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
|
||||
import emu.grasscutter.utils.WeightedList;
|
||||
|
@ -1,7 +1,6 @@
|
||||
package emu.grasscutter.data;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
@ -12,20 +11,30 @@ import emu.grasscutter.utils.Utils;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.binout.AbilityEmbryoEntry;
|
||||
import emu.grasscutter.data.binout.AbilityModifier;
|
||||
import emu.grasscutter.data.binout.AbilityModifierEntry;
|
||||
import emu.grasscutter.data.binout.MainQuestData;
|
||||
import emu.grasscutter.data.binout.OpenConfigEntry;
|
||||
import emu.grasscutter.data.binout.ScenePointEntry;
|
||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityConfigData;
|
||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
|
||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierActionType;
|
||||
import emu.grasscutter.data.common.PointData;
|
||||
import emu.grasscutter.data.common.ScenePointConfig;
|
||||
import emu.grasscutter.data.custom.AbilityEmbryoEntry;
|
||||
import emu.grasscutter.data.custom.OpenConfigEntry;
|
||||
import emu.grasscutter.data.custom.ScenePointEntry;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
|
||||
public class ResourceLoader {
|
||||
|
||||
private static List<String> loadedResources = new ArrayList<String>();
|
||||
|
||||
public static List<Class<?>> getResourceDefClasses() {
|
||||
Reflections reflections = new Reflections(ResourceLoader.class.getPackage().getName());
|
||||
Set<?> classes = reflections.getSubTypesOf(GameResource.class);
|
||||
@ -47,12 +56,14 @@ public class ResourceLoader {
|
||||
// Load ability lists
|
||||
loadAbilityEmbryos();
|
||||
loadOpenConfig();
|
||||
loadAbilityModifiers();
|
||||
// Load resources
|
||||
loadResources();
|
||||
// Process into depots
|
||||
GameDepot.load();
|
||||
// Load spawn data
|
||||
// Load spawn data and quests
|
||||
loadSpawnData();
|
||||
loadQuests();
|
||||
// Load scene points - must be done AFTER resources are loaded
|
||||
loadScenePoints();
|
||||
// Custom - TODO move this somewhere else
|
||||
@ -89,6 +100,10 @@ public class ResourceLoader {
|
||||
}
|
||||
|
||||
public static void loadResources() {
|
||||
loadResources(false);
|
||||
}
|
||||
|
||||
public static void loadResources(boolean doReload) {
|
||||
for (Class<?> resourceDefinition : getResourceDefClasses()) {
|
||||
ResourceType type = resourceDefinition.getAnnotation(ResourceType.class);
|
||||
|
||||
@ -104,7 +119,7 @@ public class ResourceLoader {
|
||||
}
|
||||
|
||||
try {
|
||||
loadFromResource(resourceDefinition, type, map);
|
||||
loadFromResource(resourceDefinition, type, map, doReload);
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error("Error loading resource file: " + Arrays.toString(type.name()), e);
|
||||
}
|
||||
@ -112,30 +127,32 @@ public class ResourceLoader {
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected static void loadFromResource(Class<?> c, ResourceType type, Int2ObjectMap map) throws Exception {
|
||||
for (String name : type.name()) {
|
||||
loadFromResource(c, name, map);
|
||||
protected static void loadFromResource(Class<?> c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception {
|
||||
if(!loadedResources.contains(c.getSimpleName()) || doReload) {
|
||||
for (String name : type.name()) {
|
||||
loadFromResource(c, name, map);
|
||||
}
|
||||
Grasscutter.getLogger().info("Loaded " + map.size() + " " + c.getSimpleName() + "s.");
|
||||
loadedResources.add(c.getSimpleName());
|
||||
}
|
||||
Grasscutter.getLogger().info("Loaded " + map.size() + " " + c.getSimpleName() + "s.");
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
protected static void loadFromResource(Class<?> c, String fileName, Int2ObjectMap map) throws Exception {
|
||||
FileReader fileReader = new FileReader(Grasscutter.getConfig().RESOURCE_FOLDER + "ExcelBinOutput/" + fileName);
|
||||
Gson gson = Grasscutter.getGsonFactory();
|
||||
List list = gson.fromJson(fileReader, List.class);
|
||||
try (FileReader fileReader = new FileReader(RESOURCE("ExcelBinOutput/" + fileName))) {
|
||||
List list = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, c).getType());
|
||||
|
||||
for (Object o : list) {
|
||||
Map<String, Object> tempMap = Utils.switchPropertiesUpperLowerCase((Map<String, Object>) o, c);
|
||||
GameResource res = gson.fromJson(gson.toJson(tempMap), TypeToken.get(c).getType());
|
||||
res.onLoad();
|
||||
map.put(res.getId(), res);
|
||||
for (Object o : list) {
|
||||
GameResource res = (GameResource) o;
|
||||
res.onLoad();
|
||||
map.put(res.getId(), res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadScenePoints() {
|
||||
Pattern pattern = Pattern.compile("(?<=scene)(.*?)(?=_point.json)");
|
||||
File folder = new File(Grasscutter.getConfig().RESOURCE_FOLDER + "BinOutput/Scene/Point");
|
||||
File folder = new File(RESOURCE("BinOutput/Scene/Point"));
|
||||
|
||||
if (!folder.isDirectory() || !folder.exists() || folder.listFiles() == null) {
|
||||
Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!");
|
||||
@ -144,8 +161,7 @@ public class ResourceLoader {
|
||||
|
||||
List<ScenePointEntry> scenePointList = new ArrayList<>();
|
||||
for (File file : Objects.requireNonNull(folder.listFiles())) {
|
||||
ScenePointConfig config = null;
|
||||
Integer sceneId = null;
|
||||
ScenePointConfig config; Integer sceneId;
|
||||
|
||||
Matcher matcher = pattern.matcher(file.getName());
|
||||
if (matcher.find()) {
|
||||
@ -183,23 +199,19 @@ public class ResourceLoader {
|
||||
}
|
||||
|
||||
private static void loadAbilityEmbryos() {
|
||||
// Read from cached file if exists
|
||||
File embryoCache = new File(Grasscutter.getConfig().DATA_FOLDER + "AbilityEmbryos.json");
|
||||
List<AbilityEmbryoEntry> embryoList = null;
|
||||
|
||||
if (embryoCache.exists()) {
|
||||
// Load from cache
|
||||
try (FileReader fileReader = new FileReader(embryoCache)) {
|
||||
embryoList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityEmbryoEntry.class).getType());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
|
||||
// Read from cached file if exists
|
||||
try(InputStream embryoCache = DataLoader.load("AbilityEmbryos.json", false)) {
|
||||
embryoList = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(embryoCache), TypeToken.getParameterized(Collection.class, AbilityEmbryoEntry.class).getType());
|
||||
} catch(Exception ignored) {}
|
||||
|
||||
if(embryoList == null) {
|
||||
// Load from BinOutput
|
||||
Pattern pattern = Pattern.compile("(?<=ConfigAvatar_)(.*?)(?=.json)");
|
||||
|
||||
embryoList = new LinkedList<>();
|
||||
File folder = new File(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + "BinOutput/Avatar/"));
|
||||
File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Avatar/")));
|
||||
File[] files = folder.listFiles();
|
||||
if(files == null) {
|
||||
Grasscutter.getLogger().error("Error loading ability embryos: no files found in " + folder.getAbsolutePath());
|
||||
@ -244,19 +256,76 @@ public class ResourceLoader {
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadSpawnData() {
|
||||
// Read from cached file if exists
|
||||
File spawnDataEntries = new File(Grasscutter.getConfig().DATA_FOLDER + "Spawns.json");
|
||||
List<SpawnGroupEntry> spawnEntryList = null;
|
||||
|
||||
if (spawnDataEntries.exists()) {
|
||||
// Load from cache
|
||||
try (FileReader fileReader = new FileReader(spawnDataEntries)) {
|
||||
spawnEntryList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType());
|
||||
private static void loadAbilityModifiers() {
|
||||
// Load from BinOutput
|
||||
File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Ability/Temp/AvatarAbilities/")));
|
||||
File[] files = folder.listFiles();
|
||||
if (files == null) {
|
||||
Grasscutter.getLogger().error("Error loading ability modifiers: no files found in " + folder.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
List<AbilityConfigData> abilityConfigList;
|
||||
|
||||
try (FileReader fileReader = new FileReader(file)) {
|
||||
abilityConfigList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityConfigData.class).getType());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
for (AbilityConfigData data : abilityConfigList) {
|
||||
if (data.Default.modifiers == null || data.Default.modifiers.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AbilityModifierEntry modifierEntry = new AbilityModifierEntry(data.Default.abilityName);
|
||||
|
||||
for (Entry<String, AbilityModifier> entry : data.Default.modifiers.entrySet()) {
|
||||
AbilityModifier modifier = entry.getValue();
|
||||
|
||||
// Stare.
|
||||
if (modifier.onAdded != null) {
|
||||
for (AbilityModifierAction action : modifier.onAdded) {
|
||||
if (action.$type.contains("HealHP")) {
|
||||
action.type = AbilityModifierActionType.HealHP;
|
||||
modifierEntry.getOnAdded().add(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modifier.onThinkInterval != null) {
|
||||
for (AbilityModifierAction action : modifier.onThinkInterval) {
|
||||
if (action.$type.contains("HealHP")) {
|
||||
action.type = AbilityModifierActionType.HealHP;
|
||||
modifierEntry.getOnThinkInterval().add(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modifier.onRemoved != null) {
|
||||
for (AbilityModifierAction action : modifier.onRemoved) {
|
||||
if (action.$type.contains("HealHP")) {
|
||||
action.type = AbilityModifierActionType.HealHP;
|
||||
modifierEntry.getOnRemoved().add(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameData.getAbilityModifiers().put(modifierEntry.getName(), modifierEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadSpawnData() {
|
||||
List<SpawnGroupEntry> spawnEntryList = null;
|
||||
|
||||
// Read from cached file if exists
|
||||
try(InputStream spawnDataEntries = DataLoader.load("Spawns.json")) {
|
||||
spawnEntryList = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(spawnDataEntries), TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType());
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
if (spawnEntryList == null || spawnEntryList.isEmpty()) {
|
||||
Grasscutter.getLogger().error("No spawn data loaded!");
|
||||
@ -264,31 +333,26 @@ public class ResourceLoader {
|
||||
}
|
||||
|
||||
for (SpawnGroupEntry entry : spawnEntryList) {
|
||||
entry.getSpawns().stream().forEach(s -> {
|
||||
s.setGroup(entry);
|
||||
});
|
||||
entry.getSpawns().forEach(s -> s.setGroup(entry));
|
||||
GameDepot.getSpawnListById(entry.getSceneId()).insert(entry, entry.getPos().getX(), entry.getPos().getZ());
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadOpenConfig() {
|
||||
// Read from cached file if exists
|
||||
File openConfigCache = new File(Grasscutter.getConfig().DATA_FOLDER + "OpenConfig.json");
|
||||
List<OpenConfigEntry> list = null;
|
||||
|
||||
if (openConfigCache.exists()) {
|
||||
try (FileReader fileReader = new FileReader(openConfigCache)) {
|
||||
list = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, OpenConfigEntry.class).getType());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
|
||||
try(InputStream openConfigCache = DataLoader.load("OpenConfig.json", false)) {
|
||||
list = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(openConfigCache), TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType());
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
if (list == null) {
|
||||
Map<String, OpenConfigEntry> map = new TreeMap<>();
|
||||
java.lang.reflect.Type type = new TypeToken<Map<String, OpenConfigData[]>>() {}.getType();
|
||||
String[] folderNames = {"BinOutput/Talent/EquipTalents/", "BinOutput/Talent/AvatarTalents/"};
|
||||
|
||||
for (String name : folderNames) {
|
||||
File folder = new File(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + name));
|
||||
File folder = new File(Utils.toFilePath(RESOURCE(name)));
|
||||
File[] files = folder.listFiles();
|
||||
if(files == null) {
|
||||
Grasscutter.getLogger().error("Error loading open config: no files found in " + folder.getAbsolutePath()); return;
|
||||
@ -327,6 +391,29 @@ public class ResourceLoader {
|
||||
GameData.getOpenConfigEntries().put(entry.getName(), entry);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadQuests() {
|
||||
File folder = new File(RESOURCE("BinOutput/Quest/"));
|
||||
|
||||
if (!folder.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : folder.listFiles()) {
|
||||
MainQuestData mainQuest = null;
|
||||
|
||||
try (FileReader fileReader = new FileReader(file)) {
|
||||
mainQuest = Grasscutter.getGsonFactory().fromJson(fileReader, MainQuestData.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest);
|
||||
}
|
||||
|
||||
Grasscutter.getLogger().info("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas.");
|
||||
}
|
||||
|
||||
// BinOutput configs
|
||||
|
||||
@ -348,8 +435,14 @@ public class ResourceLoader {
|
||||
public static class OpenConfigData {
|
||||
public String $type;
|
||||
public String abilityName;
|
||||
|
||||
@SerializedName(value="talentIndex", alternate={"OJOFFKLNAHN"})
|
||||
public int talentIndex;
|
||||
|
||||
@SerializedName(value="skillID", alternate={"overtime"})
|
||||
public int skillID;
|
||||
|
||||
@SerializedName(value="pointDelta", alternate={"IGEBKIHPOIF"})
|
||||
public int pointDelta;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package emu.grasscutter.data.custom;
|
||||
package emu.grasscutter.data.binout;
|
||||
|
||||
public class AbilityEmbryoEntry {
|
||||
private String name;
|
@ -0,0 +1,36 @@
|
||||
package emu.grasscutter.data.binout;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class AbilityModifier {
|
||||
public AbilityModifierAction[] onAdded;
|
||||
public AbilityModifierAction[] onThinkInterval;
|
||||
public AbilityModifierAction[] onRemoved;
|
||||
|
||||
public static class AbilityConfigData {
|
||||
public AbilityData Default;
|
||||
}
|
||||
|
||||
public static class AbilityData {
|
||||
public String abilityName;
|
||||
public Map<String, AbilityModifier> modifiers;
|
||||
}
|
||||
|
||||
public static class AbilityModifierAction {
|
||||
public String $type;
|
||||
public AbilityModifierActionType type;
|
||||
public String target;
|
||||
public AbilityModifierValue amount;
|
||||
public AbilityModifierValue amountByTargetCurrentHPRatio;
|
||||
}
|
||||
|
||||
public static class AbilityModifierValue {
|
||||
public boolean isFormula;
|
||||
public boolean isDynamic;
|
||||
public String dynamicKey;
|
||||
}
|
||||
|
||||
public enum AbilityModifierActionType {
|
||||
HealHP, ApplyModifier, LoseHP;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package emu.grasscutter.data.binout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
|
||||
|
||||
public class AbilityModifierEntry {
|
||||
private String name; // Custom value
|
||||
public List<AbilityModifierAction> onModifierAdded;
|
||||
public List<AbilityModifierAction> onThinkInterval;
|
||||
public List<AbilityModifierAction> onRemoved;
|
||||
|
||||
public AbilityModifierEntry(String name) {
|
||||
this.name = name;
|
||||
this.onModifierAdded = new ArrayList<>();
|
||||
this.onThinkInterval = new ArrayList<>();
|
||||
this.onRemoved = new ArrayList<>();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<AbilityModifierAction> getOnAdded() {
|
||||
return onModifierAdded;
|
||||
}
|
||||
|
||||
public List<AbilityModifierAction> getOnThinkInterval() {
|
||||
return onThinkInterval;
|
||||
}
|
||||
|
||||
public List<AbilityModifierAction> getOnRemoved() {
|
||||
return onRemoved;
|
||||
}
|
||||
|
||||
}
|
53
src/main/java/emu/grasscutter/data/binout/MainQuestData.java
Normal file
53
src/main/java/emu/grasscutter/data/binout/MainQuestData.java
Normal file
@ -0,0 +1,53 @@
|
||||
package emu.grasscutter.data.binout;
|
||||
|
||||
import emu.grasscutter.game.quest.enums.LogicType;
|
||||
import emu.grasscutter.game.quest.enums.QuestTrigger;
|
||||
import emu.grasscutter.game.quest.enums.QuestType;
|
||||
|
||||
public class MainQuestData {
|
||||
private int id;
|
||||
private int series;
|
||||
private QuestType type;
|
||||
|
||||
private long titleTextMapHash;
|
||||
private int[] suggestTrackMainQuestList;
|
||||
private int[] rewardIdList;
|
||||
|
||||
private SubQuestData[] subQuests;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getSeries() {
|
||||
return series;
|
||||
}
|
||||
|
||||
public QuestType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public long getTitleTextMapHash() {
|
||||
return titleTextMapHash;
|
||||
}
|
||||
|
||||
public int[] getSuggestTrackMainQuestList() {
|
||||
return suggestTrackMainQuestList;
|
||||
}
|
||||
|
||||
public int[] getRewardIdList() {
|
||||
return rewardIdList;
|
||||
}
|
||||
|
||||
public SubQuestData[] getSubQuests() {
|
||||
return subQuests;
|
||||
}
|
||||
|
||||
public static class SubQuestData {
|
||||
private int subId;
|
||||
|
||||
public int getSubId() {
|
||||
return subId;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package emu.grasscutter.data.custom;
|
||||
package emu.grasscutter.data.binout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
@ -1,21 +1,21 @@
|
||||
package emu.grasscutter.data.custom;
|
||||
|
||||
import emu.grasscutter.data.common.PointData;
|
||||
|
||||
public class ScenePointEntry {
|
||||
private String name;
|
||||
private PointData pointData;
|
||||
|
||||
public ScenePointEntry(String name, PointData pointData) {
|
||||
this.name = name;
|
||||
this.pointData = pointData;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public PointData getPointData() {
|
||||
return pointData;
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.data.binout;
|
||||
|
||||
import emu.grasscutter.data.common.PointData;
|
||||
|
||||
public class ScenePointEntry {
|
||||
private String name;
|
||||
private PointData pointData;
|
||||
|
||||
public ScenePointEntry(String name, PointData pointData) {
|
||||
this.name = name;
|
||||
this.pointData = pointData;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public PointData getPointData() {
|
||||
return pointData;
|
||||
}
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
public class CurveInfo {
|
||||
private String Type;
|
||||
private String Arith;
|
||||
private float Value;
|
||||
private String type;
|
||||
private String arith;
|
||||
private float value;
|
||||
|
||||
public String getType() {
|
||||
return Type;
|
||||
return type;
|
||||
}
|
||||
public String getArith() {
|
||||
return Arith;
|
||||
return arith;
|
||||
}
|
||||
public float getValue() {
|
||||
return Value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,16 @@ package emu.grasscutter.data.common;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
|
||||
public class FightPropData {
|
||||
private String PropType;
|
||||
private String propType;
|
||||
private FightProperty prop;
|
||||
private float Value;
|
||||
private float value;
|
||||
|
||||
public String getPropType() {
|
||||
return PropType;
|
||||
return propType;
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
return Value;
|
||||
return value;
|
||||
}
|
||||
|
||||
public FightProperty getProp() {
|
||||
@ -20,6 +20,6 @@ public class FightPropData {
|
||||
}
|
||||
|
||||
public void onLoad() {
|
||||
this.prop = FightProperty.getPropByName(PropType);
|
||||
this.prop = FightProperty.getPropByName(propType);
|
||||
}
|
||||
}
|
@ -1,20 +1,33 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class ItemParamData {
|
||||
private int Id;
|
||||
private int Count;
|
||||
@SerializedName(value="id", alternate={"itemId"})
|
||||
private int id;
|
||||
|
||||
@SerializedName(value="count", alternate={"itemCount"})
|
||||
private int count;
|
||||
|
||||
public ItemParamData() {}
|
||||
public ItemParamData(int id, int count) {
|
||||
this.Id = id;
|
||||
this.Count = count;
|
||||
this.id = id;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return Id;
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getItemId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return Count;
|
||||
return count;
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,26 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
public class ItemParamStringData {
|
||||
private int Id;
|
||||
private String Count;
|
||||
private int id;
|
||||
private String count;
|
||||
|
||||
public ItemParamStringData() {}
|
||||
|
||||
public int getId() {
|
||||
return Id;
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getCount() {
|
||||
return Count;
|
||||
return count;
|
||||
}
|
||||
|
||||
public ItemParamData toItemParamData() {
|
||||
if (Count.contains(";")) {
|
||||
String[] split = Count.split(";");
|
||||
Count = Count.split(";")[split.length - 1];
|
||||
} else if (Count.contains(".")) {
|
||||
return new ItemParamData(Id, (int) Math.ceil(Double.parseDouble(Count)));
|
||||
if (count.contains(";")) {
|
||||
String[] split = count.split(";");
|
||||
count = count.split(";")[split.length - 1];
|
||||
} else if (count.contains(".")) {
|
||||
return new ItemParamData(id, (int) Math.ceil(Double.parseDouble(count)));
|
||||
}
|
||||
return new ItemParamData(Id, Integer.parseInt(Count));
|
||||
return new ItemParamData(id, Integer.parseInt(count));
|
||||
}
|
||||
}
|
||||
|
24
src/main/java/emu/grasscutter/data/common/ItemUseData.java
Normal file
24
src/main/java/emu/grasscutter/data/common/ItemUseData.java
Normal file
@ -0,0 +1,24 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ItemUseData {
|
||||
private String useOp;
|
||||
private List<String> useParam;
|
||||
|
||||
public String getUseOp() {
|
||||
return useOp;
|
||||
}
|
||||
|
||||
public void setUseOp(String useOp) {
|
||||
this.useOp = useOp;
|
||||
}
|
||||
|
||||
public List<String> getUseParam() {
|
||||
return useParam;
|
||||
}
|
||||
|
||||
public void setUseParam(List<String> useParam) {
|
||||
this.useParam = useParam;
|
||||
}
|
||||
}
|
@ -3,22 +3,22 @@ package emu.grasscutter.data.common;
|
||||
import java.util.List;
|
||||
|
||||
public class OpenCondData {
|
||||
private String CondType;
|
||||
private List<Integer> ParamList;
|
||||
private String condType;
|
||||
private List<Integer> paramList;
|
||||
|
||||
public String getCondType() {
|
||||
return CondType;
|
||||
return condType;
|
||||
}
|
||||
|
||||
public void setCondType(String condType) {
|
||||
CondType = condType;
|
||||
condType = condType;
|
||||
}
|
||||
|
||||
public List<Integer> getParamList() {
|
||||
return ParamList;
|
||||
return paramList;
|
||||
}
|
||||
|
||||
public void setParamList(List<Integer> paramList) {
|
||||
ParamList = paramList;
|
||||
paramList = paramList;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.DailyDungeonData;
|
||||
import emu.grasscutter.data.excels.DailyDungeonData;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
@ -11,7 +13,11 @@ public class PointData {
|
||||
private int id;
|
||||
private String $type;
|
||||
private Position tranPos;
|
||||
|
||||
@SerializedName(value="dungeonIds", alternate={"JHHFPGJNMIN"})
|
||||
private int[] dungeonIds;
|
||||
|
||||
@SerializedName(value="dungeonRandomList", alternate={"OIBKFJNBLHO"})
|
||||
private int[] dungeonRandomList;
|
||||
|
||||
private int tranSceneId;
|
||||
|
@ -1,13 +1,15 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
public class PropGrowCurve {
|
||||
private String Type;
|
||||
private String GrowCurve;
|
||||
private String type;
|
||||
private String growCurve;
|
||||
|
||||
public String getType(){
|
||||
return this.Type;
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public String getGrowCurve(){
|
||||
return this.GrowCurve;
|
||||
return this.growCurve;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
public class RewardItemData {
|
||||
private int ItemId;
|
||||
private int ItemCount;
|
||||
|
||||
public int getItemId() {
|
||||
return ItemId;
|
||||
}
|
||||
|
||||
public void setItemId(int itemId) {
|
||||
ItemId = itemId;
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return ItemCount;
|
||||
}
|
||||
|
||||
public void setItemCount(int itemCount) {
|
||||
ItemCount = itemCount;
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||
|
||||
@ResourceType(name = "AvatarSkillExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)
|
||||
public class AvatarSkillData extends GameResource {
|
||||
private int Id;
|
||||
private float CdTime;
|
||||
private int CostElemVal;
|
||||
private int MaxChargeNum;
|
||||
private int TriggerID;
|
||||
private boolean IsAttackCameraLock;
|
||||
private int ProudSkillGroupId;
|
||||
private String CostElemType;
|
||||
private List<Float> LockWeightParams;
|
||||
|
||||
private long NameTextMapHash;
|
||||
|
||||
private String AbilityName;
|
||||
private String LockShape;
|
||||
private String GlobalValueKey;
|
||||
|
||||
@Override
|
||||
public int getId(){
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public float getCdTime() {
|
||||
return CdTime;
|
||||
}
|
||||
|
||||
public int getCostElemVal() {
|
||||
return CostElemVal;
|
||||
}
|
||||
|
||||
public int getMaxChargeNum() {
|
||||
return MaxChargeNum;
|
||||
}
|
||||
|
||||
public int getTriggerID() {
|
||||
return TriggerID;
|
||||
}
|
||||
|
||||
public boolean isIsAttackCameraLock() {
|
||||
return IsAttackCameraLock;
|
||||
}
|
||||
|
||||
public int getProudSkillGroupId() {
|
||||
return ProudSkillGroupId;
|
||||
}
|
||||
|
||||
public String getCostElemType() {
|
||||
return CostElemType;
|
||||
}
|
||||
|
||||
public List<Float> getLockWeightParams() {
|
||||
return LockWeightParams;
|
||||
}
|
||||
|
||||
public long getNameTextMapHash() {
|
||||
return NameTextMapHash;
|
||||
}
|
||||
|
||||
public String getAbilityName() {
|
||||
return AbilityName;
|
||||
}
|
||||
|
||||
public String getLockShape() {
|
||||
return LockShape;
|
||||
}
|
||||
|
||||
public String getGlobalValueKey() {
|
||||
return GlobalValueKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ResourceType(name = "CombineExcelConfigData.json")
|
||||
public class CombineData extends GameResource {
|
||||
|
||||
private int CombineId;
|
||||
|
||||
private int PlayerLevel;
|
||||
|
||||
private boolean IsDefaultShow;
|
||||
|
||||
private int CombineType;
|
||||
|
||||
private int SubCombineType;
|
||||
|
||||
private int ResultItemId;
|
||||
|
||||
private int ResultItemCount;
|
||||
|
||||
private int ScoinCost;
|
||||
|
||||
private List<CombineItemPair> RandomItems;
|
||||
|
||||
private List<CombineItemPair> MaterialItems;
|
||||
|
||||
private long EffectDescTextMapHash;
|
||||
|
||||
private String RecipeType;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.CombineId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
super.onLoad();
|
||||
// clean data
|
||||
RandomItems = RandomItems.stream().filter(item -> item.Id > 0).collect(Collectors.toList());
|
||||
MaterialItems = MaterialItems.stream().filter(item -> item.Id > 0).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static class CombineItemPair {
|
||||
|
||||
private int Id;
|
||||
|
||||
private int Count;
|
||||
|
||||
public CombineItemPair(int id, int count) {
|
||||
Id = id;
|
||||
Count = count;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return Count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
Count = count;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCombineId() {
|
||||
return CombineId;
|
||||
}
|
||||
|
||||
public void setCombineId(int combineId) {
|
||||
CombineId = combineId;
|
||||
}
|
||||
|
||||
public int getPlayerLevel() {
|
||||
return PlayerLevel;
|
||||
}
|
||||
|
||||
public void setPlayerLevel(int playerLevel) {
|
||||
PlayerLevel = playerLevel;
|
||||
}
|
||||
|
||||
public boolean isDefaultShow() {
|
||||
return IsDefaultShow;
|
||||
}
|
||||
|
||||
public void setDefaultShow(boolean defaultShow) {
|
||||
IsDefaultShow = defaultShow;
|
||||
}
|
||||
|
||||
public int getCombineType() {
|
||||
return CombineType;
|
||||
}
|
||||
|
||||
public void setCombineType(int combineType) {
|
||||
CombineType = combineType;
|
||||
}
|
||||
|
||||
public int getSubCombineType() {
|
||||
return SubCombineType;
|
||||
}
|
||||
|
||||
public void setSubCombineType(int subCombineType) {
|
||||
SubCombineType = subCombineType;
|
||||
}
|
||||
|
||||
public int getResultItemId() {
|
||||
return ResultItemId;
|
||||
}
|
||||
|
||||
public void setResultItemId(int resultItemId) {
|
||||
ResultItemId = resultItemId;
|
||||
}
|
||||
|
||||
public int getResultItemCount() {
|
||||
return ResultItemCount;
|
||||
}
|
||||
|
||||
public void setResultItemCount(int resultItemCount) {
|
||||
ResultItemCount = resultItemCount;
|
||||
}
|
||||
|
||||
public int getScoinCost() {
|
||||
return ScoinCost;
|
||||
}
|
||||
|
||||
public void setScoinCost(int scoinCost) {
|
||||
ScoinCost = scoinCost;
|
||||
}
|
||||
|
||||
public List<CombineItemPair> getRandomItems() {
|
||||
return RandomItems;
|
||||
}
|
||||
|
||||
public void setRandomItems(List<CombineItemPair> randomItems) {
|
||||
RandomItems = randomItems;
|
||||
}
|
||||
|
||||
public List<CombineItemPair> getMaterialItems() {
|
||||
return MaterialItems;
|
||||
}
|
||||
|
||||
public void setMaterialItems(List<CombineItemPair> materialItems) {
|
||||
MaterialItems = materialItems;
|
||||
}
|
||||
|
||||
public long getEffectDescTextMapHash() {
|
||||
return EffectDescTextMapHash;
|
||||
}
|
||||
|
||||
public void setEffectDescTextMapHash(long effectDescTextMapHash) {
|
||||
EffectDescTextMapHash = effectDescTextMapHash;
|
||||
}
|
||||
|
||||
public String getRecipeType() {
|
||||
return RecipeType;
|
||||
}
|
||||
|
||||
public void setRecipeType(String recipeType) {
|
||||
RecipeType = recipeType;
|
||||
}
|
||||
}
|
||||
|
@ -1,258 +0,0 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
@ResourceType(name = {"MaterialExcelConfigData.json", "WeaponExcelConfigData.json", "ReliquaryExcelConfigData.json"})
|
||||
public class ItemData extends GameResource {
|
||||
|
||||
private int Id;
|
||||
private int StackLimit = 1;
|
||||
private int MaxUseCount;
|
||||
private int RankLevel;
|
||||
private String EffectName;
|
||||
private int[] SatiationParams;
|
||||
private int Rank;
|
||||
private int Weight;
|
||||
private int GadgetId;
|
||||
|
||||
private int[] DestroyReturnMaterial;
|
||||
private int[] DestroyReturnMaterialCount;
|
||||
|
||||
// Food
|
||||
private String FoodQuality;
|
||||
private String UseTarget;
|
||||
private String[] UseParam;
|
||||
|
||||
// String enums
|
||||
private String ItemType;
|
||||
private String MaterialType;
|
||||
private String EquipType;
|
||||
private String EffectType;
|
||||
private String DestroyRule;
|
||||
|
||||
// Relic
|
||||
private int MainPropDepotId;
|
||||
private int AppendPropDepotId;
|
||||
private int AppendPropNum;
|
||||
private int SetId;
|
||||
private int[] AddPropLevels;
|
||||
private int BaseConvExp;
|
||||
private int MaxLevel;
|
||||
|
||||
// Weapon
|
||||
private int WeaponPromoteId;
|
||||
private int WeaponBaseExp;
|
||||
private int StoryId;
|
||||
private int AvatarPromoteId;
|
||||
private int AwakenMaterial;
|
||||
private int[] AwakenCosts;
|
||||
private int[] SkillAffix;
|
||||
private WeaponProperty[] WeaponProp;
|
||||
|
||||
// Hash
|
||||
private String Icon;
|
||||
private long NameTextMapHash;
|
||||
|
||||
// Post load
|
||||
private transient emu.grasscutter.game.inventory.MaterialType materialType;
|
||||
private transient emu.grasscutter.game.inventory.ItemType itemType;
|
||||
private transient emu.grasscutter.game.inventory.EquipType equipType;
|
||||
|
||||
private IntSet addPropLevelSet;
|
||||
|
||||
@Override
|
||||
public int getId(){
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public String getMaterialTypeString(){
|
||||
return this.MaterialType;
|
||||
}
|
||||
|
||||
public int getStackLimit(){
|
||||
return this.StackLimit;
|
||||
}
|
||||
|
||||
public int getMaxUseCount(){
|
||||
return this.MaxUseCount;
|
||||
}
|
||||
|
||||
public String getUseTarget(){
|
||||
return this.UseTarget;
|
||||
}
|
||||
|
||||
public String[] getUseParam(){
|
||||
return this.UseParam;
|
||||
}
|
||||
|
||||
public int getRankLevel(){
|
||||
return this.RankLevel;
|
||||
}
|
||||
|
||||
public String getFoodQuality(){
|
||||
return this.FoodQuality;
|
||||
}
|
||||
|
||||
public String getEffectName(){
|
||||
return this.EffectName;
|
||||
}
|
||||
|
||||
public int[] getSatiationParams(){
|
||||
return this.SatiationParams;
|
||||
}
|
||||
|
||||
public int[] getDestroyReturnMaterial(){
|
||||
return this.DestroyReturnMaterial;
|
||||
}
|
||||
|
||||
public int[] getDestroyReturnMaterialCount(){
|
||||
return this.DestroyReturnMaterialCount;
|
||||
}
|
||||
|
||||
public long getNameTextMapHash(){
|
||||
return this.NameTextMapHash;
|
||||
}
|
||||
|
||||
public String getIcon(){
|
||||
return this.Icon;
|
||||
}
|
||||
|
||||
public String getItemTypeString(){
|
||||
return this.ItemType;
|
||||
}
|
||||
|
||||
public int getRank(){
|
||||
return this.Rank;
|
||||
}
|
||||
|
||||
public int getGadgetId() {
|
||||
return GadgetId;
|
||||
}
|
||||
|
||||
public int getBaseConvExp() {
|
||||
return BaseConvExp;
|
||||
}
|
||||
|
||||
public int getMainPropDepotId() {
|
||||
return MainPropDepotId;
|
||||
}
|
||||
|
||||
public int getAppendPropDepotId() {
|
||||
return AppendPropDepotId;
|
||||
}
|
||||
|
||||
public int getAppendPropNum() {
|
||||
return AppendPropNum;
|
||||
}
|
||||
|
||||
public int getSetId() {
|
||||
return SetId;
|
||||
}
|
||||
|
||||
public int getWeaponPromoteId() {
|
||||
return WeaponPromoteId;
|
||||
}
|
||||
|
||||
public int getWeaponBaseExp() {
|
||||
return WeaponBaseExp;
|
||||
}
|
||||
|
||||
public int getAwakenMaterial() {
|
||||
return AwakenMaterial;
|
||||
}
|
||||
|
||||
public int[] getAwakenCosts() {
|
||||
return AwakenCosts;
|
||||
}
|
||||
|
||||
public IntSet getAddPropLevelSet() {
|
||||
return addPropLevelSet;
|
||||
}
|
||||
|
||||
public int[] getSkillAffix() {
|
||||
return SkillAffix;
|
||||
}
|
||||
|
||||
public WeaponProperty[] getWeaponProperties() {
|
||||
return WeaponProp;
|
||||
}
|
||||
|
||||
public int getMaxLevel() {
|
||||
return MaxLevel;
|
||||
}
|
||||
|
||||
public emu.grasscutter.game.inventory.ItemType getItemType() {
|
||||
return this.itemType;
|
||||
}
|
||||
|
||||
public emu.grasscutter.game.inventory.MaterialType getMaterialType() {
|
||||
return this.materialType;
|
||||
}
|
||||
|
||||
public emu.grasscutter.game.inventory.EquipType getEquipType() {
|
||||
return this.equipType;
|
||||
}
|
||||
|
||||
public boolean canAddRelicProp(int level) {
|
||||
return this.addPropLevelSet != null & this.addPropLevelSet.contains(level);
|
||||
}
|
||||
|
||||
public boolean isEquip() {
|
||||
return this.itemType == emu.grasscutter.game.inventory.ItemType.ITEM_RELIQUARY || this.itemType == emu.grasscutter.game.inventory.ItemType.ITEM_WEAPON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.itemType = emu.grasscutter.game.inventory.ItemType.getTypeByName(getItemTypeString());
|
||||
this.materialType = emu.grasscutter.game.inventory.MaterialType.getTypeByName(getMaterialTypeString());
|
||||
|
||||
if (this.itemType == emu.grasscutter.game.inventory.ItemType.ITEM_RELIQUARY) {
|
||||
this.equipType = emu.grasscutter.game.inventory.EquipType.getTypeByName(this.EquipType);
|
||||
if (this.AddPropLevels != null && this.AddPropLevels.length > 0) {
|
||||
this.addPropLevelSet = new IntOpenHashSet(this.AddPropLevels);
|
||||
}
|
||||
} else if (this.itemType == emu.grasscutter.game.inventory.ItemType.ITEM_WEAPON) {
|
||||
this.equipType = emu.grasscutter.game.inventory.EquipType.EQUIP_WEAPON;
|
||||
} else {
|
||||
this.equipType = emu.grasscutter.game.inventory.EquipType.EQUIP_NONE;
|
||||
}
|
||||
|
||||
if (this.getWeaponProperties() != null) {
|
||||
for (WeaponProperty weaponProperty : this.getWeaponProperties()) {
|
||||
weaponProperty.onLoad();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class WeaponProperty {
|
||||
private FightProperty fightProp;
|
||||
private String PropType;
|
||||
private float InitValue;
|
||||
private String Type;
|
||||
|
||||
public String getPropType(){
|
||||
return this.PropType;
|
||||
}
|
||||
|
||||
public float getInitValue(){
|
||||
return this.InitValue;
|
||||
}
|
||||
|
||||
public String getType(){
|
||||
return this.Type;
|
||||
}
|
||||
|
||||
public FightProperty getFightProp() {
|
||||
return fightProp;
|
||||
}
|
||||
|
||||
public void onLoad() {
|
||||
this.fightProp = FightProperty.getPropByName(PropType);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.common.RewardItemData;
|
||||
|
||||
@ResourceType(name = "RewardExcelConfigData.json")
|
||||
public class RewardData extends GameResource {
|
||||
public int RewardId;
|
||||
public List<RewardItemData> RewardItemList;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return RewardId;
|
||||
}
|
||||
|
||||
public List<RewardItemData> getRewardItemList() {
|
||||
return RewardItemList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
@ResourceType(name = "TowerFloorExcelConfigData.json")
|
||||
public class TowerFloorData extends GameResource {
|
||||
|
||||
private int FloorId;
|
||||
private int FloorIndex;
|
||||
private int LevelId;
|
||||
private int OverrideMonsterLevel;
|
||||
private int TeamNum;
|
||||
private int FloorLevelConfigId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.FloorId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
super.onLoad();
|
||||
}
|
||||
|
||||
public int getFloorId() {
|
||||
return FloorId;
|
||||
}
|
||||
|
||||
public void setFloorId(int floorId) {
|
||||
FloorId = floorId;
|
||||
}
|
||||
|
||||
public int getFloorIndex() {
|
||||
return FloorIndex;
|
||||
}
|
||||
|
||||
public void setFloorIndex(int floorIndex) {
|
||||
FloorIndex = floorIndex;
|
||||
}
|
||||
|
||||
public int getLevelId() {
|
||||
return LevelId;
|
||||
}
|
||||
|
||||
public void setLevelId(int levelId) {
|
||||
LevelId = levelId;
|
||||
}
|
||||
|
||||
public int getOverrideMonsterLevel() {
|
||||
return OverrideMonsterLevel;
|
||||
}
|
||||
|
||||
public void setOverrideMonsterLevel(int overrideMonsterLevel) {
|
||||
OverrideMonsterLevel = overrideMonsterLevel;
|
||||
}
|
||||
|
||||
public int getTeamNum() {
|
||||
return TeamNum;
|
||||
}
|
||||
|
||||
public void setTeamNum(int teamNum) {
|
||||
TeamNum = teamNum;
|
||||
}
|
||||
|
||||
public int getFloorLevelConfigId() {
|
||||
return FloorLevelConfigId;
|
||||
}
|
||||
|
||||
public void setFloorLevelConfigId(int floorLevelConfigId) {
|
||||
FloorLevelConfigId = floorLevelConfigId;
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
@ResourceType(name = "TowerLevelExcelConfigData.json")
|
||||
public class TowerLevelData extends GameResource {
|
||||
|
||||
private int ID;
|
||||
private int LevelId;
|
||||
private int LevelIndex;
|
||||
private int DungeonId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
super.onLoad();
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
public void setID(int ID) {
|
||||
this.ID = ID;
|
||||
}
|
||||
|
||||
public int getLevelId() {
|
||||
return LevelId;
|
||||
}
|
||||
|
||||
public void setLevelId(int levelId) {
|
||||
LevelId = levelId;
|
||||
}
|
||||
|
||||
public int getLevelIndex() {
|
||||
return LevelIndex;
|
||||
}
|
||||
|
||||
public void setLevelIndex(int levelIndex) {
|
||||
LevelIndex = levelIndex;
|
||||
}
|
||||
|
||||
public int getDungeonId() {
|
||||
return DungeonId;
|
||||
}
|
||||
|
||||
public void setDungeonId(int dungeonId) {
|
||||
DungeonId = dungeonId;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package emu.grasscutter.data.def;
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
@ -6,21 +6,21 @@ import emu.grasscutter.data.ResourceType;
|
||||
|
||||
@ResourceType(name = "AvatarCostumeExcelConfigData.json")
|
||||
public class AvatarCostumeData extends GameResource {
|
||||
private int CostumeId;
|
||||
private int ItemId;
|
||||
private int AvatarId;
|
||||
private int costumeId;
|
||||
private int itemId;
|
||||
private int avatarId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.CostumeId;
|
||||
return this.costumeId;
|
||||
}
|
||||
|
||||
public int getItemId() {
|
||||
return this.ItemId;
|
||||
return this.itemId;
|
||||
}
|
||||
|
||||
public int getAvatarId() {
|
||||
return AvatarId;
|
||||
return avatarId;
|
||||
}
|
||||
|
||||
@Override
|
@ -1,4 +1,4 @@
|
||||
package emu.grasscutter.data.def;
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -10,27 +10,27 @@ import emu.grasscutter.data.common.CurveInfo;
|
||||
|
||||
@ResourceType(name = "AvatarCurveExcelConfigData.json")
|
||||
public class AvatarCurveData extends GameResource {
|
||||
private int Level;
|
||||
private CurveInfo[] CurveInfos;
|
||||
private int level;
|
||||
private CurveInfo[] curveInfos;
|
||||
|
||||
private Map<String, Float> curveInfos;
|
||||
private Map<String, Float> curveInfoMap;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.Level;
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return Level;
|
||||
return level;
|
||||
}
|
||||
|
||||
public Map<String, Float> getCurveInfos() {
|
||||
return curveInfos;
|
||||
return curveInfoMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.curveInfos = new HashMap<>();
|
||||
Stream.of(this.CurveInfos).forEach(info -> this.curveInfos.put(info.getType(), info.getValue()));
|
||||
this.curveInfoMap = new HashMap<>();
|
||||
Stream.of(this.curveInfos).forEach(info -> this.curveInfoMap.put(info.getType(), info.getValue()));
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package emu.grasscutter.data.def;
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -6,9 +6,10 @@ import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||
import emu.grasscutter.data.binout.AbilityEmbryoEntry;
|
||||
import emu.grasscutter.data.common.PropGrowCurve;
|
||||
import emu.grasscutter.data.custom.AbilityEmbryoEntry;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.WeaponType;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
@ -17,38 +18,36 @@ import it.unimi.dsi.fastutil.ints.IntList;
|
||||
@ResourceType(name = "AvatarExcelConfigData.json", loadPriority = LoadPriority.LOW)
|
||||
public class AvatarData extends GameResource {
|
||||
|
||||
private String name;
|
||||
private String IconName;
|
||||
private String BodyType;
|
||||
private String QualityType;
|
||||
private int ChargeEfficiency;
|
||||
private int InitialWeapon;
|
||||
private String WeaponType;
|
||||
private String ImageName;
|
||||
private int AvatarPromoteId;
|
||||
private String CutsceneShow;
|
||||
private int SkillDepotId;
|
||||
private int StaminaRecoverSpeed;
|
||||
private List<String> CandSkillDepotIds;
|
||||
private long DescTextMapHash;
|
||||
private String AvatarIdentityType;
|
||||
private List<Integer> AvatarPromoteRewardLevelList;
|
||||
private List<Integer> AvatarPromoteRewardIdList;
|
||||
private int FeatureTagGroupID;
|
||||
|
||||
private long NameTextMapHash;
|
||||
private long GachaImageNameHashSuffix;
|
||||
private long InfoDescTextMapHash;
|
||||
|
||||
private float HpBase;
|
||||
private float AttackBase;
|
||||
private float DefenseBase;
|
||||
private float Critical;
|
||||
private float CriticalHurt;
|
||||
private String iconName;
|
||||
private String bodyType;
|
||||
private String qualityType;
|
||||
private int chargeEfficiency;
|
||||
private int initialWeapon;
|
||||
private WeaponType weaponType;
|
||||
private String imageName;
|
||||
private int avatarPromoteId;
|
||||
private String cutsceneShow;
|
||||
private int skillDepotId;
|
||||
private int staminaRecoverSpeed;
|
||||
private List<String> candSkillDepotIds;
|
||||
private String avatarIdentityType;
|
||||
private List<Integer> avatarPromoteRewardLevelList;
|
||||
private List<Integer> avatarPromoteRewardIdList;
|
||||
|
||||
private List<PropGrowCurve> PropGrowCurves;
|
||||
private int Id;
|
||||
private long nameTextMapHash;
|
||||
|
||||
private float hpBase;
|
||||
private float attackBase;
|
||||
private float defenseBase;
|
||||
private float critical;
|
||||
private float criticalHurt;
|
||||
|
||||
private List<PropGrowCurve> propGrowCurves;
|
||||
private int id;
|
||||
|
||||
// Transient
|
||||
private String name;
|
||||
|
||||
private Int2ObjectMap<String> growthCurveMap;
|
||||
private float[] hpGrowthCurve;
|
||||
private float[] attackGrowthCurve;
|
||||
@ -58,11 +57,11 @@ public class AvatarData extends GameResource {
|
||||
|
||||
private List<Integer> fetters;
|
||||
private int nameCardRewardId;
|
||||
private int nameCardId;
|
||||
private int nameCardId;
|
||||
|
||||
@Override
|
||||
public int getId(){
|
||||
return this.Id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@ -70,107 +69,91 @@ public class AvatarData extends GameResource {
|
||||
}
|
||||
|
||||
public String getBodyType(){
|
||||
return this.BodyType;
|
||||
return this.bodyType;
|
||||
}
|
||||
|
||||
public String getQualityType(){
|
||||
return this.QualityType;
|
||||
return this.qualityType;
|
||||
}
|
||||
|
||||
public int getChargeEfficiency(){
|
||||
return this.ChargeEfficiency;
|
||||
return this.chargeEfficiency;
|
||||
}
|
||||
|
||||
public int getInitialWeapon(){
|
||||
return this.InitialWeapon;
|
||||
return this.initialWeapon;
|
||||
}
|
||||
|
||||
public String getWeaponType(){
|
||||
return this.WeaponType;
|
||||
public WeaponType getWeaponType(){
|
||||
return this.weaponType;
|
||||
}
|
||||
|
||||
public String getImageName(){
|
||||
return this.ImageName;
|
||||
return this.imageName;
|
||||
}
|
||||
|
||||
public int getAvatarPromoteId(){
|
||||
return this.AvatarPromoteId;
|
||||
}
|
||||
|
||||
public long getGachaImageNameHashSuffix(){
|
||||
return this.GachaImageNameHashSuffix;
|
||||
return this.avatarPromoteId;
|
||||
}
|
||||
|
||||
public String getCutsceneShow(){
|
||||
return this.CutsceneShow;
|
||||
return this.cutsceneShow;
|
||||
}
|
||||
|
||||
public int getSkillDepotId(){
|
||||
return this.SkillDepotId;
|
||||
return this.skillDepotId;
|
||||
}
|
||||
|
||||
public int getStaminaRecoverSpeed(){
|
||||
return this.StaminaRecoverSpeed;
|
||||
return this.staminaRecoverSpeed;
|
||||
}
|
||||
|
||||
public List<String> getCandSkillDepotIds(){
|
||||
return this.CandSkillDepotIds;
|
||||
return this.candSkillDepotIds;
|
||||
}
|
||||
|
||||
public long getDescTextMapHash(){
|
||||
return this.DescTextMapHash;
|
||||
}
|
||||
|
||||
|
||||
public String getAvatarIdentityType(){
|
||||
return this.AvatarIdentityType;
|
||||
return this.avatarIdentityType;
|
||||
}
|
||||
|
||||
public List<Integer> getAvatarPromoteRewardLevelList(){
|
||||
return this.AvatarPromoteRewardLevelList;
|
||||
return this.avatarPromoteRewardLevelList;
|
||||
}
|
||||
|
||||
public List<Integer> getAvatarPromoteRewardIdList(){
|
||||
return this.AvatarPromoteRewardIdList;
|
||||
return this.avatarPromoteRewardIdList;
|
||||
}
|
||||
|
||||
public int getFeatureTagGroupID(){
|
||||
return this.FeatureTagGroupID;
|
||||
}
|
||||
|
||||
public long getInfoDescTextMapHash(){
|
||||
return this.InfoDescTextMapHash;
|
||||
}
|
||||
|
||||
public float getBaseHp(int level){
|
||||
try {
|
||||
return this.HpBase * this.hpGrowthCurve[level - 1];
|
||||
return this.hpBase * this.hpGrowthCurve[level - 1];
|
||||
} catch (Exception e) {
|
||||
return this.HpBase;
|
||||
return this.hpBase;
|
||||
}
|
||||
}
|
||||
|
||||
public float getBaseAttack(int level){
|
||||
try {
|
||||
return this.AttackBase * this.attackGrowthCurve[level - 1];
|
||||
return this.attackBase * this.attackGrowthCurve[level - 1];
|
||||
} catch (Exception e) {
|
||||
return this.AttackBase;
|
||||
return this.attackBase;
|
||||
}
|
||||
}
|
||||
|
||||
public float getBaseDefense(int level){
|
||||
try {
|
||||
return this.DefenseBase * this.defenseGrowthCurve[level - 1];
|
||||
return this.defenseBase * this.defenseGrowthCurve[level - 1];
|
||||
} catch (Exception e) {
|
||||
return this.DefenseBase;
|
||||
return this.defenseBase;
|
||||
}
|
||||
}
|
||||
|
||||
public float getBaseCritical(){
|
||||
return this.Critical;
|
||||
return this.critical;
|
||||
}
|
||||
|
||||
public float getBaseCriticalHurt(){
|
||||
return this.CriticalHurt;
|
||||
return this.criticalHurt;
|
||||
}
|
||||
|
||||
public float getGrowthCurveById(int level, FightProperty prop) {
|
||||
@ -186,7 +169,7 @@ public class AvatarData extends GameResource {
|
||||
}
|
||||
|
||||
public long getNameTextMapHash(){
|
||||
return this.NameTextMapHash;
|
||||
return this.nameTextMapHash;
|
||||
}
|
||||
|
||||
public AvatarSkillDepotData getSkillDepot() {
|
||||
@ -211,13 +194,13 @@ public class AvatarData extends GameResource {
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.skillDepot = GameData.getAvatarSkillDepotDataMap().get(this.SkillDepotId);
|
||||
this.skillDepot = GameData.getAvatarSkillDepotDataMap().get(this.skillDepotId);
|
||||
|
||||
// Get fetters from GameData
|
||||
this.fetters = GameData.getFetterDataEntries().get(this.Id);
|
||||
this.fetters = GameData.getFetterDataEntries().get(this.id);
|
||||
|
||||
if (GameData.getFetterCharacterCardDataMap().get(this.Id) != null) {
|
||||
this.nameCardRewardId = GameData.getFetterCharacterCardDataMap().get(this.Id).getRewardId();
|
||||
if (GameData.getFetterCharacterCardDataMap().get(this.id) != null) {
|
||||
this.nameCardRewardId = GameData.getFetterCharacterCardDataMap().get(this.id).getRewardId();
|
||||
}
|
||||
|
||||
if (GameData.getRewardDataMap().get(this.nameCardRewardId) != null) {
|
||||
@ -230,7 +213,7 @@ public class AvatarData extends GameResource {
|
||||
this.defenseGrowthCurve = new float[size];
|
||||
for (AvatarCurveData curveData : GameData.getAvatarCurveDataMap().values()) {
|
||||
int level = curveData.getLevel() - 1;
|
||||
for (PropGrowCurve growCurve : this.PropGrowCurves) {
|
||||
for (PropGrowCurve growCurve : this.propGrowCurves) {
|
||||
FightProperty prop = FightProperty.getPropByName(growCurve.getType());
|
||||
switch (prop) {
|
||||
case FIGHT_PROP_BASE_HP:
|
||||
@ -256,7 +239,7 @@ public class AvatarData extends GameResource {
|
||||
*/
|
||||
|
||||
// Cache abilities
|
||||
String[] split = this.IconName.split("_");
|
||||
String[] split = this.iconName.split("_");
|
||||
if (split.length > 0) {
|
||||
this.name = split[split.length - 1];
|
||||
|
@ -1,23 +1,23 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
@ResourceType(name = "AvatarFettersLevelExcelConfigData.json")
|
||||
public class AvatarFetterLevelData extends GameResource {
|
||||
private int FetterLevel;
|
||||
private int NeedExp;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.FetterLevel;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return FetterLevel;
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return NeedExp;
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
@ResourceType(name = "AvatarFettersLevelExcelConfigData.json")
|
||||
public class AvatarFetterLevelData extends GameResource {
|
||||
private int fetterLevel;
|
||||
private int needExp;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.fetterLevel;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return fetterLevel;
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return needExp;
|
||||
}
|
||||
}
|
@ -1,20 +1,20 @@
|
||||
package emu.grasscutter.data.def;
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
@ResourceType(name = "AvatarFlycloakExcelConfigData.json")
|
||||
public class AvatarFlycloakData extends GameResource {
|
||||
private int FlycloakId;
|
||||
private long NameTextMapHash;
|
||||
private int flycloakId;
|
||||
private long nameTextMapHash;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.FlycloakId;
|
||||
return this.flycloakId;
|
||||
}
|
||||
|
||||
public long getNameTextMapHash() {
|
||||
return NameTextMapHash;
|
||||
return nameTextMapHash;
|
||||
}
|
||||
|
||||
@Override
|
@ -1,23 +1,23 @@
|
||||
package emu.grasscutter.data.def;
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
@ResourceType(name = "AvatarLevelExcelConfigData.json")
|
||||
public class AvatarLevelData extends GameResource {
|
||||
private int Level;
|
||||
private int Exp;
|
||||
private int level;
|
||||
private int exp;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.Level;
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return Level;
|
||||
return level;
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return Exp;
|
||||
return exp;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package emu.grasscutter.data.def;
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
@ -9,45 +9,45 @@ import emu.grasscutter.data.common.ItemParamData;
|
||||
@ResourceType(name = "AvatarPromoteExcelConfigData.json")
|
||||
public class AvatarPromoteData extends GameResource {
|
||||
|
||||
private int AvatarPromoteId;
|
||||
private int PromoteLevel;
|
||||
private int ScoinCost;
|
||||
private ItemParamData[] CostItems;
|
||||
private int UnlockMaxLevel;
|
||||
private FightPropData[] AddProps;
|
||||
private int RequiredPlayerLevel;
|
||||
private int avatarPromoteId;
|
||||
private int promoteLevel;
|
||||
private int scoinCost;
|
||||
private ItemParamData[] costItems;
|
||||
private int unlockMaxLevel;
|
||||
private FightPropData[] addProps;
|
||||
private int requiredPlayerLevel;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return (AvatarPromoteId << 8) + PromoteLevel;
|
||||
return (avatarPromoteId << 8) + promoteLevel;
|
||||
}
|
||||
|
||||
public int getAvatarPromoteId() {
|
||||
return AvatarPromoteId;
|
||||
return avatarPromoteId;
|
||||
}
|
||||
|
||||
public int getPromoteLevel() {
|
||||
return PromoteLevel;
|
||||
return promoteLevel;
|
||||
}
|
||||
|
||||
public ItemParamData[] getCostItems() {
|
||||
return CostItems;
|
||||
return costItems;
|
||||
}
|
||||
|
||||
public int getCoinCost() {
|
||||
return ScoinCost;
|
||||
return scoinCost;
|
||||
}
|
||||
|
||||
public FightPropData[] getAddProps() {
|
||||
return AddProps;
|
||||
return addProps;
|
||||
}
|
||||
|
||||
public int getUnlockMaxLevel() {
|
||||
return UnlockMaxLevel;
|
||||
return unlockMaxLevel;
|
||||
}
|
||||
|
||||
public int getRequiredPlayerLevel() {
|
||||
return RequiredPlayerLevel;
|
||||
return requiredPlayerLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,7 +60,7 @@ public class AvatarPromoteData extends GameResource {
|
||||
}
|
||||
trim.add(itemParam);
|
||||
}
|
||||
this.CostItems = trim.toArray(new ItemParamData[trim.size()]);
|
||||
this.costItems = trim.toArray(new ItemParamData[trim.size()]);
|
||||
// Trim fight prop data (just in case)
|
||||
ArrayList<FightPropData> parsed = new ArrayList<>(getAddProps().length);
|
||||
for (FightPropData prop : getAddProps()) {
|
||||
@ -69,6 +69,6 @@ public class AvatarPromoteData extends GameResource {
|
||||
parsed.add(prop);
|
||||
}
|
||||
}
|
||||
this.AddProps = parsed.toArray(new FightPropData[parsed.size()]);
|
||||
this.addProps = parsed.toArray(new FightPropData[parsed.size()]);
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
|
||||
@ResourceType(name = "AvatarSkillExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)
|
||||
public class AvatarSkillData extends GameResource {
|
||||
private int id;
|
||||
private float cdTime;
|
||||
private int costElemVal;
|
||||
private int maxChargeNum;
|
||||
private int triggerID;
|
||||
private boolean isAttackCameraLock;
|
||||
private int proudSkillGroupId;
|
||||
private ElementType costElemType;
|
||||
private List<Float> lockWeightParams;
|
||||
|
||||
private long nameTextMapHash;
|
||||
|
||||
private String abilityName;
|
||||
private String lockShape;
|
||||
private String globalValueKey;
|
||||
|
||||
@Override
|
||||
public int getId(){
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public float getCdTime() {
|
||||
return cdTime;
|
||||
}
|
||||
|
||||
public int getCostElemVal() {
|
||||
return costElemVal;
|
||||
}
|
||||
|
||||
public int getMaxChargeNum() {
|
||||
return maxChargeNum;
|
||||
}
|
||||
|
||||
public int getTriggerID() {
|
||||
return triggerID;
|
||||
}
|
||||
|
||||
public boolean isIsAttackCameraLock() {
|
||||
return isAttackCameraLock;
|
||||
}
|
||||
|
||||
public int getProudSkillGroupId() {
|
||||
return proudSkillGroupId;
|
||||
}
|
||||
|
||||
public ElementType getCostElemType() {
|
||||
return costElemType;
|
||||
}
|
||||
|
||||
public List<Float> getLockWeightParams() {
|
||||
return lockWeightParams;
|
||||
}
|
||||
|
||||
public long getNameTextMapHash() {
|
||||
return nameTextMapHash;
|
||||
}
|
||||
|
||||
public String getAbilityName() {
|
||||
return abilityName;
|
||||
}
|
||||
|
||||
public String getLockShape() {
|
||||
return lockShape;
|
||||
}
|
||||
|
||||
public String getGlobalValueKey() {
|
||||
return globalValueKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user