66 Commits

Author SHA1 Message Date
8b83dbf58c Update Korean translation (#1977)
* updated ko-KR.json

Update Korean translation

* Update ko-KR.json
2022-12-11 01:22:34 +10:30
d6fef3252f Formalizing and changing untranslated words (#1973)
Changing non-formal word of "Sebahagian" to "Sebagian", Changing untranslated word, Making stuff slightly more clear
2022-12-10 10:26:46 +10:30
e73984bd41 Update CHS translation (#1965) 2022-12-02 10:25:15 +10:30
553e22ead8 Add more explicit NoSuchFileException message for excels 2022-11-28 21:04:39 +10:30
5878cb6f8d Accidentally left recent banner on test string 2022-11-26 16:50:56 +10:30
100d08ec5d Fix up pity tallies for new BannerTypes
Also fixes Beginner banner using Standard pity.
2022-11-26 02:03:11 +10:30
83b84408a1 Bake banner defaults into BannerType enum, and add every historic banner 2022-11-25 23:25:22 +10:30
da3981089d Add Position JsonAdapter for [x,y,z] format
Also add serializers for existing JsonAdapters
2022-11-25 00:29:26 +10:30
ad502a8568 Finally enforce deprecation of ancient Banners.json fields
Also add costItemId10 column so people know it exists, and removeC6FromPool column because it's a cool setting nobody knows about.
2022-11-24 23:56:13 +10:30
f6c84fdfbf Forgot about a 5star character that was added to the standard pool 2022-11-24 23:17:10 +10:30
1c4d263dd2 Add Data TSJ loading, replace and update Banners 2022-11-24 23:09:55 +10:30
35962542af Fix oversight on EnumTypeAdapterFactory 2022-11-24 01:36:58 +10:30
0b5329514b TSJ and TSV parsing (#1962)
* Deserialization support for tsv files

* Benchmarking

* Apparently moving the setter out of the lambda fixed the setAccessible issue

* Thread it

* Use AllArgsConstructor instead of field reflection

* Clean up AllArgsConstructor TSV deserialization

* Refactor TsvUtils

* Remove AllArgsConstructors from Excels

* Set field accessible

* [WIP] TSJ improvements

* [WIP] More TSV stuff

* [WIP] More TSV stuff

* Working TSV parser (slow)

* Load Excels in TSJ > JSON > TSV priority
2022-11-24 00:18:57 +10:30
46b0c7cf93 Work on French localization (#1958)
* Work on French localization

* Apply suggestions from code review
2022-11-22 20:48:39 +10:30
1e932ce144 added IT redeirect on all ReadME and typo fix (#1954)
* Added it-IT translaton

* added Italian readme

* readme redirect

add "it-IT" redirect on all readme

* added "it-IT" redirect on README.md

* Add files via upload

* added it to jp readme

* fix

* fix whitspasces

(vscode)
2022-11-20 22:45:43 +10:30
b1a9ed0226 Update DeforestationManager.java (#1955)
* Update DeforestationManager.java

* Update src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java
2022-11-20 18:25:36 +10:30
676ed32a12 Added it-IT translaton (#1946)
* Added it-IT translaton

* added Italian readme
2022-11-14 11:19:35 +10:30
05fe62b49a [FIX] Language es-ES (spanish) (#1941) 2022-11-08 14:54:15 +10:30
b781e560e4 Version 1.4.4-dev [skip actions] 2022-11-05 12:49:35 +00:00
5c4c62c1ed Version 1.4.3
Update languages [skip actions]
Fix whitespace [skip actions]
Refactor Entity data
Clean up excels
Make PlayerBuffManager::removeBuff actually remove buff
Remove LinkedList usage https://twitter.com/joshbloch/status/583813919019573248
Add FIGHT_PROP_CUR_DEFENSE alias to setstats (closes #1929)
Update gradle wrapper (closes #1076)
Add warnings to ancient deprecated Banners.json fields Will probably turn these into runtime errors in 1.5.0, people need to stop sharing configs with dead fields and especially stop making PRs with them.
3.2 First Half Banners (closes #1932)
Reimplement namecard claiming (fixes #1882)
Kill console on IOError
Refactor command kwarg parsing
Update roomSceneId obfuscated names (#1926)
Add the new keys (3.2 Support) (#1923)
Update README_ja-JP.md (#1922)
Fix Mail SendToAll Freeze (#1913)
Remove deprecated constructor call
Debug system (#1894)
[Security][Bugfix] Fix directory traversal exploit (#1907)
Updated spanish translations (#1911)
Don't override en-us gacha strings with vietnamese
Fix gacha history internal server error
Fix CONTIBUTING typo in protect_files.yml
Remove compilation warning on Language.java
Version 1.4.3-dev [skip actions]
2022-11-05 12:49:35 +00:00
e2b59fbd8d Update languages [skip actions] 2022-11-05 12:49:35 +00:00
84bf783243 Fix whitespace [skip actions] 2022-11-05 12:49:35 +00:00
4d8caf5a8c Refactor Entity data 2022-11-05 23:18:33 +10:30
a30f16b0e1 Clean up excels 2022-11-05 23:12:03 +10:30
65915b7666 Make PlayerBuffManager::removeBuff actually remove buff 2022-11-05 17:26:20 +10:30
1ceda2a455 Remove LinkedList usage
https://twitter.com/joshbloch/status/583813919019573248
2022-11-05 17:04:15 +10:30
09f392bb5b Add FIGHT_PROP_CUR_DEFENSE alias to setstats (closes #1929) 2022-11-05 15:36:52 +10:30
944bfb76f3 Update gradle wrapper (closes #1076) 2022-11-05 15:03:00 +10:30
dc7b8d8ca6 Add warnings to ancient deprecated Banners.json fields
Will probably turn these into runtime errors in 1.5.0, people need to stop sharing configs with dead fields and especially stop making PRs with them.
2022-11-05 14:22:17 +10:30
9f00ea3573 3.2 First Half Banners
(closes #1932)
2022-11-05 13:56:27 +10:30
12316b36b1 Reimplement namecard claiming (fixes #1882) 2022-11-04 15:05:51 +10:30
0fb7d50acd Kill console on IOError 2022-11-04 13:55:39 +10:30
c926fe326c Refactor command kwarg parsing 2022-11-04 13:55:39 +10:30
e8930e92e1 Update roomSceneId obfuscated names (#1926) 2022-11-02 18:03:41 +10:30
4ed0b90c27 Add the new keys (3.2 Support) (#1923)
* Add the new keys

* Some improvements to the key loading system & Bump the game version
2022-11-01 23:28:04 +01:00
7bfb35ac39 Update README_ja-JP.md (#1922)
* Translate README.md into Japanese

Update README_ja-JP.md

* Update README_ja-JP.md

Update command link for account creation to take the reader closer to the actual command description.

Co-authored-by: GanyusLeftHorn <1244229+GanyusLeftHorn@users.noreply.github.com>
2022-11-01 03:43:19 +01:00
47911aa16e Fix Mail SendToAll Freeze (#1913)
* Avoid iterating over every offline player

* getAllPlayers by stream

* Use the new method without changing the old signature

* Annotate deprecated `getAllPlayers`
2022-10-30 20:03:30 +10:30
855d3182ab Remove deprecated constructor call 2022-10-30 00:40:00 +10:30
43b7d7a383 Debug system (#1894)
* Add build (compile) script: gradlew jar

* Move server and services log levels to ConfigContainer, ability to enable/disable show packet payload and loop packets

* Add some loop packets to known list
2022-10-29 23:31:28 +10:30
55928d9154 [Security][Bugfix] Fix directory traversal exploit (#1907)
* [Security][Bugfix] Fix directory traversal exploit

1.The first slash will act as root path when resolving local path, so directory traversal is possible
2.Filter the illegal payload to prevent directory traversal
3.This also fix the bug about not loading the files in data folder when querying  `/hk4e/announcement/`

* Fix formatting

* Update src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java
2022-10-29 23:19:46 +10:30
6219902e0f Updated spanish translations (#1911) 2022-10-29 23:06:44 +10:30
d7af52f94b Don't override en-us gacha strings with vietnamese 2022-10-29 00:11:44 +10:30
c21d216d8d Fix gacha history internal server error 2022-10-29 00:05:29 +10:30
60657b3b98 Fix CONTIBUTING typo in protect_files.yml 2022-10-28 22:23:13 +10:30
f07ce48b24 Remove compilation warning on Language.java 2022-10-28 22:13:13 +10:30
2dd644f28b Version 1.4.3-dev [skip actions] 2022-10-26 12:31:30 +00:00
229303f934 Version 1.4.2
Update languages [skip actions]
Fix whitespace [skip actions]
Update README and fil-PH (#1901)
Remove references to old repo
Make Player lazyload correct Account (should fix #1900)
Lombokify Grasscutter.java some more
Update ru-RU.json (#1895)
Extend setConstCommand "all" (#1884)
add Quest command alias (#1891)
Added zh-CN translaton for non-translated strings (#1890)
Updated Polish Translation (#1889)
Added "s" alias to SpawnCommand (closes #1840)
fix: unlocking home bgm doesn't work. (#1886)
Fix edge case on FileUtils::getFilenameWithoutPath
Medicine revival&Login white screen (#1883)
Save avatar in forceConstellationLevel (closes #1881)
Fix IllegalStateException when execute toMap (#1879)
Fix StackOverFlow when execute /give all (#1878)
Version 1.4.2-dev [skip actions]
2022-10-26 12:31:30 +00:00
a9148e1b66 Update languages [skip actions] 2022-10-26 12:31:30 +00:00
d99a50b80f Fix whitespace [skip actions] 2022-10-26 12:31:30 +00:00
877f747d01 Update README and fil-PH (#1901)
* made it more  c l e a r e r

* add .

* Update README.md

* Capitalised HTTPS

* update actions to build

* fixed typo

Fixed the bullet point spacing, removed http://mitm.it as the download page don't exist anymore, added `mitmproxy-ca-cert.cer` and save script into the instruction.

* added additional info about mitmproxy

* minor fixes

* Update README_fil-PH

Synced with the README
Removed bad words, insults like saying the user has skill issues
Added some professionally

* grammar fix
2022-10-26 12:15:08 +10:30
18360a6231 Remove references to old repo 2022-10-26 12:08:51 +10:30
a2c4895c16 Make Player lazyload correct Account (should fix #1900) 2022-10-25 18:31:55 +10:30
a5579368bb Lombokify Grasscutter.java some more 2022-10-25 15:49:14 +10:30
ae51f4c046 Update ru-RU.json (#1895) 2022-10-25 10:54:22 +10:30
5b6698f583 Extend setConstCommand "all" (#1884)
* Extend give command "talent"

* Update src/main/java/emu/grasscutter/data/excels/AvatarSkillDepotData.java

Shorten IntStream for getCombatSkills

Co-authored-by: Luke H-W <Birdulon@users.noreply.github.com>

* Fix setSkillLevel to work during avatar construction
Shortening getCombatSkills

* changeSkillLevel now acts as intermediate operation to fetch skillIds

* setSkillLevel changes to allow out of range levels to be normalized

* Update src/main/java/emu/grasscutter/command/commands/GiveCommand.java

Removing recalcStats since it's redundant

Co-authored-by: Luke H-W <Birdulon@users.noreply.github.com>

* Major changes and cleanup:
- AvatarSkillDepotData: removed getCombatSkills since it's unused
- TalentCommand: shortened /talent all using getSkillsAndEnergySkill
- GiveCommand: changed changeSkillLevel to setSkillLevel
- Avatar: delete changeSkillLevel and moved the operation inside setSkillLevel,updated skillId to Integer to catch special cases from GiveCommand

* Small cleanup:
Removed the special case from Avatar to be handled inside of GiveCommand

* Added "all" parameter to SetConst

* Changed all to [all] int SetConstCommand usage

Co-authored-by: Luke H-W <Birdulon@users.noreply.github.com>

Co-authored-by: Luke H-W <Birdulon@users.noreply.github.com>
2022-10-24 14:28:39 +10:30
496cd671da add Quest command alias (#1891) 2022-10-24 12:32:35 +10:30
fd6ed2f15f Added zh-CN translaton for non-translated strings (#1890)
Added zh-CN translation for non-translated strings
2022-10-24 10:34:51 +10:30
ceed05cd15 Updated Polish Translation (#1889) 2022-10-24 10:33:15 +10:30
7d1a7b501b Added "s" alias to SpawnCommand (closes #1840) 2022-10-24 10:32:10 +10:30
8b520b3883 fix: unlocking home bgm doesn't work. (#1886)
* fix: unlocking home bgm doesn't work.

* Update src/main/java/emu/grasscutter/game/home/GameHome.java

Co-authored-by: Luke H-W <Birdulon@users.noreply.github.com>

Co-authored-by: Luke H-W <Birdulon@users.noreply.github.com>
2022-10-23 15:08:17 +10:30
54ad108a14 Fix edge case on FileUtils::getFilenameWithoutPath 2022-10-22 17:15:43 +10:30
ccf182d692 Medicine revival&Login white screen (#1883)
* Update InventorySystem.java

-:[fix] Medicine revival

* Update GameMainQuest.java

-:[fix] Login white screen
2022-10-22 16:51:33 +10:30
c51f7610b2 Save avatar in forceConstellationLevel (closes #1881) 2022-10-22 12:45:27 +10:30
c331a7f288 Fix IllegalStateException when execute toMap (#1879) 2022-10-21 21:49:48 +10:30
be8fbcbc02 Fix StackOverFlow when execute /give all (#1878)
* Fix StackOverFlow when execute /give all

* Use more proper code
2022-10-20 20:22:10 +10:30
c5d30c44eb Version 1.4.2-dev [skip actions] 2022-10-18 14:56:27 +00:00
152 changed files with 3269 additions and 2613 deletions

View File

@ -20,4 +20,4 @@ jobs:
steps: steps:
- uses: superbrothers/close-pull-request@v3 - uses: superbrothers/close-pull-request@v3
with: with:
comment: "This PR has been closed for modifying protected files. See `CONTIBUTING.md` for more information." comment: "This PR has been closed for modifying protected files. See `CONTRIBUTING.md` for more information."

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Attention:** We always welcome contributors to the project. Before adding your contribution, please carefully read our [Code of Conduct](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Attention:** We always welcome contributors to the project. Before adding your contribution, please carefully read our [Code of Conduct](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
@ -37,13 +37,13 @@
**Note:** If you updated from an older version, delete `config.json` to regenerate it. **Note:** If you updated from an older version, delete `config.json` to regenerate it.
1. Get `grasscutter.jar` 1. Get `grasscutter.jar`
- Download from [actions](https://github.com/Grasscutters/Grasscutter/actions/workflows/build.yml) or [build the server by yourself](#building). - Download from [releases](https://github.com/Grasscutters/Grasscutter/releases/latest) or [actions](https://github.com/Grasscutters/Grasscutter/actions/workflows/build.yml) or [build the server by yourself](#building).
2. Create a `resources` folder in the directory where grasscutter.jar is located and move your `BinOutput, ExcelBinOutput, Readables, Scripts, Subtitle, TextMap` folders there *(Check the [wiki](https://github.com/Grasscutters/Grasscutter/wiki) for more details how to get those.)* 2. Create a `resources` folder in the directory where grasscutter.jar is located and move your `BinOutput, ExcelBinOutput, Readables, Scripts, Subtitle, TextMap` folders there *(Check the [wiki](https://github.com/Grasscutters/Grasscutter/wiki) for more details how to get those.)*
3. Run Grasscutter with `java -jar grasscutter.jar`. **Make sure mongodb service is running as well.** 3. Run Grasscutter with `java -jar grasscutter.jar`. **Make sure mongodb service is running as well.**
### Connecting with the client ### Connecting with the client
½. Create an account using [server console command](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting). ½. Create an account in the server console using this [command](https://github.com/Grasscutters/Grasscutter/wiki/Commands#:~:text=account%20%3Ccreate|delete%3E%20%3Cusername%3E%20[UID]).
1. Redirect traffic: (choose one only) 1. Redirect traffic: (choose one only)
- mitmdump: `mitmdump -s proxy.py -k` - mitmdump: `mitmdump -s proxy.py -k`
@ -58,7 +58,6 @@
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
``` ```
- Fiddler Classic: Run Fiddler Classic, turn on `Decrypt HTTPS traffic` in (Tools -> Options -> HTTPS) and change the default port in (Tools -> Options -> Connections) to anything other than `8888`, load [this script](https://github.com/Grasscutters/Grasscutter/wiki/Resources#fiddler-classic-jscript) (copy and paste the script in the `FiddlerScript` tab) and click the `Save Script` button. - Fiddler Classic: Run Fiddler Classic, turn on `Decrypt HTTPS traffic` in (Tools -> Options -> HTTPS) and change the default port in (Tools -> Options -> Connections) to anything other than `8888`, load [this script](https://github.com/Grasscutters/Grasscutter/wiki/Resources#fiddler-classic-jscript) (copy and paste the script in the `FiddlerScript` tab) and click the `Save Script` button.
- [Hosts file](https://github.com/Grasscutters/Grasscutter/wiki/Resources#hosts-file) - [Hosts file](https://github.com/Grasscutters/Grasscutter/wiki/Resources#hosts-file)
@ -67,7 +66,7 @@
- For mitmproxy: After setting up the network proxy and installing the certificate, check http://mitm.it/ if traffic is passing through mitmproxy. - For mitmproxy: After setting up the network proxy and installing the certificate, check http://mitm.it/ if traffic is passing through mitmproxy.
**You can also use `start.cmd` to start servers and proxy daemons automatically, but you have to set up `JAVA_HOME` enviroment and configure the `start_config.cmd` file.** **You can also use `start.cmd` to start servers and proxy daemons automatically, but you have to set up `JAVA_HOME` environment and configure the `start_config.cmd` file.**
### Building ### Building
@ -102,7 +101,6 @@ You can find the output jar in the root of the project folder.
# Quick Troubleshooting # Quick Troubleshooting
* If compiling wasn't successful, please check your JDK installation (Make sure its JDK 17 or higher and validated JDK's bin PATH variable) * If compiling wasn't successful, please check your JDK installation (Make sure its JDK 17 or higher and validated JDK's bin PATH variable).
* My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is *the issue*, if using * My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is *the issue*. If you're using Fiddler, change the default port to anything other than 8888.
Fiddler make sure it running on another port except 8888
* Startup sequence: MongoDB > Grasscutter > Proxy Daemon (mitmdump, fiddler, etc.) > Game * Startup sequence: MongoDB > Grasscutter > Proxy Daemon (mitmdump, fiddler, etc.) > Game

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**תשומת לב בבקשה:** אנחנו מקבלים עזרה בפיתוח התוכנה. לפני שאתם תורמים לפרויקט בבקשה תקראו את [תנאי השימוש](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **תשומת לב בבקשה:** אנחנו מקבלים עזרה בפיתוח התוכנה. לפני שאתם תורמים לפרויקט בבקשה תקראו את [תנאי השימוש](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
@ -66,7 +66,7 @@ certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
-עריכת [קובץ הHosts](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map) -עריכת [קובץ הHosts](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. תשנו את שרת בproxy שלכם ל`127.0.0.1:8080` 2. תשנו את שרת בproxy שלכם ל`127.0.0.1:8080`

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Aantekening:** We verwelkomen altijd bijdragers aan het project. Lees onze [Gedragscode](https://github.com/Grasscutters/Grasscutter/blob/development/README_NL.md#bijdragen-aan-het-project) zorgvuldig door voordat u uw bijdrage toevoegt. **Aantekening:** We verwelkomen altijd bijdragers aan het project. Lees onze [Gedragscode](https://github.com/Grasscutters/Grasscutter/blob/development/README_NL.md#bijdragen-aan-het-project) zorgvuldig door voordat u uw bijdrage toevoegt.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Atención:** Siempre damos la bienvenida a contribuidores del proyecto. Antes de añadir tu contribución, por favor lee cuidadosamente nuestro [Código de conducta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Atención:** Siempre damos la bienvenida a contribuidores del proyecto. Antes de añadir tu contribución, por favor lee cuidadosamente nuestro [Código de conducta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
@ -63,11 +63,11 @@
- Fiddler Classic: Ejecuta Fiddler Classic, activa `Decrypt https traffic` en las opciones y cambia el puerto por defecto ahí (Herramientas -> Opciones -> Conexiones) a alguno que no sea `8888`, y carga [este script](https://github.lunatic.moe/fiddlerscript). - Fiddler Classic: Ejecuta Fiddler Classic, activa `Decrypt https traffic` en las opciones y cambia el puerto por defecto ahí (Herramientas -> Opciones -> Conexiones) a alguno que no sea `8888`, y carga [este script](https://github.lunatic.moe/fiddlerscript).
- [Archivo Hosts](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map) - [Archivo Hosts](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. Establece el proxy de red a `127.0.0.1:8080` o el puerto de proxy que pusiste. 2. Establece el proxy de red a `127.0.0.1:8080` o el puerto de proxy que pusiste.
**también puedes usar `start.cmd` para iniciar el servidor y el servicio de proxy automáticamente, pero tienes que configurar el entorno JAVA_HOME** **También puedes usar `start.cmd` para iniciar el servidor y el servicio de proxy automáticamente, pero tienes que configurar el entorno JAVA_HOME**
### Construcción ### Construcción

View File

@ -3,15 +3,13 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Atensyon:** Ang mga kontributor ay laging welcome sa proyektong ito. Bago mag-bigay ng kontribusyon, basahin muna ng mabuti ang [Code of Conduct](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Atensyon:** Ang mga kontributor ay laging welcome sa proyektong ito. Bago mag-bigay ng kontribusyon, basahin muna ng mabuti ang [Code of Conduct](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
<b>(Basahin ha, hindi titingin lang)</b> ## Ang mga kasalukuyang features
## Ang mga current features * Logging in
* Login system
* Combat * Combat
* Friends list * Friends list
* Teleportation * Teleportation
@ -22,62 +20,61 @@
## Quick setup guide ## Quick setup guide
**Atensyon:** Kung di mo talaga kaya o hindi mo maintindihan ang wiki, maaari kang sumali sa aming server [Discord](https://discord.gg/T5vZU6UyeG). **Atensyon:** Para sa mga nangangailangan ng suporta, maaari kang sumali sa aming server [Discord](https://discord.gg/T5vZU6UyeG).
### Ang mga kailangan ### Ang mga kailangan
* Java SE - 17 ([link](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)) * [Java SE - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) or higher
**Atensyon:** Kung gusto mo lang **paganahin** ang server, then **jre** is pwede naman. **Atensyon:** Kung gusto mo lang **paganahin** ang server, pwede naman ang **jre**.
* [MongoDB](https://www.mongodb.com/try/download/community) (recommended 4.0+) * [MongoDB](https://www.mongodb.com/try/download/community) (recommended 4.0+)
* Proxy daemon: mitmproxy (mitmdump, recommended), Fiddler Classic, etc. * Proxy Daemon: [mitmproxy](https://mitmproxy.org/) (mitmdump, recommended), [Fiddler Classic](https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe), etc.
### Running ### Running
**Atensyon:** Kung nag-update ka galing sa old version, paki-delete ang `config.json` para mag-regenerate ulit. **Atensyon:** Kung nag-update ka galing sa lumang version, paki-delete ang `config.json` para mag-regenerate ulit.
1. Get `grasscutter.jar` 1. Get `grasscutter.jar`
- Download ka from [actions](https://github.com/Grasscutters/Grasscutter/suites/6895963598/artifacts/267483297) - I-download mo sa [releases](https://github.com/Grasscutters/Grasscutter/releases/latest) o sa [actions](https://github.com/Grasscutters/Grasscutter/actions/workflows/build.yml) o [bumuo ng iyong sariling server](#building).
- [Build mo ung jar by yourself](#Building) 2. Gawa ka ng `resources` folder sa directory kung nasaan ang grasscutter.jar at ilagay ang `BinOutput, ExcelBinOutput, Readables, Scripts, Subtitle, TextMap` folders sa loob ng resources folder *(Tingnan mo ang [wiki](https://github.com/Grasscutters/Grasscutter/wiki) para malaman mo kung saan mo makukuha yan)*
2. Gawa ka ng `resources` folder sa directory kung nasaan ang grasscutter.jar at ilagay ang `BinOutput` at `ExcelBinOutput` sa loob ng resources folder *(Check mo ang [wiki](https://github.com/Grasscutters/Grasscutter/wiki) para malaman mo san mo makukuha yan)* 3. Paandarin ang Grasscutter gamit ang command na `java -jar grasscutter.jar`. **Siguraduhin mo na ang mongodb service ay naka-open din.**
3. Paandarin ang Grasscutter gamit ang command na `java -jar grasscutter.jar`. **Make sure na gumagana ang mongodb (Google mo nalang kung pano mo malalaman)**
### Connecting with the client ### Connecting with the client
½. Create ka ng account gamit ang [server console command](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting). ½. Gumawa ng account sa server console gamit ang [command](https://github.com/Grasscutters/Grasscutter/wiki/Commands#:~:text=account%20%3Ccreate|delete%3E%20%3Cusername%3E%20[UID]) na ito.
1. Redirect traffic: (choose one) 1. Redirect traffic: (pumili lang dapat ng isa)
- mitmdump: `mitmdump -s proxy.py -k` - mitmdump: `mitmdump -s proxy.py -k`
Trust CA certificate: - Trust CA certificate:
**Note:** Usually ang CA certificate ay nakalagay sa `%USERPROFILE%\ .mitmproxy`, o pwede mo naman i-download from `http://mitm.it` - Ang CA certificate ay nasa `%USERPROFILE%\.mitmproxy`, i-double click ang `mitmproxy-ca-cert.cer` para ma-[install](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) o...
Double click para ma-[install](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) or ... - Via command line *(kailangan ng administration privileges)*
- Gamit ang command line (cmd.exe) ```shell
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
```
```shell - Fiddler Classic: Paadarin ang Fiddler Classic, turn on mo yung `Decrypt https traffic` sa (Tools -> Options -> HTTPS) at baguhin mo ang default port na nakalagay (Tools -> Options -> Connections) sa anumang numero maliban sa `8888`, i-load ang [script](https://github.com/Grasscutters/Grasscutter/wiki/Resources#fiddler-classic-jscript) na ito (copy and paste ang script sa `FiddlerScript` tab) at i-click ang `Save Script` button.
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
```
- Fiddler Classic: Paadarin ang Fiddler Classic, tsaka turn on mo yung `Decrypt https traffic` sa settings at baguhin mo yung default port na nakalagay (Tools -> Options -> Connections) to anything other than `8888`, at saka mo i-load [itong script](https://github.lunatic.moe/fiddlerscript). - [Hosts file](https://github.com/Grasscutters/Grasscutter/wiki/Resources#hosts-file)
- [Hosts file](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map)
2. Set mo ung proxy sa `127.0.0.1:8080` or dun sa proxy port na iyong inilagay. 2. Set mo ung proxy sa `127.0.0.1:8080` or dun sa proxy port na iyong inilagay.
**pwede mo rin gamitin ang `start.cmd` to start the servers and proxy daemons automatically, pero kailagan mong i-setup ang JAVA_HOME enviroment** - Para sa mitmproxy: Pagkatapos mong i-setup ang network proxy at sa pag-install ng certificate, tingnan mo sa http://mitm.it/ kung ang traffic ay dumadaan sa mitmproxy.
**Pwede mo rin gamitin ang `start.cmd` to start the servers and proxy daemons automatically, pero kailagan mong i-setup ang JAVA_HOME environment at i-configure ang `start_config.cmd` file.**
### Building ### Building
Ang Grasscutter ay gumagamit ng gradle for depedencies at building. Ang Grasscutter ay gumagamit ng Gradle para sa depedencies at building.
**Mga kailangan:** **Mga kailangan:**
- [Java SE Development Kits - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) - [Java SE Development Kits - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) or higher
- [Git](https://git-scm.com/downloads) - [Git](https://git-scm.com/downloads)
##### Windows ##### Windows
@ -98,17 +95,12 @@ chmod +x gradlew
./gradlew jar # Compile jar ./gradlew jar # Compile jar
``` ```
Pag-katapos mong i-compile, check mo yung [project](https://github.com/grasscutters/grasscutter) directory at saka makikita mo ung jar na kinompile mo. Usually pag-dev version, ang dapat nakalagay jan ay `grasscutter-<version>-dev.jar`. Bulag ka pag-hindi mo pa yan nakita. Pag-katapos mong i-compile, check mo yung project directory at makikita mo yung jar na kinompile mo. Usually pag-dev version, ang dapat nakalagay diyan ay `grasscutter-<version>-dev.jar`.
### Atensyon: ang mga server commands ay nasa [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)! ### Ang mga server commands ay nasa [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands) na!
# Quick Troubleshooting # Quick Troubleshooting
* Kung hindi nag-compile, paki-check ung JDK installation mo (JDK 17 at JDK's bin PATH variable). Pag-hindi mo pa rin na-compile o hindi mo ma-gets, isa lang masasabi ko sayo, may skill issue+reading issue ka. * Kung hindi nag-compile, paki-check ung JDK installation mo (JDK 17 at JDK's bin PATH variable).
* Hindi ako maka-connect, ayaw mag-login, 4206, etc... - `Usually proxy may kasalanan nyan`, ito ung pinaka-malalang skill issue na pwede mong makuha, sa lahat ng problems sa gc. Kung ayaw mo nyan, basahin mo ito. * Hindi ako maka-connect, ayaw mag-login, 4206, etc... - Mostly ang proxy setup mo ang may kasalanan niyan, kung gamit mo ay Fiddler, paki-sigurado na naka-set ung port sa kahit ano except sa 8888.
* Ang pagkakasunud-sunod: MongoDB > Grasscutter > Proxy Daemon (mitmdump, fiddler, etc.) > Game
Kung <b>Fiddler user</b> ka, paki-sigurado na naka-set ung port sa kahit ano except sa `8888`. (8888 port is for hoyoverse spider logs, in case na hindi mo alam)
* Startup sequence: MongoDB > Grasscutter > Proxy daemon o Proxy service (mitmdump, fiddler, etc.)
<b> KUNG HINDI MO TALAGA MAINTINDIHAN, LUMAYAS KA NA DITO.........
PUTANG INA MO, TAGLISH NA NGA YAN. TAS HINDI MO PA MA-GETS LMAO</b>

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Attention:** De nouveaux contributeurs sont toujours les bienvenus. Avant d'ajouter votre contribution, veuillez lire le [code de conduite](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Attention:** De nouveaux contributeurs sont toujours les bienvenus. Avant d'ajouter votre contribution, veuillez lire le [code de conduite](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
@ -63,7 +63,7 @@
- Fiddler Classic: Exécutez Fiddler Classic, Activez `Decrypt https traffic` dans les paramètres et changez le port par défaut ici (Tools -> Options -> Connections) à autre chose que `8888`, et chargez [ce script](https://github.lunatic.moe/fiddlerscript). - Fiddler Classic: Exécutez Fiddler Classic, Activez `Decrypt https traffic` dans les paramètres et changez le port par défaut ici (Tools -> Options -> Connections) à autre chose que `8888`, et chargez [ce script](https://github.lunatic.moe/fiddlerscript).
- [Fichier hosts](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map) - [Fichier hosts](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. Définissez le proxy du réseau comme `127.0.0.1:8080` ou le port du proxy que vous avez spécifié. 2. Définissez le proxy du réseau comme `127.0.0.1:8080` ou le port du proxy que vous avez spécifié.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Perhatian:** Kami selalu menyambut kontributor untuk proyek ini. Sebelum menambahkan kontribusi Anda, harap baca [Kode Etik](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md) kami. **Perhatian:** Kami selalu menyambut kontributor untuk proyek ini. Sebelum menambahkan kontribusi Anda, harap baca [Kode Etik](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md) kami.
@ -14,7 +14,7 @@
* Daftar teman * Daftar teman
* Teleportasi * Teleportasi
* Sistem gacha * Sistem gacha
* Co-op *sebahagian* berfungsi * Co-op *sebagian* berfungsi
* Memunculkan monster melalui konsol * Memunculkan monster melalui konsol
* Fitur inventaris (menerima item/karakter, meng-upgrade item/karakter, dll) * Fitur inventaris (menerima item/karakter, meng-upgrade item/karakter, dll)
@ -53,9 +53,9 @@
**Catatan:** Sertifikat CA biasanya disimpan di `%USERPROFILE%\ .mitmproxy`, atau anda dapat download dari `http://mitm.it` **Catatan:** Sertifikat CA biasanya disimpan di `%USERPROFILE%\ .mitmproxy`, atau anda dapat download dari `http://mitm.it`
klik dua kali untuk [menginstall](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) or ... klik dua kali untuk [menginstall](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) ataupun juga
- Via command line - melalui command line
```shell ```shell
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
@ -63,7 +63,7 @@
- Fiddler Classic: Jalankan Fiddler Classic, nyalakan `Decrypt https traffic` dalam setting dan ubah port default di sana (Tools -> Options -> Connections) ke apa pun selain `8888`, dan muat [skrip ini](https://github.lunatic.moe/fiddlerscript). - Fiddler Classic: Jalankan Fiddler Classic, nyalakan `Decrypt https traffic` dalam setting dan ubah port default di sana (Tools -> Options -> Connections) ke apa pun selain `8888`, dan muat [skrip ini](https://github.lunatic.moe/fiddlerscript).
- [File host](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map) - [File host](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. Atur proxy jaringan ke `127.0.0.1:8080` atau port proxy yang anda tentukan. 2. Atur proxy jaringan ke `127.0.0.1:8080` atau port proxy yang anda tentukan.
@ -103,6 +103,6 @@ Anda bisa menemukan output jar di root folder proyek.
# Quick Troubleshooting # Quick Troubleshooting
* Jika kompilasi tidak berhasil, periksa instalasi JDK Anda (JDK 17 dan validasi variabel bin PATH JDK) * Jika kompilasi tidak berhasil, periksa instalasi JDK Anda (JDK 17 dan validasi variabel bin PATH JDK)
* Klien saya tidak terhubung, tidak login, 4206, dll... - Sebagian besar pengaturan daemon proxy Anda adalah *masalahnya*, jika menggunakan * Klien saya tidak terhubung, tidak login, 4206, dan lain-lain - Sebagian besar pengaturan daemon proxy Anda adalah *masalahnya*, jika menggunakan
Fiddler pastikan berjalan pada port lain kecuali 8888 Fiddler pastikan berjalan pada port lain kecuali 8888
* Urutan startup: MongoDB > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Game * Urutan startup: MongoDB > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Game

108
README_it-IT.md Normal file
View File

@ -0,0 +1,108 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Attenzione:** Diamo sempre il benvenuto ai contributori del progetto. Prima di aggiungere il tuo contributo, leggi attentamente il nostro [Codice di condotta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
## Funzionalità attuali
* Login
* Combattimento
* Lista di amici
* Teletrasporto
* Sistema Gacha
* Cooperativa *parzialmente* funzionale
* Evoca mostri dalla console
* Funzionalità dell'inventario (ricevi oggetti/personaggi, aggiorna oggetti/personaggi, ecc.)
## Guida rapida all'installazione
**Nota:** Per il supporto, unisciti al nostro [Discord](https://discord.gg/T5vZU6UyeG).
### Requisiti
* Java SE - 17 ([link](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html))
**Nota:** se vuoi solo **eseguirlo**, **jre** è sufficiente.
* [MongoDB](https://www.mongodb.com/try/download/community) (consigliato 4.0+)
* Servizio proxy: mitmproxy (mitmdump, consigliato), Fiddler Classic, ecc.
### Esecuzione
**Nota:** Se hai eseguito l'aggiornamento da una versione precedente, rimuovi `config.json` in modo che venga generato di nuovo.
1. Ottieni "grasscutter.jar".
- Scarica da [azioni](https://github.com/Grasscutters/Grasscutter/suites/6895963598/artifacts/267483297)
- [Compilalo tu stesso](#Compilazione)
2. Crea una cartella `resources` nella directory in cui si trova grasscutter.jar e sposta lì le cartelle `BinOutput` ed `ExcelBinOutput` *(Vedi il [wiki](https://github.com/Grasscutters/Grasscutter/wiki ) per maggiori dettagli su come ottenerli.)*
3. Eseguire Grasscutter con `java -jar grasscutter.jar`. **Assicurati che il servizio mongodb sia attivo.**
### Connessione client
½. Crea un account usando [il comando corrispondente nella console del server](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting).
1. Reindirizza il traffico: (scegli uno)
- mitmdump: `mitmdump -s proxy.py -k`
Autorizza il certificato CA:
**Nota:**Il certificato CA si trova solitamente in `%USERPROFILE%\ .mitmproxy`, oppure puoi scaricarlo da `http://mitm.it`
Fare doppio clic su [installa](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) o ...
- Con riga di comando
```shell
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
```
- Fiddler Classic: esegui Fiddler Classic, abilita `Decrypt https traffic` nelle opzioni e cambia la porta predefinita in (Strumenti -> Opzioni -> Connessioni) in qualcosa di diverso da `8888`, e carica [questo script](https :/ /github.lunatic.moe/fiddlerscript).
- [File host](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. Impostare il proxy di rete su `127.0.0.1:8080` o la porta proxy impostata.
**Puoi anche usare `start.cmd` per avviare automaticamente il server e il servizio proxy, ma devi impostare l'ambiente JAVA_HOME**
### Compilazione
Grasscutter usa Gradle per gestire le dipendenze e le build.
**Requisiti:**
- [Kit di sviluppo Java SE - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
- [Git](https://git-scm.com/downloads)
##### Windows
```shell
git clone https://github.com/Grasscutters/Grasscutter.git
cd grasscutter
.\gradlew.bat # Impostazioni dell'ambiente
.\gradlew jar # Compila
```
##### Linux
```bash
git clone https://github.com/Grasscutters/Grasscutter.git
cd grasscutter
chmod +x gradlew
./gradlew jar # Compila
```
Puoi trovare il jar generato nella cartella principale del progetto.
### I comandi sono stati spostati nel [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)!
# Soluzioni agli errori comuni
* Se la compilazione non riesce, controlla l'installazione di JDK (JDK 17 e convalida la variabile JDK bin PATH)
* Il mio client non si connette, non accede, 4206, ecc... - Probabilmente le tue impostazioni proxy sono *il problema*, se usi
Fiddler assicurati di utilizzare una porta diversa da 8888
* Sequenza di avvio: MongoDB > Grasscutter > Servizio proxy (mitmdump, fiddler, ecc.) > Gioco

View File

@ -3,10 +3,10 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**:** 私たちはプロジェクトへの貢献者をいつでも歓迎します。 貢献を追加する前に我々の [行動規範](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)をよくお読みください. **:** 私たちはプロジェクトへの貢献者をいつでも歓迎します。貢献を追加する前に我々の [行動規範](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)をよくお読みください
## 現在機能している物 ## 現在機能している物
@ -21,53 +21,52 @@
## クイックセットアップガイド ## クイックセットアップガイド
**:** サポートが必要な場合はGrasscutterの[Discord](https://discord.gg/T5vZU6UyeG)に参加してください. **:** サポートが必要な場合はGrasscutterの[Discord](https://discord.gg/T5vZU6UyeG)に参加してください
### 動作環境 ### 動作環境
* [JAVAのバージョン17以降](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) * [JAVAのバージョン17以降](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
**:** サーバーを動作させるだけならjreのみで十分です。 開発をしたい場合JDKが必要になるかもしれません **:** サーバーを動作させるだけならjreのみで十分です。 開発をしたい場合JDKが必要になるかもしれません
* [MongoDB](https://www.mongodb.com/try/download/community) (バージョン4.0以降を推奨) * [MongoDB](https://www.mongodb.com/try/download/community) (バージョン4.0以降を推奨)
* プロキシツール: [mitmproxy](https://mitmproxy.org/) (mitmdump, 推奨)[Fiddler Classic](https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe)その他。 * プロキシツール: [mitmproxy](https://mitmproxy.org/) (mitmdump, 推奨)[Fiddler Classic](https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe)その他。
### 起動方法 ### 起動方法
**:** もしサーバーをアップデートしたい場合は`config.json`を削除してから再生成してください **:** もしサーバーをアップデートしたい場合は`config.json`を削除してから再生成してください
1. `grasscutter.jar`を入手する 1. `grasscutter.jar`を入手する
- [action](https://github.com/Grasscutters/Grasscutter/actions) からダウンロードするか [自分でビルド](https://github.com/Grasscutters/Grasscutter#building)してください。 - [releases](https://github.com/Grasscutters/Grasscutter/releases/latest) か [action](https://github.com/Grasscutters/Grasscutter/actions) からダウンロードするか[自分でビルド](https://github.com/Grasscutters/Grasscutter#building)してください。
2. `grasscutter.jar` があるディレクトリに `resources` フォルダーを作成しそこに `BinOutput, ExcelBinOutput, Readables, Scripts, Subtitle, TextMap` を移動してください *(`resources` フォルダの中身の入手方法については [wiki](https://github.com/Grasscutters/Grasscutter/wiki) を参照してください.)* 2. `grasscutter.jar` があるディレクトリに `resources` フォルダーを作成しそこに `BinOutput, ExcelBinOutput, Readables, Scripts, Subtitle, TextMap` を移動してください *(`resources` フォルダの中身の入手方法については [wiki](https://github.com/Grasscutters/Grasscutter/wiki) を参照してください.)*
3. コマンドプロンプトに`java -jar grasscutter.jar`を入力しGrasscutterを起動してください**このときMongoDBも実行する必要があります** 3. コマンドプロンプトに`java -jar grasscutter.jar`を入力しGrasscutterを起動してください**このときMongoDBも実行する必要があります**
### クライアントとの接続 ### クライアントとの接続
½. [サーバーコンソールコマンド](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting)を使用してアカウントを作成してください。 ½. [このコマンド](https://github.com/Grasscutters/Grasscutter/wiki/Commands#commands-for-server-admins)をサーバーコンソールから使用してアカウントを作成してください。
1. 通信内容をリダイレクトする: (どちらか一つを選択してください) 1. 通信内容をリダイレクトする: (どちらか一つを選択してください)
- mitmdump: `mitmdump -s proxy.py -k` - mitmdump: `mitmdump -s proxy.py -k`
CA証明書を信頼する: - CA証明書を信頼する:
**:** CA証明書は`%USERPROFILE%\.mitmproxy`に保存されているか、`http://mitm.it`からダウンロードできます。 - **:** CA証明書は`%USERPROFILE%\.mitmproxy`に保存されています。ダブルクリックして[インストール](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate)するか...
ダブルクリックして[インストール](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate)するか... - コマンドライン経由でインストールします
- コマンドライン経由でインストールします
```shell ```shell
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
``` ```
- Fiddler Classic: Fiddler Classicを起動し設定から`Decrypt https traffic`をオンにしてください。 (Tools -> Options -> Connections) に有るポート番号の設定を`8888`以外に設定してくださいその後この[スクリプト](https://github.com/Grasscutters/Grasscutter/wiki/Resources#fiddler-classic-jscript)をロードします - Fiddler Classic: Fiddler Classicを起動し(Tools -> Options -> HTTPS)から`Decrypt https traffic`をオンにしてください。 (Tools -> Options -> Connections) に有るポート番号の設定を`8888`以外に設定してくださいその後この[スクリプト](https://github.com/Grasscutters/Grasscutter/wiki/Resources#fiddler-classic-jscript)をFiddlerScriptタブにコピペしてロードします
- [ホストファイル](https://github.com/Grasscutters/Grasscutter/wiki/Resources#hosts-file) - [ホストファイル](https://github.com/Grasscutters/Grasscutter/wiki/Resources#hosts-file)
2. ネットワークプロキシを `127.0.0.1:(自分で設定したポート番号)` に設定してください。 2. ネットワークプロキシを `127.0.0.1:(自分で設定したポート番号)` に設定してください。
- mitmproxyを使用した場合プロキシの設定と証明書のインストールが終わった後、http://mitm.it/ でトラフィックがmitmproxyを通過しているか確認しましょう。
**`start_config.cmd`でJAVAのパスを指定している必要があります。 `start.cmd`でmitmdumpとサーバーをまとめて起動することが出来ます。** **`start.cmd`でmitmdumpとサーバーをまとめて起動することが出来ます。ただ、事前に`start_config.cmd`でJAVAのパスを指定している必要があります。**
### ビルド ### ビルド
@ -75,7 +74,7 @@ GrasscutterはGradleを使用して依存関係とビルドを処理していま
**要件:** **要件:**
- [Java SE 開発キット - 17以降](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) - [Java SE Development Kits - 17以降](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
- [Git](https://git-scm.com/downloads) - [Git](https://git-scm.com/downloads)
##### Windows ##### Windows
@ -96,13 +95,13 @@ chmod +x gradlew
./gradlew jar # コンパイル ./gradlew jar # コンパイル
``` ```
コンパイルされたjarファイルはプロクトフォルダのルートに有ります 生成されたjarファイルはプロジェクトフォルダのルートに有ります
### コマンドリストは[wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)へ移動しました。 ### コマンドリストは[wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)へ移動しました。
# トラブルシューティング # トラブルシューティング
* コンパイルが失敗した場合JDKがインストールされているか確認してください (JDKの17以降と環境変数でJAVAのパスが設定されている必要があります) * コンパイルが失敗した場合JDKがインストールされているか確認してください(JDKのバージョンが17以降であることと、環境変数でJDKのパスが設定されている必要があります)
* クライアントが接続できないログインできないエラーコード4206、 その他... - ほとんどの場合、プロキシ デーモンの設定が問題です。 * クライアントが接続できないログインできないエラーコード4206・またその他場合、ほとんど、プロキシデーモンの設定が問題です。Fiddlerを使っている場合はデフォルトポートを8888以外の別のポートに変更してみてください。
Fiddlerを使用している場合はポートが8888以外に設定されていることを確認してください Fiddlerを使用している場合はポートが8888以外に設定されていることを確認してください
* 起動シーケンス(順番): MongoDB > Grasscutter > プロキシツール (mitmdumpかfiddlerその他) > ゲーム * 起動シーケンス(順番): MongoDB > Grasscutter > プロキシツール (mitmdumpかfiddlerその他) > ゲーム

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**주의 :** 우리는 항상 프로젝트에 기여하는 사람들을 환영합니다. 기여를 하기 전, [행동 지침](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)을 주의 깊게 읽어주세요. **주의 :** 우리는 항상 프로젝트에 기여하는 사람들을 환영합니다. 기여를 하기 전, [행동 지침](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)을 주의 깊게 읽어주세요.
@ -63,7 +63,7 @@
- Fiddler Classic : Fiddler Classic을 실행한 후, Setting에서 `Decrypt https traffic` 옵션을 켜고, Tools -> Options -> Connections에 있는 기본 포트를 `8888`을 제외한 다른 포트로 지정합니다. 그리고 [이 스크립트](https://github.lunatic.moe/fiddlerscript)를 불러옵니다. - Fiddler Classic : Fiddler Classic을 실행한 후, Setting에서 `Decrypt https traffic` 옵션을 켜고, Tools -> Options -> Connections에 있는 기본 포트를 `8888`을 제외한 다른 포트로 지정합니다. 그리고 [이 스크립트](https://github.lunatic.moe/fiddlerscript)를 불러옵니다.
- [호스트 파일](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map) - [호스트 파일](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. 네트워크 프록시를 `127.0.0.1:8080` 로 설정하거나 지정한 프록시 포트로 설정합니다. 2. 네트워크 프록시를 `127.0.0.1:8080` 로 설정하거나 지정한 프록시 포트로 설정합니다.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Uwaga:** Zawsze jesteśmy otwarci na wasz wkład w projekt. Przed zaproponowaniem zmian przeczytaj [zasady postępowania (ENG)](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Uwaga:** Zawsze jesteśmy otwarci na wasz wkład w projekt. Przed zaproponowaniem zmian przeczytaj [zasady postępowania (ENG)](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
@ -63,7 +63,7 @@
- Fiddler Classic: Uruchom Fiddler Classic, włącz `Decrypt https traffic` w ustawieniach oraz zmień domyślny port (Tools -> Options -> Connections) na dowolny inny niż `8888`, i wczytaj [ten skrypt](https://github.lunatic.moe/fiddlerscript) (w polu FiddlerScript). - Fiddler Classic: Uruchom Fiddler Classic, włącz `Decrypt https traffic` w ustawieniach oraz zmień domyślny port (Tools -> Options -> Connections) na dowolny inny niż `8888`, i wczytaj [ten skrypt](https://github.lunatic.moe/fiddlerscript) (w polu FiddlerScript).
- [Plik hosts](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map) - [Plik hosts](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. Ustaw serwer proxy na `127.0.0.1:8080` albo inny wybrany przez ciebie port. 2. Ustaw serwer proxy na `127.0.0.1:8080` albo inny wybrany przez ciebie port.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**Внимание:** Мы всегда рады новому вкладу в проект. Однако, перед тем, как сделать свой вклад, пожалуйста, прочтите наш [кодекс делового поведения](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Внимание:** Мы всегда рады новому вкладу в проект. Однако, перед тем, как сделать свой вклад, пожалуйста, прочтите наш [кодекс делового поведения](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
@ -63,7 +63,7 @@
- Fiddler Classic: Запустите Fiddler Classic, включите настройку `Decrypt https traffic` в опциях и измените порт по умолчанию (Меню -> Tools -> Options -> Connections) на что-то не равное `8888`, после чего запустите [этот скрипт](https://github.lunatic.moe/fiddlerscript) во вкладке FiddlerSrcipt. - Fiddler Classic: Запустите Fiddler Classic, включите настройку `Decrypt https traffic` в опциях и измените порт по умолчанию (Меню -> Tools -> Options -> Connections) на что-то не равное `8888`, после чего запустите [этот скрипт](https://github.lunatic.moe/fiddlerscript) во вкладке FiddlerSrcipt.
- [Файл hosts](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map) - [Файл hosts](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. Установите прокси сети в `127.0.0.1:8080`, либо в тот порт прокси, который вы задали. 2. Установите прокси сети в `127.0.0.1:8080`, либо в тот порт прокси, который вы задали.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**请注意:** 欢迎成为本项目的贡献者。但在提交 PR 之前, 请仔细阅读 [代码规范](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)。 **请注意:** 欢迎成为本项目的贡献者。但在提交 PR 之前, 请仔细阅读 [代码规范](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)。

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) [EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md)
**請注意:** 歡迎成為本專案的貢獻者。在提交 PR 之前, 請仔細閱讀[程式碼規範](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)。 **請注意:** 歡迎成為本專案的貢獻者。在提交 PR 之前, 請仔細閱讀[程式碼規範](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)。

View File

@ -43,7 +43,7 @@ sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17
group = 'xyz.grasscutters' group = 'xyz.grasscutters'
version = '1.4.1' version = '1.4.4-dev'
sourceCompatibility = 17 sourceCompatibility = 17
targetCompatibility = 17 targetCompatibility = 17

Binary file not shown.

270
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh #!/bin/sh
# #
# Copyright 2015 the original author or authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -17,78 +17,113 @@
# #
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
@ -105,84 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=$(save "$@") # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong JAVACMD=$( cygpath --unix "$JAVACMD" )
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")" # Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

2
gradlew-jar.bat Normal file
View File

@ -0,0 +1,2 @@
call .\gradlew jar
pause

25
gradlew.bat vendored
View File

@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -51,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@ -6,7 +6,7 @@ import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
public final class GameConstants { public final class GameConstants {
public static String VERSION = "3.1.0"; public static String VERSION = "3.2.0";
public static final int DEFAULT_TEAMS = 4; public static final int DEFAULT_TEAMS = 4;
public static final int MAX_TEAMS = 10; public static final int MAX_TEAMS = 10;

View File

@ -48,27 +48,27 @@ import static emu.grasscutter.config.Configuration.SERVER;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
public final class Grasscutter { public final class Grasscutter {
private static final Logger log = (Logger) LoggerFactory.getLogger(Grasscutter.class); @Getter private static final Logger logger = (Logger) LoggerFactory.getLogger(Grasscutter.class);
private static LineReader consoleLineReader = null; private static LineReader consoleLineReader = null;
private static Language language; @Getter @Setter private static Language language;
public static final File configFile = new File("./config.json"); public static final File configFile = new File("./config.json");
@Setter private static ServerRunMode runModeOverride = null; // Config override for run mode @Setter private static ServerRunMode runModeOverride = null; // Config override for run mode
private static int day; // Current day of week. @Getter private static int currentDayOfWeek;
@Getter @Setter private static String preferredLanguage; @Getter @Setter private static String preferredLanguage;
private static HttpServer httpServer; @Getter private static HttpServer httpServer;
private static GameServer gameServer; @Getter private static GameServer gameServer;
private static PluginManager pluginManager; @Getter private static PluginManager pluginManager;
@Getter private static CommandMap commandMap; @Getter private static CommandMap commandMap;
private static AuthenticationSystem authenticationSystem; @Getter @Setter private static AuthenticationSystem authenticationSystem;
private static PermissionHandler permissionHandler; @Getter @Setter private static PermissionHandler permissionHandler;
public static final Reflections reflector = new Reflections("emu.grasscutter"); public static final Reflections reflector = new Reflections("emu.grasscutter");
public static ConfigContainer config; @Getter public static ConfigContainer config;
static { static {
// Declare logback configuration. // Declare logback configuration.
@ -230,18 +230,6 @@ public final class Grasscutter {
* Getters for the various server components. * Getters for the various server components.
*/ */
public static ConfigContainer getConfig() {
return config;
}
public static Language getLanguage() {
return language;
}
public static void setLanguage(Language language) {
Grasscutter.language = language;
}
public static Language getLanguage(String langCode) { public static Language getLanguage(String langCode) {
return Language.getLanguage(langCode); return Language.getLanguage(langCode);
} }
@ -250,10 +238,6 @@ public final class Grasscutter {
return Grasscutter.runModeOverride != null ? Grasscutter.runModeOverride : SERVER.runMode; return Grasscutter.runModeOverride != null ? Grasscutter.runModeOverride : SERVER.runMode;
} }
public static Logger getLogger() {
return log;
}
public static LineReader getConsole() { public static LineReader getConsole() {
if (consoleLineReader == null) { if (consoleLineReader == null) {
Terminal terminal = null; Terminal terminal = null;
@ -274,38 +258,14 @@ public final class Grasscutter {
return consoleLineReader; return consoleLineReader;
} }
public static HttpServer getHttpServer() {
return httpServer;
}
public static GameServer getGameServer() {
return gameServer;
}
public static PluginManager getPluginManager() {
return pluginManager;
}
public static AuthenticationSystem getAuthenticationSystem() {
return authenticationSystem;
}
public static PermissionHandler getPermissionHandler() {
return permissionHandler;
}
public static int getCurrentDayOfWeek() {
return day;
}
/* /*
* Utility methods. * Utility methods.
*/ */
public static void updateDayOfWeek() { public static void updateDayOfWeek() {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
day = calendar.get(Calendar.DAY_OF_WEEK); Grasscutter.currentDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
Grasscutter.getLogger().debug("Set day of week to "+day); Grasscutter.getLogger().debug("Set day of week to "+currentDayOfWeek);
} }
public static void startConsole() { public static void startConsole() {
@ -333,8 +293,8 @@ public final class Grasscutter {
Grasscutter.getLogger().info("EOF detected."); Grasscutter.getLogger().info("EOF detected.");
continue; continue;
} catch (IOError e) { } catch (IOError e) {
Grasscutter.getLogger().error("An IO error occurred.", e); Grasscutter.getLogger().error("An IO error occurred while trying to read from console.", e);
continue; return;
} }
isLastInterrupted = false; isLastInterrupted = false;
@ -346,24 +306,6 @@ public final class Grasscutter {
} }
} }
/**
* Sets the authentication system for the server.
*
* @param authenticationSystem The authentication system to use.
*/
public static void setAuthenticationSystem(AuthenticationSystem authenticationSystem) {
Grasscutter.authenticationSystem = authenticationSystem;
}
/**
* Sets the permission handler for the server.
*
* @param permissionHandler The permission handler to use.
*/
public static void setPermissionHandler(PermissionHandler permissionHandler) {
Grasscutter.permissionHandler = permissionHandler;
}
/* /*
* Enums for the configuration. * Enums for the configuration.
*/ */

View File

@ -33,21 +33,18 @@ public class CommandHelpers {
} }
public static <T> List<String> parseIntParameters(List<String> args, @Nonnull T params, Map<Pattern, BiConsumer<T, Integer>> map) { public static <T> List<String> parseIntParameters(List<String> args, @Nonnull T params, Map<Pattern, BiConsumer<T, Integer>> map) {
for (int i = args.size() - 1; i >= 0; i--) { args.removeIf(arg -> {
String arg = args.get(i).toLowerCase(); var argL = arg.toLowerCase();
boolean deleteArg = false; boolean deleteArg = false;
int argNum;
for (var entry : map.entrySet()) { for (var entry : map.entrySet()) {
if ((argNum = matchIntOrNeg(entry.getKey(), arg)) != -1) { int argNum = matchIntOrNeg(entry.getKey(), argL);
if (argNum != -1) {
entry.getValue().accept(params, argNum); entry.getValue().accept(params, argNum);
deleteArg = true; deleteArg = true;
break;
} }
} }
if (deleteArg) { return deleteArg;
args.remove(i); });
}
}
return args; return args;
} }
} }

View File

@ -89,7 +89,7 @@ public final class CommandMap {
} }
public List<Command> getAnnotationsAsList() { public List<Command> getAnnotationsAsList() {
return new LinkedList<>(this.annotations.values()); return new ArrayList<>(this.annotations.values());
} }
public Map<String, Command> getAnnotations() { public Map<String, Command> getAnnotations() {
@ -102,7 +102,7 @@ public final class CommandMap {
* @return All command handlers as a list. * @return All command handlers as a list.
*/ */
public List<CommandHandler> getHandlersAsList() { public List<CommandHandler> getHandlersAsList() {
return new LinkedList<>(this.commands.values()); return new ArrayList<>(this.commands.values());
} }
public Map<String, CommandHandler> getHandlers() { public Map<String, CommandHandler> getHandlers() {
@ -234,8 +234,8 @@ public final class CommandMap {
// Parse message. // Parse message.
String[] split = rawMessage.split(" "); String[] split = rawMessage.split(" ");
List<String> args = new LinkedList<>(Arrays.asList(split)); String label = split[0].toLowerCase();
String label = args.remove(0).toLowerCase(); List<String> args = new ArrayList<>(Arrays.asList(split).subList(1, split.length));
String playerId = (player == null) ? consoleId : player.getAccount().getId(); String playerId = (player == null) ? consoleId : player.getAccount().getId();
// Check for special cases - currently only target command. // Check for special cases - currently only target command.

View File

@ -9,7 +9,11 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "quest", usage = {"(add|finish) [<questId>]"}, permission = "player.quest", permissionTargeted = "player.quest.others") @Command(label = "quest",
aliases = {"q"},
usage = {"(add|finish) [<questId>]"},
permission = "player.quest",
permissionTargeted = "player.quest.others")
public final class QuestCommand implements CommandHandler { public final class QuestCommand implements CommandHandler {
@Override @Override

View File

@ -9,6 +9,7 @@ import emu.grasscutter.game.player.Player;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Objects;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@ -78,9 +79,10 @@ public final class SendMailCommand implements CommandHandler {
Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail); Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail);
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", mailBuilder.recipient)); CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", mailBuilder.recipient));
} else { } else {
for (Player player : DatabaseHelper.getAllPlayers()) { DatabaseHelper.getByGameClass(Player.class).forEach(player -> {
Grasscutter.getGameServer().getPlayerByUid(player.getUid(), true).sendMail(mailBuilder.mail); var onlinePlayer = Grasscutter.getGameServer().getPlayerByUid(player.getUid(), false);
} Objects.requireNonNullElse(onlinePlayer, player).sendMail(mailBuilder.mail);
});
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_all_done")); CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_all_done"));
} }
mailBeingConstructed.remove(senderId); mailBeingConstructed.remove(senderId);

View File

@ -1,10 +1,7 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.AvatarTalentData;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
@ -12,14 +9,13 @@ import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.World; import emu.grasscutter.game.world.World;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.util.List; import java.util.List;
@Command( @Command(
label = "setConst", label = "setConst",
aliases = {"setconstellation"}, aliases = {"setconstellation"},
usage = {"<constellation level>"}, usage = {"<constellation level> [all]"},
permission = "player.setconstellation", permission = "player.setconstellation",
permissionTargeted = "player.setconstellation.others") permissionTargeted = "player.setconstellation.others")
public final class SetConstCommand implements CommandHandler { public final class SetConstCommand implements CommandHandler {
@ -29,21 +25,28 @@ public final class SetConstCommand implements CommandHandler {
sendUsageMessage(sender); sendUsageMessage(sender);
return; return;
} }
try { try {
int constLevel = Integer.parseInt(args.get(0)); int constLevel = Integer.parseInt(args.get(0));
// Check if level is out of range
if (constLevel < -1 || constLevel > 6) { if (constLevel < -1 || constLevel > 6) {
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.range_error"); CommandHandler.sendTranslatedMessage(sender, "commands.setConst.range_error");
return; return;
} }
// If it's either empty or anything else other than "all" just do normal setConstellation
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity(); if (args.size() == 1) {
if (entity == null) return; EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
Avatar avatar = entity.getAvatar(); if (entity == null) return;
Avatar avatar = entity.getAvatar();
this.setConstellation(targetPlayer, avatar, constLevel); this.setConstellation(targetPlayer, avatar, constLevel);
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.success", avatar.getAvatarData().getName(), constLevel);
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.success", avatar.getAvatarData().getName(), constLevel); return;
}
// Check if there's an additional argument which is "all", if it does then go setAllConstellation
if (args.size() > 1 && args.get(1).equalsIgnoreCase("all")) {
this.setAllConstellation(targetPlayer, constLevel);
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.successall", constLevel);
}
else sendUsageMessage(sender);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendTranslatedMessage(sender, "commands.setConst.level_error"); CommandHandler.sendTranslatedMessage(sender, "commands.setConst.level_error");
} }
@ -55,13 +58,7 @@ public final class SetConstCommand implements CommandHandler {
// force player to reload scene when necessary // force player to reload scene when necessary
if (constLevel < currentConstLevel) { if (constLevel < currentConstLevel) {
World world = player.getWorld(); this.reloadScene(player);
Scene scene = player.getScene();
Position pos = player.getPosition();
world.transferPlayerToScene(player, 1, pos);
world.transferPlayerToScene(player, scene.getId(), pos);
scene.broadcastPacket(new PacketSceneEntityAppearNotify(player));
} }
// ensure that all changes are visible to the player // ensure that all changes are visible to the player
@ -69,4 +66,24 @@ public final class SetConstCommand implements CommandHandler {
avatar.recalcStats(true); avatar.recalcStats(true);
avatar.save(); avatar.save();
} }
private void setAllConstellation(Player player, int constLevel) {
player.getAvatars().forEach(avatar -> {
avatar.forceConstellationLevel(constLevel);
avatar.recalcConstellations();
avatar.recalcStats(true);
avatar.save();
});
// Just reload scene once, shorter than having to check for each constLevel < currentConstLevel
this.reloadScene(player);
}
private void reloadScene(Player player) {
World world = player.getWorld();
Scene scene = player.getScene();
Position pos = player.getPosition();
world.transferPlayerToScene(player, 1, pos);
world.transferPlayerToScene(player, scene.getId(), pos);
scene.broadcastPacket(new PacketSceneEntityAppearNotify(player));
}
} }

View File

@ -67,9 +67,10 @@ public final class SetStatsCommand implements CommandHandler {
// Compatibility aliases // Compatibility aliases
this.stats.put("mhp", this.stats.get("maxhp")); this.stats.put("mhp", this.stats.get("maxhp"));
this.stats.put("hp", new Stat(FightProperty.FIGHT_PROP_CUR_HP)); // Overrides FIGHT_PROP_HP this.stats.put("hp", this.stats.get("_cur_hp")); // Overrides FIGHT_PROP_HP
this.stats.put("atk", new Stat(FightProperty.FIGHT_PROP_CUR_ATTACK)); // Overrides FIGHT_PROP_ATTACK this.stats.put("atk", this.stats.get("_cur_attack")); // Overrides FIGHT_PROP_ATTACK
this.stats.put("atkb", new Stat(FightProperty.FIGHT_PROP_BASE_ATTACK)); // This doesn't seem to get used to recalculate ATK, so it's only useful for stuff like Bennett's buff. this.stats.put("def", this.stats.get("_cur_defense")); // Overrides FIGHT_PROP_DEFENSE
this.stats.put("atkb", this.stats.get("_base_attack")); // This doesn't seem to get used to recalculate ATK, so it's only useful for stuff like Bennett's buff.
this.stats.put("eanemo", this.stats.get("anemo%")); this.stats.put("eanemo", this.stats.get("anemo%"));
this.stats.put("ecryo", this.stats.get("cryo%")); this.stats.put("ecryo", this.stats.get("cryo%"));
this.stats.put("edendro", this.stats.get("dendro%")); this.stats.put("edendro", this.stats.get("dendro%"));

View File

@ -25,7 +25,7 @@ import static emu.grasscutter.utils.Language.translate;
@Command( @Command(
label = "spawn", label = "spawn",
aliases = {"drop"}, aliases = {"drop", "s"},
usage = { usage = {
"<itemId> [x<amount>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>", "<itemId> [x<amount>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>",
"<gadgetId> [x<amount>] [state<state>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>", "<gadgetId> [x<amount>] [state<state>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>] [blk<blockId>] [grp<groupId>] [cfg<configId>] <x> <y> <z>",

View File

@ -1,5 +1,6 @@
package emu.grasscutter.config; package emu.grasscutter.config;
import ch.qos.logback.classic.Level;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerDebugMode; import emu.grasscutter.Grasscutter.ServerDebugMode;
@ -101,6 +102,7 @@ public class ConfigContainer {
public Game game = new Game(); public Game game = new Game();
public Dispatch dispatch = new Dispatch(); public Dispatch dispatch = new Dispatch();
public DebugMode debugMode = new DebugMode();
} }
public static class Language { public static class Language {
@ -150,6 +152,10 @@ public class ConfigContainer {
public int kcpInterval = 20; public int kcpInterval = 20;
/* Controls whether packets should be logged in console or not */ /* Controls whether packets should be logged in console or not */
public ServerDebugMode logPackets = ServerDebugMode.NONE; public ServerDebugMode logPackets = ServerDebugMode.NONE;
/* Show packet payload in console or no (in any case the payload is shown in encrypted view) */
public Boolean isShowPacketPayload = false;
/* Show annoying loop packets or no */
public Boolean isShowLoopPackets = false;
public GameOptions gameOptions = new GameOptions(); public GameOptions gameOptions = new GameOptions();
public JoinOptions joinOptions = new JoinOptions(); public JoinOptions joinOptions = new JoinOptions();
@ -163,9 +169,33 @@ public class ConfigContainer {
public String defaultName = "Grasscutter"; public String defaultName = "Grasscutter";
/* Controls whether http requests should be logged in console or not */
public ServerDebugMode logRequests = ServerDebugMode.NONE; public ServerDebugMode logRequests = ServerDebugMode.NONE;
} }
/* Debug options container, used when jar launch argument is -debug | -debugall and override default values
* (see StartupArguments.enableDebug) */
public static class DebugMode {
/* Log level of the main server code (works only with -debug arg) */
public Level serverLoggerLevel = Level.DEBUG;
/* Log level of the third-party services (works only with -debug arg):
javalin, quartz, reflections, jetty, mongodb.driver*/
public Level servicesLoggersLevel = Level.INFO;
/* Controls whether packets should be logged in console or not */
public ServerDebugMode logPackets = ServerDebugMode.ALL;
/* Show packet payload in console or no (in any case the payload is shown in encrypted view) */
public Boolean isShowPacketPayload = false;
/* Show annoying loop packets or no */
public Boolean isShowLoopPackets = false;
/* Controls whether http requests should be logged in console or not */
public ServerDebugMode logRequests = ServerDebugMode.ALL;
}
public static class Encryption { public static class Encryption {
public boolean useEncryption = true; public boolean useEncryption = true;
/* Should 'https' be appended to URLs? */ /* Should 'https' be appended to URLs? */

View File

@ -38,6 +38,7 @@ public final class Configuration extends ConfigContainer {
public static final HTTP HTTP_INFO = config.server.http; public static final HTTP HTTP_INFO = config.server.http;
public static final Game GAME_INFO = config.server.game; public static final Game GAME_INFO = config.server.game;
public static final Dispatch DISPATCH_INFO = config.server.dispatch; public static final Dispatch DISPATCH_INFO = config.server.dispatch;
public static final DebugMode DEBUG_MODE_INFO = config.server.debugMode;
public static final Encryption HTTP_ENCRYPTION = config.server.http.encryption; public static final Encryption HTTP_ENCRYPTION = config.server.http.encryption;
public static final Policies HTTP_POLICIES = config.server.http.policies; public static final Policies HTTP_POLICIES = config.server.http.policies;

View File

@ -5,6 +5,8 @@ import emu.grasscutter.server.http.handlers.GachaHandler;
import emu.grasscutter.tools.Tools; import emu.grasscutter.tools.Tools;
import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.JsonUtils; import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.TsvUtils;
import lombok.val;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@ -88,6 +90,17 @@ public class DataLoader {
} }
} }
public static <T> List<T> loadTableToList(String resourcePath, Class<T> classType) throws IOException {
val path = FileUtils.getDataPathTsjJsonTsv(resourcePath);
Grasscutter.getLogger().info("Loading data table from: "+path);
return switch (FileUtils.getFileExtension(path)) {
case "json" -> JsonUtils.loadToList(path, classType);
case "tsj" -> TsvUtils.loadTsjToListSetField(path, classType);
case "tsv" -> TsvUtils.loadTsvToListSetField(path, classType);
default -> null;
};
}
public static void checkAllFiles() { public static void checkAllFiles() {
try { try {
List<Path> filenames = FileUtils.getPathsFromResource("/defaults/data/"); List<Path> filenames = FileUtils.getPathsFromResource("/defaults/data/");

View File

@ -11,7 +11,10 @@ import emu.grasscutter.game.world.SpawnDataEntry;
import emu.grasscutter.game.world.SpawnDataEntry.GridBlockId; import emu.grasscutter.game.world.SpawnDataEntry.GridBlockId;
import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry; import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
import emu.grasscutter.scripts.SceneIndexManager; import emu.grasscutter.scripts.SceneIndexManager;
import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.JsonUtils; import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.TsvUtils;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.ints.IntArraySet;
@ -23,6 +26,8 @@ import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -32,8 +37,9 @@ import static emu.grasscutter.utils.Language.translate;
public class ResourceLoader { public class ResourceLoader {
private static final List<String> loadedResources = new ArrayList<>(); private static final Set<String> loadedResources = new CopyOnWriteArraySet<>();
// Get a list of all resource classes, sorted by loadPriority
public static List<Class<?>> getResourceDefClasses() { public static List<Class<?>> getResourceDefClasses() {
Reflections reflections = new Reflections(ResourceLoader.class.getPackage().getName()); Reflections reflections = new Reflections(ResourceLoader.class.getPackage().getName());
Set<?> classes = reflections.getSubTypesOf(GameResource.class); Set<?> classes = reflections.getSubTypesOf(GameResource.class);
@ -51,6 +57,25 @@ public class ResourceLoader {
return classList; return classList;
} }
// Get a list containing sets of all resource classes, sorted by loadPriority
protected static List<Set<Class<?>>> getResourceDefClassesPrioritySets() {
val reflections = new Reflections(ResourceLoader.class.getPackage().getName());
val classes = reflections.getSubTypesOf(GameResource.class);
val priorities = ResourceType.LoadPriority.getInOrder();
Grasscutter.getLogger().debug("Priorities are "+priorities);
val map = new LinkedHashMap<ResourceType.LoadPriority, Set<Class<?>>>(priorities.size());
priorities.forEach(p -> map.put(p, new HashSet<>()));
classes.forEach(c -> {
// val c = (Class<?>) o;
val annotation = c.getAnnotation(ResourceType.class);
if (annotation != null) {
map.get(annotation.loadPriority()).add(c);
}
});
return List.copyOf(map.values());
}
private static boolean loadedAll = false; private static boolean loadedAll = false;
public static void loadAll() { public static void loadAll() {
if (loadedAll) return; if (loadedAll) return;
@ -86,48 +111,66 @@ public class ResourceLoader {
} }
public static void loadResources(boolean doReload) { public static void loadResources(boolean doReload) {
for (Class<?> resourceDefinition : getResourceDefClasses()) { long startTime = System.nanoTime();
ResourceType type = resourceDefinition.getAnnotation(ResourceType.class); val errors = new ConcurrentLinkedQueue<Pair<String, Exception>>(); // Logger in a parallel stream will deadlock
if (type == null) { getResourceDefClassesPrioritySets().forEach(classes -> {
continue; classes.stream()
} .parallel().unordered()
.forEach(c -> {
val type = c.getAnnotation(ResourceType.class);
if (type == null) return;
@SuppressWarnings("rawtypes") val map = GameData.getMapByResourceDef(c);
Int2ObjectMap map = GameData.getMapByResourceDef(resourceDefinition); if (map == null) return;
if (map == null) { try {
continue; loadFromResource(c, type, map, doReload);
} } catch (Exception e) {
errors.add(Pair.of(Arrays.toString(type.name()), e));
try { }
loadFromResource(resourceDefinition, type, map, doReload); });
} catch (Exception e) { });
Grasscutter.getLogger().error("Error loading resource file: " + Arrays.toString(type.name()), e.getLocalizedMessage()); errors.forEach(pair -> Grasscutter.getLogger().error("Error loading resource file: " + pair.left(), pair.right()));
} long endTime = System.nanoTime();
} long ns = (endTime - startTime); //divide by 1000000 to get milliseconds.
Grasscutter.getLogger().debug("Loading resources took "+ns+"ns == "+ns/1000000+"ms");
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
protected static void loadFromResource(Class<?> c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception { protected static void loadFromResource(Class<?> c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception {
if (!loadedResources.contains(c.getSimpleName()) || doReload) { val simpleName = c.getSimpleName();
if (doReload || !loadedResources.contains(simpleName)) {
for (String name : type.name()) { for (String name : type.name()) {
loadFromResource(c, name, map); loadFromResource(c, FileUtils.getExcelPath(name), map);
} }
loadedResources.add(c.getSimpleName()); loadedResources.add(simpleName);
Grasscutter.getLogger().debug("Loaded " + map.size() + " " + c.getSimpleName() + "s.");
} }
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
protected static <T> void loadFromResource(Class<T> c, String fileName, Int2ObjectMap map) throws Exception { protected static <T> void loadFromResource(Class<T> c, Path filename, Int2ObjectMap map) throws Exception {
List<T> list = JsonUtils.loadToList(getResourcePath("ExcelBinOutput/" + fileName), c); val results = switch (FileUtils.getFileExtension(filename)) {
case "json" -> JsonUtils.loadToList(filename, c);
for (T o : list) { case "tsj" -> TsvUtils.loadTsjToListSetField(filename, c);
case "tsv" -> TsvUtils.loadTsvToListSetField(filename, c);
default -> null;
};
if (results == null) return;
results.forEach(o -> {
GameResource res = (GameResource) o; GameResource res = (GameResource) o;
res.onLoad(); res.onLoad();
map.put(res.getId(), res); map.put(res.getId(), res);
} });
}
@SuppressWarnings({"rawtypes", "unchecked"})
protected static <T> void loadFromResource(Class<T> c, String fileName, Int2ObjectMap map) throws Exception {
JsonUtils.loadToList(getResourcePath("ExcelBinOutput/" + fileName), c).forEach(o -> {
GameResource res = (GameResource) o;
res.onLoad();
map.put(res.getId(), res);
});
} }
public class ScenePointConfig { // Sadly this doesn't work as a local class in loadScenePoints() public class ScenePointConfig { // Sadly this doesn't work as a local class in loadScenePoints()

View File

@ -2,6 +2,8 @@ package emu.grasscutter.data;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.stream.Stream;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ResourceType { public @interface ResourceType {
@ -28,5 +30,9 @@ public @interface ResourceType {
public int value() { public int value() {
return value; return value;
} }
public static List<LoadPriority> getInOrder() {
return Stream.of(LoadPriority.values()).sorted((x, y) -> y.value() - x.value()).toList();
}
} }
} }

View File

@ -13,18 +13,15 @@ import java.util.List;
@Getter @Getter
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class ActivityWatcherData extends GameResource { public class ActivityWatcherData extends GameResource {
@Getter(onMethod = @__(@Override))
int id; int id;
int rewardID; int rewardID;
int progress; int progress;
WatcherTrigger triggerConfig; WatcherTrigger triggerConfig;
@Override
public int getId() {
return this.id;
}
@Override @Override
public void onLoad() { public void onLoad() {
triggerConfig.paramList = triggerConfig.paramList.stream().filter(x -> !x.isBlank()).toList(); triggerConfig.paramList = triggerConfig.paramList.stream().filter(x -> (x != null) && !x.isBlank()).toList();
triggerConfig.watcherTriggerType = WatcherTriggerType.getTypeByName(triggerConfig.triggerType); triggerConfig.watcherTriggerType = WatcherTriggerType.getTypeByName(triggerConfig.triggerType);
} }

View File

@ -44,6 +44,7 @@ public class AvatarData extends GameResource {
private float criticalHurt; private float criticalHurt;
private List<PropGrowCurve> propGrowCurves; private List<PropGrowCurve> propGrowCurves;
@Getter(onMethod = @__(@Override))
private int id; private int id;
// Transient // Transient
@ -60,11 +61,6 @@ public class AvatarData extends GameResource {
@Getter private int nameCardRewardId; @Getter private int nameCardRewardId;
@Getter private int nameCardId; @Getter private int nameCardId;
@Override
public int getId() {
return this.id;
}
public float getBaseHp(int level) { public float getBaseHp(int level) {
try { try {
return this.hpBase * this.hpGrowthCurve[level - 1]; return this.hpBase * this.hpGrowthCurve[level - 1];

View File

@ -7,26 +7,18 @@ import emu.grasscutter.game.props.ElementType;
import lombok.Getter; import lombok.Getter;
@ResourceType(name = "AvatarSkillExcelConfigData.json", loadPriority = LoadPriority.HIGHEST) @ResourceType(name = "AvatarSkillExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)
@Getter
public class AvatarSkillData extends GameResource { public class AvatarSkillData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
@Getter private float cdTime; private float cdTime;
@Getter private int costElemVal; private int costElemVal;
@Getter private int maxChargeNum; private int maxChargeNum;
@Getter private int triggerID; private int triggerID;
@Getter private boolean isAttackCameraLock; private boolean isAttackCameraLock;
@Getter private int proudSkillGroupId; private int proudSkillGroupId;
@Getter private ElementType costElemType; private ElementType costElemType;
@Getter private long nameTextMapHash; private long nameTextMapHash;
@Getter private long descTextMapHash; private long descTextMapHash;
@Getter private String abilityName; private String abilityName;
@Override
public int getId() {
return this.id;
}
@Override
public void onLoad() {
}
} }

View File

@ -18,31 +18,27 @@ import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter; import lombok.Getter;
@ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH) @ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH)
@Getter
public class AvatarSkillDepotData extends GameResource { public class AvatarSkillDepotData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
@Getter private int energySkill; private int energySkill;
@Getter private int attackModeSkill; private int attackModeSkill;
@Getter private List<Integer> skills; private List<Integer> skills;
@Getter private List<Integer> subSkills; private List<Integer> subSkills;
@Getter private List<String> extraAbilities; private List<String> extraAbilities;
@Getter private List<Integer> talents; private List<Integer> talents;
@Getter private List<InherentProudSkillOpens> inherentProudSkillOpens; private List<InherentProudSkillOpens> inherentProudSkillOpens;
@Getter private String talentStarName; private String talentStarName;
@Getter private String skillDepotAbilityGroup; private String skillDepotAbilityGroup;
// Transient // Transient
@Getter private AvatarSkillData energySkillData; private AvatarSkillData energySkillData;
@Getter private ElementType elementType; private ElementType elementType;
@Getter private IntList abilities; private IntList abilities;
@Getter private int talentCostItemId; private int talentCostItemId;
@Override
public int getId() {
return this.id;
}
public void setAbilities(AbilityEmbryoEntry info) { public void setAbilities(AbilityEmbryoEntry info) {
this.abilities = new IntArrayList(info.getAbilities().length); this.abilities = new IntArrayList(info.getAbilities().length);
@ -77,9 +73,10 @@ public class AvatarSkillDepotData extends GameResource {
.ifPresent(itemId -> this.talentCostItemId = itemId); .ifPresent(itemId -> this.talentCostItemId = itemId);
} }
@Getter
public static class InherentProudSkillOpens { public static class InherentProudSkillOpens {
@Getter private int proudSkillGroupId; private int proudSkillGroupId;
@Getter private int needAvatarPromoteLevel; private int needAvatarPromoteLevel;
} }
public IntStream getSkillsAndEnergySkill() { public IntStream getSkillsAndEnergySkill() {

View File

@ -9,16 +9,14 @@ import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.BattlePassMissionRefreshType; import emu.grasscutter.game.props.BattlePassMissionRefreshType;
import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus; import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
@ResourceType(name = {"BattlePassMissionExcelConfigData.json"}) @ResourceType(name = {"BattlePassMissionExcelConfigData.json"})
@Getter @Getter
public class BattlePassMissionData extends GameResource { public class BattlePassMissionData extends GameResource {
private int addPoint; @Getter(onMethod = @__(@Override))
private int id; private int id;
private int addPoint;
private int scheduleId; private int scheduleId;
private int progress; private int progress;
private TriggerConfig triggerConfig; private TriggerConfig triggerConfig;
@ -26,48 +24,46 @@ public class BattlePassMissionData extends GameResource {
private transient Set<Integer> mainParams; private transient Set<Integer> mainParams;
@Override public WatcherTriggerType getTriggerType() {
public int getId() { return this.getTriggerConfig().getTriggerType();
return this.id;
} }
public WatcherTriggerType getTriggerType() { public boolean isCycleRefresh() {
return this.getTriggerConfig().getTriggerType(); return getRefreshType() == null || getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE;
} }
public boolean isCycleRefresh() {
return getRefreshType() == null || getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE;
}
public boolean isValidRefreshType() { public boolean isValidRefreshType() {
return getRefreshType() == null || return getRefreshType() == null ||
getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE || getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE ||
getScheduleId() == 2701; getScheduleId() == 2701;
} }
@Override @Override
public void onLoad() { public void onLoad() {
if (this.getTriggerConfig() != null && getTriggerConfig().getParamList()[0].length() > 0) { if (this.getTriggerConfig() != null) {
this.mainParams = Arrays.stream(getTriggerConfig().getParamList()[0].split("[:;,]")).map(Integer::parseInt).collect(Collectors.toSet()); var params = getTriggerConfig().getParamList()[0];
} if ((params != null) && !params.isEmpty()) {
this.mainParams = Arrays.stream(params.split("[:;,]")).map(Integer::parseInt).collect(Collectors.toSet());
}
}
} }
@Getter @Getter
public static class TriggerConfig { public static class TriggerConfig {
private WatcherTriggerType triggerType; private WatcherTriggerType triggerType;
private String[] paramList; private String[] paramList;
} }
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() { public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder(); var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
protoBuilder protoBuilder
.setMissionId(getId()) .setMissionId(getId())
.setTotalProgress(this.getProgress()) .setTotalProgress(this.getProgress())
.setRewardBattlePassPoint(this.getAddPoint()) .setRewardBattlePassPoint(this.getAddPoint())
.setMissionStatus(MissionStatus.MISSION_STATUS_UNFINISHED) .setMissionStatus(MissionStatus.MISSION_STATUS_UNFINISHED)
.setMissionType(this.getRefreshType() == null ? 0 : this.getRefreshType().getValue()); .setMissionType(this.getRefreshType() == null ? 0 : this.getRefreshType().getValue());
return protoBuilder.build(); return protoBuilder.build();
} }
} }

View File

@ -7,40 +7,39 @@ import emu.grasscutter.data.ResourceType;
import lombok.Getter; import lombok.Getter;
@ResourceType(name = "BlossomRefreshExcelConfigData.json") @ResourceType(name = "BlossomRefreshExcelConfigData.json")
@Getter
public class BlossomRefreshExcelConfigData extends GameResource { public class BlossomRefreshExcelConfigData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
// Map details // Map details
@Getter private long nameTextMapHash; private long nameTextMapHash;
@Getter private long descTextMapHash; private long descTextMapHash;
@Getter private String icon; private String icon;
@Getter private String clientShowType; // BLOSSOM_SHOWTYPE_CHALLENGE, BLOSSOM_SHOWTYPE_NPCTALK private String clientShowType; // BLOSSOM_SHOWTYPE_CHALLENGE, BLOSSOM_SHOWTYPE_NPCTALK
// Refresh details // Refresh details
@Getter private String refreshType; // Leyline blossoms, magical ore outcrops private String refreshType; // Leyline blossoms, magical ore outcrops
@Getter private int refreshCount; // Number of entries to spawn at refresh (1 for each leyline type for each city, 4 for magical ore for each city) private int refreshCount; // Number of entries to spawn at refresh (1 for each leyline type for each city, 4 for magical ore for each city)
@Getter private String refreshTime; // Server time-of-day to refresh at private String refreshTime; // Server time-of-day to refresh at
@Getter private RefreshCond[] refreshCondVec; // AR requirements etc. private RefreshCond[] refreshCondVec; // AR requirements etc.
@Getter private int cityId; private int cityId;
@Getter private int blossomChestId; // 1 for mora, 2 for exp private int blossomChestId; // 1 for mora, 2 for exp
@Getter private Drop[] dropVec; private Drop[] dropVec;
// Unknown details // Unknown details
// @Getter private int reviseLevel; // @Getter private int reviseLevel;
// @Getter private int campUpdateNeedCount; // Always 1 if specified // @Getter private int campUpdateNeedCount; // Always 1 if specified
@Override @Getter
public int getId() {
return id;
}
public static class Drop { public static class Drop {
@Getter int dropId; int dropId;
@Getter int previewReward; int previewReward;
} }
@Getter
public static class RefreshCond { public static class RefreshCond {
@Getter String type; String type;
@Getter List<Integer> param; List<Integer> param;
} }
} }

View File

@ -8,27 +8,23 @@ import lombok.Setter;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
@ResourceType(name = "ChapterExcelConfigData.json") @ResourceType(name = "ChapterExcelConfigData.json")
@Getter @Getter
@Setter @Setter // TODO: remove on next API break
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class ChapterData extends GameResource { public class ChapterData extends GameResource {
@Getter(onMethod = @__(@Override))
int id; int id;
int beginQuestId; int beginQuestId;
int endQuestId; int endQuestId;
int needPlayerLevel; int needPlayerLevel;
// Why public? TODO: privatise next API break
public static final Map<Integer, ChapterData> beginQuestChapterMap = new HashMap<>(); public static final Map<Integer, ChapterData> beginQuestChapterMap = new HashMap<>();
public static final Map<Integer, ChapterData> endQuestChapterMap = new HashMap<>(); public static final Map<Integer, ChapterData> endQuestChapterMap = new HashMap<>();
@Override
public int getId() {
return this.id;
}
@Override @Override
public void onLoad() { public void onLoad() {
beginQuestChapterMap.put(beginQuestId, this); beginQuestChapterMap.put(beginQuestId, this);

View File

@ -22,9 +22,4 @@ public class CityData extends GameResource {
public int getId() { public int getId() {
return this.cityId; return this.cityId;
} }
@Override
public void onLoad() {
super.onLoad();
}
} }

View File

@ -7,18 +7,15 @@ import emu.grasscutter.data.ResourceType;
import lombok.Getter; import lombok.Getter;
@ResourceType(name = {"AnimalCodexExcelConfigData.json"}) @ResourceType(name = {"AnimalCodexExcelConfigData.json"})
@Getter
public class CodexAnimalData extends GameResource { public class CodexAnimalData extends GameResource {
@Getter(onMethod = @__(@Override))
private int Id; private int Id;
@Getter private String type; private String type;
@Getter private int describeId; private int describeId;
@Getter private int sortOrder; private int sortOrder;
@SerializedName(value="countType", alternate={"OCCLHPBCDGL"}) @SerializedName(value="countType", alternate={"OCCLHPBCDGL"})
@Getter private CountType countType; private CountType countType;
@Override
public int getId() {
return Id;
}
public enum CountType { public enum CountType {
CODEX_COUNT_TYPE_KILL, CODEX_COUNT_TYPE_KILL,

View File

@ -8,19 +8,15 @@ import lombok.Getter;
import java.util.List; import java.util.List;
@ResourceType(name = {"CompoundExcelConfigData.json"},loadPriority = ResourceType.LoadPriority.LOW) @ResourceType(name = {"CompoundExcelConfigData.json"},loadPriority = ResourceType.LoadPriority.LOW)
@Getter
public class CompoundData extends GameResource { public class CompoundData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
private int groupId;
@Override private int rankLevel;
public int getId() {return this.id;} private boolean isDefaultUnlocked;
@Getter private int groupId; private int costTime;
@Getter private int rankLevel; private int queueSize;
@Getter private boolean isDefaultUnlocked; private List<ItemParamData> inputVec;
@Getter private int costTime; private List<ItemParamData> outputVec;
@Getter private int queueSize;
@Getter private List<ItemParamData> inputVec;
@Getter private List<ItemParamData> outputVec;
@Override
public void onLoad(){}
} }

View File

@ -9,21 +9,15 @@ import emu.grasscutter.data.common.ItemParamData;
import lombok.Getter; import lombok.Getter;
@ResourceType(name = {"CookRecipeExcelConfigData.json"}, loadPriority = LoadPriority.LOW) @ResourceType(name = {"CookRecipeExcelConfigData.json"}, loadPriority = LoadPriority.LOW)
@Getter
public class CookRecipeData extends GameResource { public class CookRecipeData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
@Getter private int rankLevel; private int rankLevel;
@Getter boolean isDefaultUnlocked; private boolean isDefaultUnlocked;
@Getter int maxProficiency; private int maxProficiency;
@Getter List<ItemParamData> qualityOutputVec; private List<ItemParamData> qualityOutputVec;
@Getter List<ItemParamData> inputVec; private List<ItemParamData> inputVec;
@Override
public int getId() {
return this.id;
}
@Override
public void onLoad() {
}
} }

View File

@ -7,9 +7,11 @@ import emu.grasscutter.data.ResourceType;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
@ResourceType(name = "DailyDungeonConfigData.json") @ResourceType(name = "DailyDungeonConfigData.json")
public class DailyDungeonData extends GameResource { public class DailyDungeonData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
private int[] monday; private int[] monday;
private int[] tuesday; private int[] tuesday;
@ -26,11 +28,6 @@ public class DailyDungeonData extends GameResource {
this.map = new Int2ObjectOpenHashMap<>(); this.map = new Int2ObjectOpenHashMap<>();
} }
@Override
public int getId() {
return this.id;
}
public int[] getDungeonsByDay(int day) { public int[] getDungeonsByDay(int day) {
return map.getOrDefault(day, empty); return map.getOrDefault(day, empty);
} }

View File

@ -3,51 +3,28 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter;
import emu.grasscutter.game.props.SceneType;
@ResourceType(name = "DungeonExcelConfigData.json") @ResourceType(name = "DungeonExcelConfigData.json")
public class DungeonData extends GameResource { public class DungeonData extends GameResource {
private int id; @Getter(onMethod = @__(@Override))
private int sceneId; private int id;
private int showLevel; @Getter private int sceneId;
private int passRewardPreviewID; @Getter private int showLevel;
private String involveType; // TODO enum private int passRewardPreviewID;
private String involveType; // TODO enum
private RewardPreviewData previewData; private RewardPreviewData previewData;
private int statueCostID; @Getter private int statueCostID;
private int statueCostCount; @Getter private int statueCostCount;
@Override public RewardPreviewData getRewardPreview() {return previewData;}
public int getId() {
return this.id;
}
public int getSceneId() { @Override
return sceneId; public void onLoad() {
} if (this.passRewardPreviewID > 0) {
this.previewData = GameData.getRewardPreviewDataMap().get(this.passRewardPreviewID);
public int getShowLevel() { }
return showLevel; }
}
public RewardPreviewData getRewardPreview() {
return previewData;
}
public int getStatueCostID() {
return statueCostID;
}
public int getStatueCostCount() {
return statueCostCount;
}
@Override
public void onLoad() {
if (this.passRewardPreviewID > 0) {
this.previewData = GameData.getRewardPreviewDataMap().get(this.passRewardPreviewID);
}
}
} }

View File

@ -7,19 +7,10 @@ import lombok.Setter;
@ResourceType(name = "DungeonEntryExcelConfigData.json") @ResourceType(name = "DungeonEntryExcelConfigData.json")
@Getter @Getter
@Setter @Setter // TODO: remove this next API break
public class DungeonEntryData extends GameResource { public class DungeonEntryData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id;
private int dungeonEntryId; private int dungeonEntryId;
private int sceneId; private int sceneId;
private int id;
@Override
public int getId() {
return this.id;
}
@Override
public void onLoad() {
}
} }

View File

@ -6,9 +6,12 @@ import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import lombok.Getter;
@ResourceType(name = {"ForgeExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST) @ResourceType(name = {"ForgeExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST)
@Getter
public class ForgeData extends GameResource { public class ForgeData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
private int playerLevel; private int playerLevel;
private int forgeType; private int forgeType;
@ -21,57 +24,4 @@ public class ForgeData extends GameResource {
private int priority; private int priority;
private int forgePoint; private int forgePoint;
private List<ItemParamData> materialItems; private List<ItemParamData> materialItems;
@Override
public int getId() {
return this.id;
}
public int getPlayerLevel() {
return playerLevel;
}
public int getForgeType() {
return forgeType;
}
public int getResultItemId() {
return resultItemId;
}
public int getResultItemCount() {
return resultItemCount;
}
public int getForgeTime() {
return forgeTime;
}
public int getQueueNum() {
return queueNum;
}
public int getScoinCost() {
return scoinCost;
}
public int getPriority() {
return priority;
}
public int getForgePoint() {
return forgePoint;
}
public List<ItemParamData> getMaterialItems() {
return materialItems;
}
public int getShowItemId() {
return showItemId;
}
@Override
public void onLoad() {
}
} }

View File

@ -3,9 +3,12 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.EntityType; import emu.grasscutter.game.props.EntityType;
import lombok.Getter;
@ResourceType(name = "GadgetExcelConfigData.json") @ResourceType(name = "GadgetExcelConfigData.json")
@Getter
public class GadgetData extends GameResource { public class GadgetData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
private EntityType type; private EntityType type;
@ -15,42 +18,4 @@ public class GadgetData extends GameResource {
private String itemJsonName; private String itemJsonName;
private long nameTextMapHash; private long nameTextMapHash;
private int campID; private int campID;
@Override
public int getId() {
return this.id;
}
public EntityType getType() {
return type;
}
public String getJsonName() {
return jsonName;
}
public boolean isInteractive() {
return isInteractive;
}
public String[] getTags() {
return tags;
}
public String getItemJsonName() {
return itemJsonName;
}
public long getNameTextMapHash() {
return nameTextMapHash;
}
public int getCampID() {
return campID;
}
@Override
public void onLoad() {
}
} }

View File

@ -29,9 +29,4 @@ public class HomeWorldLevelData extends GameResource {
public int getId() { public int getId() {
return level; return level;
} }
@Override
public void onLoad() {
super.onLoad();
}
} }

View File

@ -4,7 +4,6 @@ import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
@ -14,6 +13,7 @@ import java.util.List;
@Getter @Getter
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class InvestigationMonsterData extends GameResource { public class InvestigationMonsterData extends GameResource {
@Getter(onMethod = @__(@Override))
int id; int id;
int cityId; int cityId;
List<Integer> monsterIdList; List<Integer> monsterIdList;
@ -23,10 +23,6 @@ public class InvestigationMonsterData extends GameResource {
String monsterCategory; String monsterCategory;
CityData cityData; CityData cityData;
@Override
public int getId() {
return this.id;
}
@Override @Override
public void onLoad() { public void onLoad() {

View File

@ -25,6 +25,7 @@ import lombok.Getter;
@Getter @Getter
public class ItemData extends GameResource { public class ItemData extends GameResource {
// Main // Main
@Getter(onMethod = @__(@Override))
private int id; private int id;
private int stackLimit = 1; private int stackLimit = 1;
private int maxUseCount; private int maxUseCount;
@ -81,17 +82,12 @@ public class ItemData extends GameResource {
private List<Integer> furnType; private List<Integer> furnType;
private List<Integer> furnitureGadgetID; private List<Integer> furnitureGadgetID;
@SerializedName(value="roomSceneId", alternate={"DANFGGLKLNO", "JFDLJGDFIGL", "OHIANNAEEAK"}) @SerializedName(value="roomSceneId", alternate={"BMEPAMCNABE", "DANFGGLKLNO", "JFDLJGDFIGL", "OHIANNAEEAK"})
private int roomSceneId; private int roomSceneId;
// Custom // Custom
private transient IntSet addPropLevelSet; private transient IntSet addPropLevelSet;
@Override
public int getId() {
return this.id;
}
public WeaponProperty[] getWeaponProperties() { public WeaponProperty[] getWeaponProperties() {
return this.weaponProp; return this.weaponProp;
} }

View File

@ -1,19 +1,28 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List; import java.util.List;
import java.util.Set;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.PropGrowCurve; import emu.grasscutter.data.common.PropGrowCurve;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.MonsterType; import emu.grasscutter.game.props.MonsterType;
import lombok.Getter;
@ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW) @ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW)
@Getter
public class MonsterData extends GameResource { public class MonsterData extends GameResource {
private int id; static public Set<FightProperty> definedFightProperties = Set.of(FightProperty.FIGHT_PROP_BASE_HP, FightProperty.FIGHT_PROP_BASE_ATTACK, FightProperty.FIGHT_PROP_BASE_DEFENSE, FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, FightProperty.FIGHT_PROP_FIRE_SUB_HURT, FightProperty.FIGHT_PROP_ELEC_SUB_HURT, FightProperty.FIGHT_PROP_WATER_SUB_HURT, FightProperty.FIGHT_PROP_GRASS_SUB_HURT, FightProperty.FIGHT_PROP_WIND_SUB_HURT, FightProperty.FIGHT_PROP_ROCK_SUB_HURT, FightProperty.FIGHT_PROP_ICE_SUB_HURT);
private String monsterName; @Getter(onMethod = @__(@Override))
private int id;
private String monsterName;
private MonsterType type; private MonsterType type;
private String serverScript; private String serverScript;
private List<Integer> affix; private List<Integer> affix;
@ -28,9 +37,14 @@ public class MonsterData extends GameResource {
private int describeId; private int describeId;
private int combatBGMLevel; private int combatBGMLevel;
private int entityBudgetLevel; private int entityBudgetLevel;
private float hpBase;
private float attackBase; @SerializedName("hpBase")
private float defenseBase; private float baseHp;
@SerializedName("attackBase")
private float baseAttack;
@SerializedName("defenseBase")
private float baseDefense;
private float fireSubHurt; private float fireSubHurt;
private float elecSubHurt; private float elecSubHurt;
private float grassSubHurt; private float grassSubHurt;
@ -47,154 +61,44 @@ public class MonsterData extends GameResource {
private int weaponId; private int weaponId;
private MonsterDescribeData describeData; private MonsterDescribeData describeData;
@Override public float getFightProperty(FightProperty prop) {
public int getId() { return switch (prop) {
return this.id; case FIGHT_PROP_BASE_HP -> this.baseHp;
} case FIGHT_PROP_BASE_ATTACK -> this.baseAttack;
case FIGHT_PROP_BASE_DEFENSE -> this.baseDefense;
case FIGHT_PROP_PHYSICAL_SUB_HURT -> this.physicalSubHurt;
case FIGHT_PROP_FIRE_SUB_HURT -> this.fireSubHurt;
case FIGHT_PROP_ELEC_SUB_HURT -> this.elecSubHurt;
case FIGHT_PROP_WATER_SUB_HURT -> this.waterSubHurt;
case FIGHT_PROP_GRASS_SUB_HURT -> this.grassSubHurt;
case FIGHT_PROP_WIND_SUB_HURT -> this.windSubHurt;
case FIGHT_PROP_ROCK_SUB_HURT -> this.rockSubHurt;
case FIGHT_PROP_ICE_SUB_HURT -> this.iceSubHurt;
default -> 0f;
};
}
public String getMonsterName() { @Override
return monsterName; public void onLoad() {
} this.describeData = GameData.getMonsterDescribeDataMap().get(this.getDescribeId());
public MonsterType getType() { for (int id : this.equips) {
return type; if (id == 0) {
} continue;
}
GadgetData gadget = GameData.getGadgetDataMap().get(id);
if (gadget == null) {
continue;
}
if (gadget.getItemJsonName().equals("Default_MonsterWeapon")) {
this.weaponId = id;
}
}
}
public String getServerScript() { @Getter
return serverScript; public class HpDrops {
} private int DropId;
private int HpPercent;
public List<Integer> getAffix() { }
return affix;
}
public String getAi() {
return ai;
}
public int[] getEquips() {
return equips;
}
public List<HpDrops> getHpDrops() {
return hpDrops;
}
public int getKillDropId() {
return killDropId;
}
public String getExcludeWeathers() {
return excludeWeathers;
}
public int getFeatureTagGroupID() {
return featureTagGroupID;
}
public int getMpPropID() {
return mpPropID;
}
public String getSkin() {
return skin;
}
public int getDescribeId() {
return describeId;
}
public int getCombatBGMLevel() {
return combatBGMLevel;
}
public int getEntityBudgetLevel() {
return entityBudgetLevel;
}
public float getBaseHp() {
return hpBase;
}
public float getBaseAttack() {
return attackBase;
}
public float getBaseDefense() {
return defenseBase;
}
public float getElecSubHurt() {
return elecSubHurt;
}
public float getGrassSubHurt() {
return grassSubHurt;
}
public float getWaterSubHurt() {
return waterSubHurt;
}
public float getWindSubHurt() {
return windSubHurt;
}
public float getIceSubHurt() {
return iceSubHurt;
}
public float getPhysicalSubHurt() {
return physicalSubHurt;
}
public List<PropGrowCurve> getPropGrowCurves() {
return propGrowCurves;
}
public long getNameTextMapHash() {
return nameTextMapHash;
}
public int getCampID() {
return campID;
}
public MonsterDescribeData getDescribeData() {
return describeData;
}
public int getWeaponId() {
return weaponId;
}
@Override
public void onLoad() {
this.describeData = GameData.getMonsterDescribeDataMap().get(this.getDescribeId());
for (int id : this.equips) {
if (id == 0) {
continue;
}
GadgetData gadget = GameData.getGadgetDataMap().get(id);
if (gadget == null) {
continue;
}
if (gadget.getItemJsonName().equals("Default_MonsterWeapon")) {
this.weaponId = id;
}
}
}
public class HpDrops {
private int DropId;
private int HpPercent;
public int getDropId(){
return this.DropId;
}
public int getHpPercent(){
return this.HpPercent;
}
}
} }

View File

@ -3,33 +3,14 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import lombok.Getter;
@ResourceType(name = "MonsterDescribeExcelConfigData.json", loadPriority = LoadPriority.HIGH) @ResourceType(name = "MonsterDescribeExcelConfigData.json", loadPriority = LoadPriority.HIGH)
@Getter
public class MonsterDescribeData extends GameResource { public class MonsterDescribeData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
private long nameTextMapHash; private long nameTextMapHash;
private int titleID; private int titleID;
private int specialNameLabID; private int specialNameLabID;
@Override
public int getId() {
return id;
}
public long getNameTextMapHash() {
return nameTextMapHash;
}
public int getTitleID() {
return titleID;
}
public int getSpecialNameLabID() {
return specialNameLabID;
}
@Override
public void onLoad() {
}
} }

View File

@ -10,12 +10,8 @@ import lombok.experimental.FieldDefaults;
@Getter @Getter
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class MusicGameBasicData extends GameResource { public class MusicGameBasicData extends GameResource {
@Getter(onMethod = @__(@Override))
int id; int id;
int musicID; int musicID;
int musicLevel; int musicLevel;
@Override
public int getId() {
return this.id;
}
} }

View File

@ -2,12 +2,15 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter;
@ResourceType(name = "NpcExcelConfigData.json") @ResourceType(name = "NpcExcelConfigData.json")
@Getter
public class NpcData extends GameResource { public class NpcData extends GameResource {
private int id; @Getter(onMethod = @__(@Override))
private int id;
private String jsonName; private String jsonName;
private String alias; private String alias;
private String scriptDataPath; private String scriptDataPath;
private String luaDataPath; private String luaDataPath;
@ -19,54 +22,4 @@ public class NpcData extends GameResource {
private long nameTextMapHash; private long nameTextMapHash;
private int campID; private int campID;
@Override
public int getId() {
return this.id;
}
public String getJsonName() {
return jsonName;
}
public String getAlias() {
return alias;
}
public String getScriptDataPath() {
return scriptDataPath;
}
public String getLuaDataPath() {
return luaDataPath;
}
public boolean isIsInteractive() {
return isInteractive;
}
public boolean isHasMove() {
return hasMove;
}
public String getDyePart() {
return dyePart;
}
public String getBillboardIcon() {
return billboardIcon;
}
public long getNameTextMapHash() {
return nameTextMapHash;
}
public int getCampID() {
return campID;
}
@Override
public void onLoad() {
}
} }

View File

@ -3,15 +3,14 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
@ResourceType(name = "OpenStateConfigData.json", loadPriority = ResourceType.LoadPriority.HIGHEST) @ResourceType(name = "OpenStateConfigData.json", loadPriority = ResourceType.LoadPriority.HIGHEST)
public class OpenStateData extends GameResource { public class OpenStateData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
@Getter private boolean defaultState; @Getter private boolean defaultState;
@Getter private boolean allowClientOpen; @Getter private boolean allowClientOpen;
@ -32,11 +31,6 @@ public class OpenStateData extends GameResource {
OPEN_STATE_COND_PARENT_QUEST; OPEN_STATE_COND_PARENT_QUEST;
} }
@Override
public int getId() {
return this.id;
}
@Override @Override
public void onLoad() { public void onLoad() {
// Add this open state to the global list. // Add this open state to the global list.

View File

@ -11,18 +11,13 @@ import java.util.List;
@ResourceType(name = "PersonalLineExcelConfigData.json") @ResourceType(name = "PersonalLineExcelConfigData.json")
@Getter @Getter
@Setter @Setter // TODO: remove setters next API break
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class PersonalLineData extends GameResource { public class PersonalLineData extends GameResource {
@Getter(onMethod = @__(@Override))
int id; int id;
int avatarID; int avatarID;
List<Integer> preQuestId; List<Integer> preQuestId;
int startQuestId; int startQuestId;
int chapterId; int chapterId;
@Override
public int getId() {
return this.id;
}
} }

View File

@ -1,46 +1,23 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import lombok.Getter;
@ResourceType(name = "ReliquaryAffixExcelConfigData.json") @ResourceType(name = "ReliquaryAffixExcelConfigData.json")
@Getter
public class ReliquaryAffixData extends GameResource { public class ReliquaryAffixData extends GameResource {
private int id; @Getter(onMethod = @__(@Override))
private int id;
private int depotId; private int depotId;
private int groupId; private int groupId;
private FightProperty propType; @SerializedName("propType")
private float propValue; private FightProperty fightProp;
private int weight; private float propValue;
private int upgradeWeight; private int weight;
private int upgradeWeight;
@Override
public int getId() {
return id;
}
public int getDepotId() {
return depotId;
}
public int getGroupId() {
return groupId;
}
public float getPropValue() {
return propValue;
}
public int getWeight() {
return weight;
}
public int getUpgradeWeight() {
return upgradeWeight;
}
public FightProperty getFightProp() {
return propType;
}
} }

View File

@ -7,36 +7,19 @@ import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import it.unimi.dsi.fastutil.ints.Int2FloatMap; import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import lombok.Getter;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@ResourceType(name = "ReliquaryLevelExcelConfigData.json") @ResourceType(name = "ReliquaryLevelExcelConfigData.json")
public class ReliquaryLevelData extends GameResource { public class ReliquaryLevelData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id; private int id;
private Int2FloatMap propMap; private Int2FloatMap propMap;
private int rank; @Getter private int rank;
private int level; @Getter private int level;
private int exp; @Getter private int exp;
private List<RelicLevelProperty> addProps; private List<RelicLevelProperty> addProps;
@Override
public int getId() {
return this.id;
}
public int getRank() {
return rank;
}
public int getLevel() {
return level;
}
public int getExp() {
return exp;
}
public float getPropValue(FightProperty prop) { public float getPropValue(FightProperty prop) {
return getPropValue(prop.getId()); return getPropValue(prop.getId());
} }
@ -54,16 +37,9 @@ public class ReliquaryLevelData extends GameResource {
} }
} }
@Getter
public class RelicLevelProperty { public class RelicLevelProperty {
private String propType; private String propType;
private float value; private float value;
public String getPropType() {
return propType;
}
public float getValue() {
return value;
}
} }
} }

View File

@ -1,31 +1,20 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import lombok.Getter;
@ResourceType(name = "ReliquaryMainPropExcelConfigData.json") @ResourceType(name = "ReliquaryMainPropExcelConfigData.json")
@Getter
public class ReliquaryMainPropData extends GameResource { public class ReliquaryMainPropData extends GameResource {
private int id; @Getter(onMethod = @__(@Override))
private int id;
private int propDepotId; private int propDepotId;
private FightProperty propType; @SerializedName("propType")
private int weight; private FightProperty fightProp;
private int weight;
@Override
public int getId() {
return id;
}
public int getPropDepotId() {
return propDepotId;
}
public int getWeight() {
return weight;
}
public FightProperty getFightProp() {
return propType;
}
} }

View File

@ -1,43 +1,35 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.SceneType; import lombok.Getter;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.common.ItemParamStringData; import emu.grasscutter.data.common.ItemParamStringData;
@ResourceType(name = "RewardPreviewExcelConfigData.json", loadPriority = LoadPriority.HIGH) @ResourceType(name = "RewardPreviewExcelConfigData.json", loadPriority = LoadPriority.HIGH)
public class RewardPreviewData extends GameResource { public class RewardPreviewData extends GameResource {
private int id; @Getter(onMethod = @__(@Override))
private ItemParamStringData[] previewItems; private int id;
private ItemParamData[] previewItemsArray; private ItemParamStringData[] previewItems;
private ItemParamData[] previewItemsArray;
@Override public ItemParamData[] getPreviewItems() {
public int getId() { return previewItemsArray;
return this.id; }
}
public ItemParamData[] getPreviewItems() { @Override
return previewItemsArray; public void onLoad() {
} if (this.previewItems != null && this.previewItems.length > 0) {
this.previewItemsArray = Arrays.stream(this.previewItems)
@Override .filter(d -> d.getId() > 0 && d.getCount() != null && !d.getCount().isEmpty())
public void onLoad() { .map(ItemParamStringData::toItemParamData)
if (this.previewItems != null && this.previewItems.length > 0) { .toArray(size -> new ItemParamData[size]);
this.previewItemsArray = Arrays.stream(this.previewItems) } else {
.filter(d -> d.getId() > 0 && d.getCount() != null && !d.getCount().isEmpty()) this.previewItemsArray = new ItemParamData[0];
.map(ItemParamStringData::toItemParamData) }
.toArray(size -> new ItemParamData[size]); }
} else {
this.previewItemsArray = new ItemParamData[0];
}
}
} }

View File

@ -1,32 +1,19 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameData; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.SceneType; import emu.grasscutter.game.props.SceneType;
import lombok.Getter;
@ResourceType(name = "SceneExcelConfigData.json") @ResourceType(name = "SceneExcelConfigData.json")
@Getter
public class SceneData extends GameResource { public class SceneData extends GameResource {
private int id; @Getter(onMethod = @__(@Override))
private SceneType type; private int id;
private String scriptData; @SerializedName("type")
private SceneType sceneType;
@Override private String scriptData;
public int getId() {
return this.id;
}
public SceneType getSceneType() {
return type;
}
public String getScriptData() {
return scriptData;
}
@Override
public void onLoad() {
}
} }

View File

@ -2,10 +2,11 @@ package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.Getter;
@ResourceType(name = "TowerFloorExcelConfigData.json") @ResourceType(name = "TowerFloorExcelConfigData.json")
@Getter
public class TowerFloorData extends GameResource { public class TowerFloorData extends GameResource {
private int floorId; private int floorId;
private int floorIndex; private int floorIndex;
private int levelGroupId; private int levelGroupId;
@ -17,33 +18,4 @@ public class TowerFloorData extends GameResource {
public int getId() { public int getId() {
return this.floorId; return this.floorId;
} }
@Override
public void onLoad() {
super.onLoad();
}
public int getFloorId() {
return floorId;
}
public int getFloorIndex() {
return floorIndex;
}
public int getLevelGroupId() {
return levelGroupId;
}
public int getOverrideMonsterLevel() {
return overrideMonsterLevel;
}
public int getTeamNum() {
return teamNum;
}
public int getFloorLevelConfigId() {
return floorLevelConfigId;
}
} }

View File

@ -1,6 +1,7 @@
package emu.grasscutter.database; package emu.grasscutter.database;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import com.mongodb.client.result.DeleteResult; import com.mongodb.client.result.DeleteResult;
@ -154,6 +155,11 @@ public final class DatabaseHelper {
DatabaseManager.getAccountDatastore().find(Account.class).filter(Filters.eq("id", target.getId())).delete(); DatabaseManager.getAccountDatastore().find(Account.class).filter(Filters.eq("id", target.getId())).delete();
} }
public static <T> Stream<T> getByGameClass(Class<T> classType) {
return DatabaseManager.getGameDatastore().find(classType).stream();
}
@Deprecated(forRemoval = true)
public static List<Player> getAllPlayers() { public static List<Player> getAllPlayers() {
return DatabaseManager.getGameDatastore().find(Player.class).stream().toList(); return DatabaseManager.getGameDatastore().find(Player.class).stream().toList();
} }

View File

@ -58,6 +58,7 @@ import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass.ShowAvatarInfo;
import emu.grasscutter.net.proto.ShowEquipOuterClass.ShowEquip; import emu.grasscutter.net.proto.ShowEquipOuterClass.ShowEquip;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
@ -89,7 +90,7 @@ public class Avatar {
private float currentEnergy; private float currentEnergy;
@Transient @Getter private final Int2ObjectMap<GameItem> equips; @Transient @Getter private final Int2ObjectMap<GameItem> equips;
@Transient private final Int2FloatOpenHashMap fightProp; @Transient @Getter private final Int2FloatOpenHashMap fightProperties;
@Transient @Getter private final Int2FloatOpenHashMap fightPropOverrides; @Transient @Getter private final Int2FloatOpenHashMap fightPropOverrides;
@Transient @Getter private Set<String> extraAbilityEmbryos; @Transient @Getter private Set<String> extraAbilityEmbryos;
@ -115,7 +116,7 @@ public class Avatar {
@Deprecated // Do not use. Morhpia only! @Deprecated // Do not use. Morhpia only!
public Avatar() { public Avatar() {
this.equips = new Int2ObjectOpenHashMap<>(); this.equips = new Int2ObjectOpenHashMap<>();
this.fightProp = new Int2FloatOpenHashMap(); this.fightProperties = new Int2FloatOpenHashMap();
this.fightPropOverrides = new Int2FloatOpenHashMap(); this.fightPropOverrides = new Int2FloatOpenHashMap();
this.extraAbilityEmbryos = new HashSet<>(); this.extraAbilityEmbryos = new HashSet<>();
this.fetters = new ArrayList<>(); // TODO Move to avatar this.fetters = new ArrayList<>(); // TODO Move to avatar
@ -276,10 +277,6 @@ public class Avatar {
} }
} }
public Int2FloatOpenHashMap getFightProperties() {
return fightProp;
}
public void setFightProperty(FightProperty prop, float value) { public void setFightProperty(FightProperty prop, float value) {
this.getFightProperties().put(prop.getId(), value); this.getFightProperties().put(prop.getId(), value);
} }
@ -399,9 +396,9 @@ public class Avatar {
public void recalcStats(boolean forceSendAbilityChange) { public void recalcStats(boolean forceSendAbilityChange) {
// Setup // Setup
AvatarData data = this.getAvatarData(); var data = this.getAvatarData();
AvatarPromoteData promoteData = GameData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel()); var promoteData = GameData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel());
Int2IntOpenHashMap setMap = new Int2IntOpenHashMap(); var setMap = new Int2IntOpenHashMap();
// Extra ability embryos // Extra ability embryos
Set<String> prevExtraAbilityEmbryos = this.getExtraAbilityEmbryos(); Set<String> prevExtraAbilityEmbryos = this.getExtraAbilityEmbryos();
@ -579,21 +576,11 @@ public class Avatar {
// Add any skill strings from this constellation // Add any skill strings from this constellation
// Set % stats // Set % stats
this.setFightProperty( FightProperty.forEachCompoundProperty(c -> this.setFightProperty(c.getResult(),
FightProperty.FIGHT_PROP_MAX_HP, this.getFightProperty(c.getFlat()) + (this.getFightProperty(c.getBase()) * (1f + this.getFightProperty(c.getPercent())))));
(getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP)
);
this.setFightProperty(
FightProperty.FIGHT_PROP_CUR_ATTACK,
(getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK)
);
this.setFightProperty(
FightProperty.FIGHT_PROP_CUR_DEFENSE,
(getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE)
);
// Reapply all overrides // Reapply all overrides
this.fightProp.putAll(this.fightPropOverrides); this.fightProperties.putAll(this.fightPropOverrides);
// Set current hp // Set current hp
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
@ -809,12 +796,14 @@ public class Avatar {
if (level < 0) { // Special case for resetConst to remove inactive depots too if (level < 0) { // Special case for resetConst to remove inactive depots too
this.talentIdList.clear(); this.talentIdList.clear();
this.recalcStats(); this.recalcStats();
this.save();
return; return;
} }
this.talentIdList.removeAll(this.getTalentIdList()); // Only remove constellations from active depot this.talentIdList.removeAll(this.getTalentIdList()); // Only remove constellations from active depot
for (int i = 0; i < level; i++) for (int i = 0; i < level; i++)
this.unlockConstellation(true); this.unlockConstellation(true);
this.recalcStats(); this.recalcStats();
this.save();
} }
public boolean sendSkillExtraChargeMap() { public boolean sendSkillExtraChargeMap() {

View File

@ -1,124 +0,0 @@
package emu.grasscutter.game.avatar;
import java.util.stream.Stream;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public enum AvatarStat {
FIGHT_PROP_NONE(0),
FIGHT_PROP_BASE_HP(1),
FIGHT_PROP_HP(2),
FIGHT_PROP_HP_PERCENT(3),
FIGHT_PROP_BASE_ATTACK(4),
FIGHT_PROP_ATTACK(5),
FIGHT_PROP_ATTACK_PERCENT(6),
FIGHT_PROP_BASE_DEFENSE(7),
FIGHT_PROP_DEFENSE(8),
FIGHT_PROP_DEFENSE_PERCENT(9),
FIGHT_PROP_BASE_SPEED(10),
FIGHT_PROP_SPEED_PERCENT(11),
FIGHT_PROP_HP_MP_PERCENT(12),
FIGHT_PROP_ATTACK_MP_PERCENT(13),
FIGHT_PROP_CRITICAL(20),
FIGHT_PROP_ANTI_CRITICAL(21),
FIGHT_PROP_CRITICAL_HURT(22),
FIGHT_PROP_CHARGE_EFFICIENCY(23),
FIGHT_PROP_ADD_HURT(24),
FIGHT_PROP_SUB_HURT(25),
FIGHT_PROP_HEAL_ADD(26),
FIGHT_PROP_HEALED_ADD(27),
FIGHT_PROP_ELEMENT_MASTERY(28),
FIGHT_PROP_PHYSICAL_SUB_HURT(29),
FIGHT_PROP_PHYSICAL_ADD_HURT(30),
FIGHT_PROP_DEFENCE_IGNORE_RATIO(31),
FIGHT_PROP_DEFENCE_IGNORE_DELTA(32),
FIGHT_PROP_FIRE_ADD_HURT(40),
FIGHT_PROP_ELEC_ADD_HURT(41),
FIGHT_PROP_WATER_ADD_HURT(42),
FIGHT_PROP_GRASS_ADD_HURT(43),
FIGHT_PROP_WIND_ADD_HURT(44),
FIGHT_PROP_ROCK_ADD_HURT(45),
FIGHT_PROP_ICE_ADD_HURT(46),
FIGHT_PROP_HIT_HEAD_ADD_HURT(47),
FIGHT_PROP_FIRE_SUB_HURT(50),
FIGHT_PROP_ELEC_SUB_HURT(51),
FIGHT_PROP_WATER_SUB_HURT(52),
FIGHT_PROP_GRASS_SUB_HURT(53),
FIGHT_PROP_WIND_SUB_HURT(54),
FIGHT_PROP_ROCK_SUB_HURT(55),
FIGHT_PROP_ICE_SUB_HURT(56),
FIGHT_PROP_EFFECT_HIT(60),
FIGHT_PROP_EFFECT_RESIST(61),
FIGHT_PROP_FREEZE_RESIST(62),
FIGHT_PROP_TORPOR_RESIST(63),
FIGHT_PROP_DIZZY_RESIST(64),
FIGHT_PROP_FREEZE_SHORTEN(65),
FIGHT_PROP_TORPOR_SHORTEN(66),
FIGHT_PROP_DIZZY_SHORTEN(67),
FIGHT_PROP_MAX_FIRE_ENERGY(70),
FIGHT_PROP_MAX_ELEC_ENERGY(71),
FIGHT_PROP_MAX_WATER_ENERGY(72),
FIGHT_PROP_MAX_GRASS_ENERGY(73),
FIGHT_PROP_MAX_WIND_ENERGY(74),
FIGHT_PROP_MAX_ICE_ENERGY(75),
FIGHT_PROP_MAX_ROCK_ENERGY(76),
FIGHT_PROP_SKILL_CD_MINUS_RATIO(80),
FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81),
FIGHT_PROP_CUR_FIRE_ENERGY(1000),
FIGHT_PROP_CUR_ELEC_ENERGY(1001),
FIGHT_PROP_CUR_WATER_ENERGY(1002),
FIGHT_PROP_CUR_GRASS_ENERGY(1003),
FIGHT_PROP_CUR_WIND_ENERGY(1004),
FIGHT_PROP_CUR_ICE_ENERGY(1005),
FIGHT_PROP_CUR_ROCK_ENERGY(1006),
FIGHT_PROP_CUR_HP(1010),
FIGHT_PROP_MAX_HP(2000),
FIGHT_PROP_CUR_ATTACK(2001),
FIGHT_PROP_CUR_DEFENSE(2002),
FIGHT_PROP_CUR_SPEED(2003),
FIGHT_PROP_NONEXTRA_ATTACK(3000),
FIGHT_PROP_NONEXTRA_DEFENSE(3001),
FIGHT_PROP_NONEXTRA_CRITICAL(3002),
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003),
FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004),
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005),
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006),
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007),
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008),
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009),
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010),
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011),
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012),
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013),
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014),
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015),
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016),
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017),
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018),
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019),
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020),
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021),
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022),
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023),
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024);
private final int id;
private static final Int2ObjectMap<AvatarStat> map = new Int2ObjectOpenHashMap<>();
static {
Stream.of(values()).forEach(e -> map.put(e.getId(), e));
}
private AvatarStat(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static AvatarStat getStatById(int value) {
return map.getOrDefault(value, FIGHT_PROP_NONE);
}
}

View File

@ -21,7 +21,6 @@ import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason;
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType; import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
@ -38,20 +37,25 @@ import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.ProtoHelper;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.Int2FloatMap; import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import lombok.Getter;
import lombok.val; import lombok.val;
public class EntityAvatar extends GameEntity { public class EntityAvatar extends GameEntity {
private final Avatar avatar; @Getter private final Avatar avatar;
private PlayerDieType killedType; @Getter private PlayerDieType killedType;
private int killedBy; @Getter private int killedBy;
public EntityAvatar(Avatar avatar) {
this(null, avatar);
}
public EntityAvatar(Scene scene, Avatar avatar) { public EntityAvatar(Scene scene, Avatar avatar) {
super(scene); super(scene);
this.avatar = avatar; this.avatar = avatar;
this.avatar.setCurrentEnergy(); this.avatar.setCurrentEnergy();
this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR); if (scene != null)
this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR);
GameItem weapon = this.getAvatar().getWeapon(); GameItem weapon = this.getAvatar().getWeapon();
if (weapon != null) { if (weapon != null) {
@ -59,47 +63,20 @@ public class EntityAvatar extends GameEntity {
} }
} }
public EntityAvatar(Avatar avatar) { public Player getPlayer() {return this.avatar.getPlayer();}
super(null);
this.avatar = avatar;
this.avatar.setCurrentEnergy();
}
public Player getPlayer() {
return avatar.getPlayer();
}
@Override @Override
public Position getPosition() { public Position getPosition() {return getPlayer().getPosition();}
return getPlayer().getPosition();
}
@Override @Override
public Position getRotation() { public Position getRotation() {return getPlayer().getRotation();}
return getPlayer().getRotation();
}
public Avatar getAvatar() {
return avatar;
}
public int getKilledBy() {
return killedBy;
}
public PlayerDieType getKilledType() {
return killedType;
}
@Override @Override
public boolean isAlive() { public boolean isAlive() {
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f; return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
} }
@Override @Override public Int2FloatMap getFightProperties() {return getAvatar().getFightProperties();}
public Int2FloatOpenHashMap getFightProperties() {
return getAvatar().getFightProperties();
}
public int getWeaponEntityId() { public int getWeaponEntityId() {
if (getAvatar().getWeapon() != null) { if (getAvatar().getWeapon() != null) {
@ -145,11 +122,8 @@ public class EntityAvatar extends GameEntity {
public void clearEnergy(ChangeEnergyReason reason) { public void clearEnergy(ChangeEnergyReason reason) {
// Fight props. // Fight props.
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); val curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp(); float curEnergy = this.getFightProperty(curEnergyProp);
// Get max energy.
float maxEnergy = this.avatar.getFightProperty(maxEnergyProp);
// Set energy to zero. // Set energy to zero.
this.avatar.setCurrentEnergy(curEnergyProp, 0); this.avatar.setCurrentEnergy(curEnergyProp, 0);
@ -158,7 +132,7 @@ public class EntityAvatar extends GameEntity {
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp)); this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
if (reason == ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START) { if (reason == ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START) {
this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, -maxEnergy, reason)); this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, -curEnergy, reason));
} }
} }
@ -167,18 +141,16 @@ public class EntityAvatar extends GameEntity {
} }
public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) { public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) {
// Get current and maximum energy for this avatar. // Get current and maximum energy for this avatar.
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); val elementType = this.getAvatar().getSkillDepot().getElementType();
FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp(); val curEnergyProp = elementType.getCurEnergyProp();
val maxEnergyProp = elementType.getMaxEnergyProp();
float curEnergy = this.getFightProperty(curEnergyProp); float curEnergy = this.getFightProperty(curEnergyProp);
float maxEnergy = this.getFightProperty(maxEnergyProp); float maxEnergy = this.getFightProperty(maxEnergyProp);
// Get energy recharge.
float energyRecharge = this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY);
// Scale amount by energy recharge, if the amount is not flat. // Scale amount by energy recharge, if the amount is not flat.
if (!isFlat) { if (!isFlat) {
amount *= energyRecharge; amount *= this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY);
} }
// Determine the new energy value. // Determine the new energy value.

View File

@ -3,11 +3,23 @@ package emu.grasscutter.game.entity;
import emu.grasscutter.data.binout.ConfigGadget; import emu.grasscutter.data.binout.ConfigGadget;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.utils.Position;
import lombok.Getter;
public abstract class EntityBaseGadget extends GameEntity { public abstract class EntityBaseGadget extends GameEntity {
@Getter(onMethod = @__(@Override))
protected final Position position;
@Getter(onMethod = @__(@Override))
protected final Position rotation;
public EntityBaseGadget(Scene scene) { public EntityBaseGadget(Scene scene) {
this(scene, null, null);
}
public EntityBaseGadget(Scene scene, Position position, Position rotation) {
super(scene); super(scene);
this.position = position != null ? position.clone() : new Position();
this.rotation = rotation != null ? rotation.clone() : new Position();
} }
public abstract int getGadgetId(); public abstract int getGadgetId();

View File

@ -19,30 +19,28 @@ import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.net.proto.VectorOuterClass.Vector; import emu.grasscutter.net.proto.VectorOuterClass.Vector;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import lombok.Getter;
public class EntityClientGadget extends EntityBaseGadget { public class EntityClientGadget extends EntityBaseGadget {
private final Player owner; @Getter private final Player owner;
private final Position pos; @Getter(onMethod = @__(@Override))
private final Position rot; private int gadgetId;
private int configId; @Getter private int campId;
private int campId; @Getter private int campType;
private int campType; @Getter private int ownerEntityId;
private int ownerEntityId; @Getter private int targetEntityId;
private int targetEntityId; @Getter private boolean asyncLoad;
private boolean asyncLoad;
private int originalOwnerEntityId; @Getter private int originalOwnerEntityId;
public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) { public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) {
super(scene); super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles()));
this.owner = player; this.owner = player;
this.id = notify.getEntityId(); this.id = notify.getEntityId();
this.pos = new Position(notify.getInitPos()); this.gadgetId = notify.getConfigId();
this.rot = new Position(notify.getInitEulerAngles());
this.configId = notify.getConfigId();
this.campId = notify.getCampId(); this.campId = notify.getCampId();
this.campType = notify.getCampType(); this.campType = notify.getCampType();
this.ownerEntityId = notify.getPropOwnerEntityId(); this.ownerEntityId = notify.getPropOwnerEntityId();
@ -58,61 +56,12 @@ public class EntityClientGadget extends EntityBaseGadget {
} }
} }
@Override
public int getGadgetId() {
return configId;
}
public Player getOwner() {
return owner;
}
public int getCampId() {
return campId;
}
public int getCampType() {
return campType;
}
public int getOwnerEntityId() {
return ownerEntityId;
}
public int getTargetEntityId() {
return targetEntityId;
}
public boolean isAsyncLoad() {
return this.asyncLoad;
}
public int getOriginalOwnerEntityId() {
return this.originalOwnerEntityId;
}
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method. super.onDeath(killerId); // Invoke super class's onDeath() method.
} }
@Override @Override public Int2FloatMap getFightProperties() {return null;}
public Int2FloatOpenHashMap getFightProperties() {
// TODO Auto-generated method stub
return null;
}
@Override
public Position getPosition() {
// TODO Auto-generated method stub
return this.pos;
}
@Override
public Position getRotation() {
// TODO Auto-generated method stub
return this.rot;
}
@Override @Override
public SceneEntityInfo toProto() { public SceneEntityInfo toProto() {

View File

@ -6,8 +6,6 @@ import emu.grasscutter.data.excels.GadgetData;
import emu.grasscutter.game.entity.gadget.*; import emu.grasscutter.game.entity.gadget.*;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
@ -29,77 +27,47 @@ import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify; import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import java.util.Optional;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ToString(callSuper = true) @ToString(callSuper = true)
public class EntityGadget extends EntityBaseGadget { public class EntityGadget extends EntityBaseGadget {
private final GadgetData data; @Getter private final GadgetData gadgetData;
private final Position pos; @Getter(onMethod = @__(@Override)) @Setter
private final Position rot;
private int gadgetId; private int gadgetId;
private int state; @Getter @Setter private int state;
private int pointType; @Getter @Setter private int pointType;
private GadgetContent content; @Getter private GadgetContent content;
private Int2FloatOpenHashMap fightProp; @Getter(onMethod = @__(@Override), lazy = true)
private SceneGadget metaGadget; private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
@Getter @Setter private SceneGadget metaGadget;
@Nullable @Getter @Nullable @Getter
private ConfigGadget configGadget; private ConfigGadget configGadget;
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) { public EntityGadget(Scene scene, int gadgetId, Position pos) {
super(scene); this(scene, gadgetId, pos, null, null);
this.data = GameData.getGadgetDataMap().get(gadgetId);
if (data!=null && data.getJsonName()!=null) {
this.configGadget = GameData.getGadgetConfigData().get(data.getJsonName());
}
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
this.gadgetId = gadgetId;
this.pos = pos.clone();
this.rot = rot != null ? rot.clone() : new Position();
fillFightProps(configGadget);
} }
public EntityGadget(Scene scene, int gadgetId, Position pos) { public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) {
this(scene, gadgetId, pos, new Position()); this(scene, gadgetId, pos, rot, null);
} }
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) { public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
this(scene, gadgetId, pos, rot); super(scene, pos, rot);
this.content = content; this.gadgetData = GameData.getGadgetDataMap().get(gadgetId);
} this.configGadget = Optional.ofNullable(this.gadgetData).map(GadgetData::getJsonName).map(GameData.getGadgetConfigData()::get).orElse(null);
this.id = this.getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
public GadgetData getGadgetData() {
return data;
}
@Override
public Position getPosition() {
return this.pos;
}
@Override
public Position getRotation() {
return this.rot;
}
public int getGadgetId() {
return gadgetId;
}
public void setGadgetId(int gadgetId) {
this.gadgetId = gadgetId; this.gadgetId = gadgetId;
} this.content = content;
fillFightProps(configGadget);
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
} }
public void updateState(int state) { public void updateState(int state) {
@ -108,39 +76,18 @@ public class EntityGadget extends EntityBaseGadget {
getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_STATE_CHANGE, new ScriptArgs(state, this.getConfigId())); getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_STATE_CHANGE, new ScriptArgs(state, this.getConfigId()));
} }
public int getPointType() { @Deprecated(forRemoval = true) // Dont use!
return pointType;
}
public void setPointType(int pointType) {
this.pointType = pointType;
}
public GadgetContent getContent() {
return content;
}
@Deprecated // Dont use!
public void setContent(GadgetContent content) { public void setContent(GadgetContent content) {
this.content = this.content == null ? content : this.content; this.content = this.content == null ? content : this.content;
} }
public SceneGadget getMetaGadget() {
return metaGadget;
}
public void setMetaGadget(SceneGadget metaGadget) {
this.metaGadget = metaGadget;
}
// TODO refactor // TODO refactor
public void buildContent() { public void buildContent() {
if (getContent() != null || getGadgetData() == null || getGadgetData().getType() == null) { if (this.getContent() != null || this.getGadgetData() == null || this.getGadgetData().getType() == null) {
return; return;
} }
EntityType type = getGadgetData().getType(); this.content = switch (this.getGadgetData().getType()) {
GadgetContent content = switch (type) {
case GatherPoint -> new GadgetGatherPoint(this); case GatherPoint -> new GadgetGatherPoint(this);
case GatherObject -> new GadgetGatherObject(this); case GatherObject -> new GadgetGatherObject(this);
case Worktop -> new GadgetWorktop(this); case Worktop -> new GadgetWorktop(this);
@ -149,14 +96,6 @@ public class EntityGadget extends EntityBaseGadget {
case Gadget -> new GadgetObject(this); case Gadget -> new GadgetObject(this);
default -> null; default -> null;
}; };
this.content = content;
}
@Override
public Int2FloatOpenHashMap getFightProperties() {
if (this.fightProp == null) this.fightProp = new Int2FloatOpenHashMap();
return this.fightProp;
} }
@Override @Override
@ -216,7 +155,7 @@ public class EntityGadget extends EntityBaseGadget {
entityInfo.addPropList(pair); entityInfo.addPropList(pair);
// We do not use the getter to null check because the getter will create a fight prop map if it is null // We do not use the getter to null check because the getter will create a fight prop map if it is null
if (this.fightProp != null) { if (this.fightProperties != null) {
addAllFightPropsToEntityInfo(entityInfo); addAllFightPropsToEntityInfo(entityInfo);
} }

View File

@ -25,57 +25,33 @@ import emu.grasscutter.net.proto.VectorOuterClass.Vector;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp; import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import lombok.Getter;
public class EntityItem extends EntityBaseGadget { public class EntityItem extends EntityBaseGadget {
private final Position pos; @Getter private final GameItem item;
private final Position rot; @Getter private final long guid;
@Getter private final boolean share;
private final GameItem item;
private final long guid;
private final boolean share;
public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) { public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) {
super(scene); this(scene, player, itemData, pos, count, true);
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
this.pos = new Position(pos);
this.rot = new Position();
this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid();
this.item = new GameItem(itemData, count);
this.share = true;
} }
// In official game, some drop items are shared to all players, and some other items are independent to all players // In official game, some drop items are shared to all players, and some other items are independent to all players
// For example, if you killed a monster in MP mode, all players could get drops but rarity and number of them are different // For example, if you killed a monster in MP mode, all players could get drops but rarity and number of them are different
// but if you broke regional mine, when someone picked up the drop then it disappeared // but if you broke regional mine, when someone picked up the drop then it disappeared
public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) { public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) {
super(scene); super(scene, pos, null);
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
this.pos = new Position(pos);
this.rot = new Position();
this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid(); this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid();
this.item = new GameItem(itemData, count); this.item = new GameItem(itemData, count);
this.share = share; this.share = share;
} }
@Override
public int getId() {
return this.id;
}
private GameItem getItem() {
return this.item;
}
public ItemData getItemData() { public ItemData getItemData() {
return this.getItem().getItemData(); return this.getItem().getItemData();
} }
public long getGuid() {
return guid;
}
public int getCount() { public int getCount() {
return this.getItem().getCount(); return this.getItem().getCount();
} }
@ -85,24 +61,7 @@ public class EntityItem extends EntityBaseGadget {
return this.getItemData().getGadgetId(); return this.getItemData().getGadgetId();
} }
@Override @Override public Int2FloatMap getFightProperties() {return null;}
public Position getPosition() {
return this.pos;
}
@Override
public Position getRotation() {
return this.rot;
}
@Override
public Int2FloatOpenHashMap getFightProperties() {
return null;
}
public boolean isShare() {
return share;
}
@Override @Override
public void onInteract(Player player, GadgetInteractReq interactReq) { public void onInteract(Player player, GadgetInteractReq interactReq) {

View File

@ -1,14 +1,12 @@
package emu.grasscutter.game.entity; package emu.grasscutter.game.entity;
import emu.grasscutter.Grasscutter; import java.util.Optional;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.common.PropGrowCurve; import emu.grasscutter.data.common.PropGrowCurve;
import emu.grasscutter.data.excels.EnvAnimalGatherConfigData; import emu.grasscutter.data.excels.EnvAnimalGatherConfigData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.data.excels.MonsterCurveData; import emu.grasscutter.data.excels.MonsterCurveData;
import emu.grasscutter.data.excels.MonsterData; import emu.grasscutter.data.excels.MonsterData;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.EntityIdType;
@ -16,13 +14,11 @@ import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.VisionTypeOuterClass;
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.MonsterBornTypeOuterClass.MonsterBornType; import emu.grasscutter.net.proto.MonsterBornTypeOuterClass.MonsterBornType;
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
@ -35,31 +31,32 @@ import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
public class EntityMonster extends GameEntity { public class EntityMonster extends GameEntity {
private final MonsterData monsterData; @Getter private final MonsterData monsterData;
private final Int2FloatOpenHashMap fightProp; @Getter(onMethod = @__(@Override))
private final Int2FloatOpenHashMap fightProperties;
private final Position pos; @Getter(onMethod = @__(@Override))
private final Position rot; private final Position position;
private final Position bornPos; @Getter(onMethod = @__(@Override))
private final int level; private final Position rotation;
@Getter private final Position bornPos;
@Getter private final int level;
private int weaponEntityId; private int weaponEntityId;
private int poseId; @Getter @Setter private int poseId;
@Getter @Setter @Getter @Setter private int aiId = -1;
private int aiId=-1;
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) { public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
super(scene); super(scene);
this.id = getWorld().getNextEntityId(EntityIdType.MONSTER); this.id = getWorld().getNextEntityId(EntityIdType.MONSTER);
this.monsterData = monsterData; this.monsterData = monsterData;
this.fightProp = new Int2FloatOpenHashMap(); this.fightProperties = new Int2FloatOpenHashMap();
this.pos = new Position(pos); this.position = new Position(pos);
this.rot = new Position(); this.rotation = new Position();
this.bornPos = getPosition().clone(); this.bornPos = getPosition().clone();
this.level = level; this.level = level;
@ -71,59 +68,19 @@ public class EntityMonster extends GameEntity {
this.recalcStats(); this.recalcStats();
} }
@Override
public int getId() {
return this.id;
}
public MonsterData getMonsterData() {
return monsterData;
}
public int getMonsterWeaponId() { public int getMonsterWeaponId() {
return getMonsterData().getWeaponId(); return this.getMonsterData().getWeaponId();
} }
private int getMonsterId() { private int getMonsterId() {
return this.getMonsterData().getId(); return this.getMonsterData().getId();
} }
public int getLevel() {
return level;
}
@Override
public Position getPosition() {
return this.pos;
}
@Override
public Position getRotation() {
return this.rot;
}
public Position getBornPos() {
return bornPos;
}
@Override
public Int2FloatOpenHashMap getFightProperties() {
return fightProp;
}
@Override @Override
public boolean isAlive() { public boolean isAlive() {
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f; return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
} }
public int getPoseId() {
return poseId;
}
public void setPoseId(int poseId) {
this.poseId = poseId;
}
@Override @Override
public void onInteract(Player player, GadgetInteractReq interactReq) { public void onInteract(Player player, GadgetInteractReq interactReq) {
EnvAnimalGatherConfigData gatherData = GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId()); EnvAnimalGatherConfigData gatherData = GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId());
@ -163,27 +120,24 @@ public class EntityMonster extends GameEntity {
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method. super.onDeath(killerId); // Invoke super class's onDeath() method.
var scene = this.getScene();
var challenge = Optional.ofNullable(scene.getChallenge());
var scriptManager = scene.getScriptManager();
Optional.ofNullable(this.getSpawnEntry()).ifPresent(scene.getDeadSpawnedEntities()::add);
if (this.getSpawnEntry() != null) {
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
}
// first set the challenge data // first set the challenge data
if (getScene().getChallenge() != null) { challenge.ifPresent(c -> c.onMonsterDeath(this));
getScene().getChallenge().onMonsterDeath(this);
} if (scriptManager.isInit() && this.getGroupId() > 0) {
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) { Optional.ofNullable(scriptManager.getScriptMonsterSpawnService()).ifPresent(s -> s.onMonsterDead(this));
if (getScene().getScriptManager().getScriptMonsterSpawnService() != null) {
getScene().getScriptManager().getScriptMonsterSpawnService().onMonsterDead(this);
}
// prevent spawn monster after success // prevent spawn monster after success
if (getScene().getChallenge() != null && getScene().getChallenge().inProgress()) { if (challenge.map(c -> c.inProgress()).orElse(true))
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId())); scriptManager.callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
}else if (getScene().getChallenge() == null) {
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
}
} }
// Battle Pass trigger // Battle Pass trigger
getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1)); scene.getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1));
} }
public void recalcStats() { public void recalcStats() {
@ -197,18 +151,7 @@ public class EntityMonster extends GameEntity {
this.getFightProperties().clear(); this.getFightProperties().clear();
// Base stats // Base stats
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp()); MonsterData.definedFightProperties.forEach(prop -> this.setFightProperty(prop, data.getFightProperty(prop)));
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack());
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense());
this.setFightProperty(FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, data.getPhysicalSubHurt());
this.setFightProperty(FightProperty.FIGHT_PROP_FIRE_SUB_HURT, .1f);
this.setFightProperty(FightProperty.FIGHT_PROP_ELEC_SUB_HURT, data.getElecSubHurt());
this.setFightProperty(FightProperty.FIGHT_PROP_WATER_SUB_HURT, data.getWaterSubHurt());
this.setFightProperty(FightProperty.FIGHT_PROP_GRASS_SUB_HURT, data.getGrassSubHurt());
this.setFightProperty(FightProperty.FIGHT_PROP_WIND_SUB_HURT, data.getWindSubHurt());
this.setFightProperty(FightProperty.FIGHT_PROP_ROCK_SUB_HURT, .1f);
this.setFightProperty(FightProperty.FIGHT_PROP_ICE_SUB_HURT, data.getIceSubHurt());
// Level curve // Level curve
MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel()); MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel());
@ -220,18 +163,8 @@ public class EntityMonster extends GameEntity {
} }
// Set % stats // Set % stats
this.setFightProperty( FightProperty.forEachCompoundProperty(c -> this.setFightProperty(c.getResult(),
FightProperty.FIGHT_PROP_MAX_HP, this.getFightProperty(c.getFlat()) + (this.getFightProperty(c.getBase()) * (1f + this.getFightProperty(c.getPercent())))));
(getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP)
);
this.setFightProperty(
FightProperty.FIGHT_PROP_CUR_ATTACK,
(getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK)
);
this.setFightProperty(
FightProperty.FIGHT_PROP_CUR_DEFENSE,
(getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE)
);
// Set current hp // Set current hp
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
@ -239,14 +172,14 @@ public class EntityMonster extends GameEntity {
@Override @Override
public SceneEntityInfo toProto() { public SceneEntityInfo toProto() {
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() var authority = EntityAuthorityInfo.newBuilder()
.setAbilityInfo(AbilitySyncStateInfo.newBuilder()) .setAbilityInfo(AbilitySyncStateInfo.newBuilder())
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto())) .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto()))
.setBornPos(this.getBornPos().toProto()) .setBornPos(this.getBornPos().toProto())
.build(); .build();
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() var entityInfo = SceneEntityInfo.newBuilder()
.setEntityId(getId()) .setEntityId(getId())
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER) .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
.setMotionInfo(this.getMotionInfo()) .setMotionInfo(this.getMotionInfo())
@ -257,13 +190,12 @@ public class EntityMonster extends GameEntity {
this.addAllFightPropsToEntityInfo(entityInfo); this.addAllFightPropsToEntityInfo(entityInfo);
PropPair pair = PropPair.newBuilder() entityInfo.addPropList(PropPair.newBuilder()
.setType(PlayerProperty.PROP_LEVEL.getId()) .setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel())) .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel()))
.build(); .build());
entityInfo.addPropList(pair);
SceneMonsterInfo.Builder monsterInfo = SceneMonsterInfo.newBuilder() var monsterInfo = SceneMonsterInfo.newBuilder()
.setMonsterId(getMonsterId()) .setMonsterId(getMonsterId())
.setGroupId(this.getGroupId()) .setGroupId(this.getGroupId())
.setConfigId(this.getConfigId()) .setConfigId(this.getConfigId())

View File

@ -5,14 +5,16 @@ import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.*; import emu.grasscutter.net.proto.*;
import emu.grasscutter.scripts.data.SceneNPC; import emu.grasscutter.scripts.data.SceneNPC;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import lombok.Getter;
public class EntityNPC extends GameEntity{ public class EntityNPC extends GameEntity{
@Getter(onMethod = @__(@Override))
private final Position position; private final Position position;
@Getter(onMethod = @__(@Override))
private final Position rotation; private final Position rotation;
private final SceneNPC metaNpc; private final SceneNPC metaNpc;
private final int suiteId; @Getter private final int suiteId;
public EntityNPC(Scene scene, SceneNPC metaNPC, int blockId, int suiteId) { public EntityNPC(Scene scene, SceneNPC metaNPC, int blockId, int suiteId) {
super(scene); super(scene);
@ -27,24 +29,7 @@ public class EntityNPC extends GameEntity{
} }
@Override @Override public Int2FloatMap getFightProperties() {return null;}
public Int2FloatOpenHashMap getFightProperties() {
return null;
}
@Override
public Position getPosition() {
return position;
}
@Override
public Position getRotation() {
return rotation;
}
public int getSuiteId() {
return suiteId;
}
@Override @Override
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() { public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {

View File

@ -5,7 +5,7 @@ import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass;
import emu.grasscutter.scripts.data.SceneRegion; import emu.grasscutter.scripts.data.SceneRegion;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import lombok.Getter; import lombok.Getter;
import java.util.Set; import java.util.Set;
@ -57,20 +57,11 @@ public class EntityRegion extends GameEntity{
} }
public boolean entityLeave() {return this.entityLeave;} public boolean entityLeave() {return this.entityLeave;}
public void resetEntityLeave() {this.entityLeave = false;} public void resetEntityLeave() {this.entityLeave = false;}
@Override @Override public Int2FloatMap getFightProperties() {return null;}
public Int2FloatOpenHashMap getFightProperties() {
return null;
}
@Override @Override public Position getPosition() {return position;}
public Position getPosition() {
return position;
}
@Override @Override public Position getRotation() {return null;}
public Position getRotation() {
return null;
}
@Override @Override
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() { public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {

View File

@ -12,7 +12,6 @@ import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncState
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
@ -36,10 +35,8 @@ import java.util.List;
public class EntityVehicle extends EntityBaseGadget { public class EntityVehicle extends EntityBaseGadget {
@Getter private final Player owner; @Getter private final Player owner;
private final Int2FloatMap fightProp; @Getter(onMethod = @__(@Override))
private final Int2FloatMap fightProperties;
private final Position pos;
private final Position rot;
@Getter private final int pointId; @Getter private final int pointId;
@Getter private final int gadgetId; @Getter private final int gadgetId;
@ -49,12 +46,10 @@ public class EntityVehicle extends EntityBaseGadget {
@Nullable @Getter private ConfigGadget configGadget; @Nullable @Getter private ConfigGadget configGadget;
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) { public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
super(scene); super(scene, pos, rot);
this.owner = player; this.owner = player;
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
this.fightProp = new Int2FloatOpenHashMap(); this.fightProperties = new Int2FloatOpenHashMap();
this.pos = new Position(pos);
this.rot = new Position(rot);
this.gadgetId = gadgetId; this.gadgetId = gadgetId;
this.pointId = pointId; this.pointId = pointId;
this.curStamina = 240; // might be in configGadget.GCALKECLLLP.JBAKBEFIMBN.ANBMPHPOALP this.curStamina = 240; // might be in configGadget.GCALKECLLLP.JBAKBEFIMBN.ANBMPHPOALP
@ -74,19 +69,6 @@ public class EntityVehicle extends EntityBaseGadget {
this.addFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 0); this.addFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 0);
} }
@Override
public Int2FloatMap getFightProperties() {
return fightProp;
}
@Override
public Position getPosition() { return this.pos; }
@Override
public Position getRotation() {
return this.rot;
}
@Override @Override
public SceneEntityInfo toProto() { public SceneEntityInfo toProto() {

View File

@ -33,7 +33,7 @@ public abstract class GameEntity {
@Getter @Setter private int configId; @Getter @Setter private int configId;
@Getter @Setter private int groupId; @Getter @Setter private int groupId;
private MotionState moveState; @Getter @Setter private MotionState motionState;
@Getter @Setter private int lastMoveSceneTimeMs; @Getter @Setter private int lastMoveSceneTimeMs;
@Getter @Setter private int lastMoveReliableSeq; @Getter @Setter private int lastMoveReliableSeq;
@ -45,7 +45,7 @@ public abstract class GameEntity {
public GameEntity(Scene scene) { public GameEntity(Scene scene) {
this.scene = scene; this.scene = scene;
this.moveState = MotionState.MOTION_STATE_NONE; this.motionState = MotionState.MOTION_STATE_NONE;
} }
public int getEntityType() { public int getEntityType() {
@ -84,14 +84,6 @@ public abstract class GameEntity {
public abstract Position getRotation(); public abstract Position getRotation();
public MotionState getMotionState() {
return moveState;
}
public void setMotionState(MotionState moveState) {
this.moveState = moveState;
}
public void setFightProperty(FightProperty prop, float value) { public void setFightProperty(FightProperty prop, float value) {
this.getFightProperties().put(prop.getId(), value); this.getFightProperties().put(prop.getId(), value);
} }

View File

@ -20,12 +20,12 @@ import javax.annotation.Nullable;
public class EntityPlatform extends EntityBaseGadget { public class EntityPlatform extends EntityBaseGadget {
@Getter @Getter
private final Player owner; private final Player owner;
@Getter(onMethod = @__(@Override))
private final int gadgetId; private final int gadgetId;
@Getter @Getter
private final EntityClientGadget gadget; private final EntityClientGadget gadget;
private final Int2FloatMap fightProp; @Getter(onMethod = @__(@Override))
private final Position pos; private final Int2FloatMap fightProperties;
private final Position rot;
@Nullable @Nullable
@Getter @Getter
private ConfigGadget configGadget; private ConfigGadget configGadget;
@ -39,13 +39,11 @@ public class EntityPlatform extends EntityBaseGadget {
private boolean isActive; private boolean isActive;
public EntityPlatform(EntityClientGadget gadget, Scene scene, Player player, int gadgetId, Position pos, Position rot, MovingPlatformTypeOuterClass.MovingPlatformType movingPlatformType) { public EntityPlatform(EntityClientGadget gadget, Scene scene, Player player, int gadgetId, Position pos, Position rot, MovingPlatformTypeOuterClass.MovingPlatformType movingPlatformType) {
super(scene); super(scene, pos, rot);
this.gadget = gadget; this.gadget = gadget;
this.owner = player; this.owner = player;
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
this.fightProp = new Int2FloatOpenHashMap(); this.fightProperties = new Int2FloatOpenHashMap();
this.pos = new Position(pos);
this.rot = new Position(rot);
this.movingPlatformType = movingPlatformType; this.movingPlatformType = movingPlatformType;
this.gadgetId = gadgetId; this.gadgetId = gadgetId;
GadgetData data = GameData.getGadgetDataMap().get(gadgetId); GadgetData data = GameData.getGadgetDataMap().get(gadgetId);
@ -56,26 +54,6 @@ public class EntityPlatform extends EntityBaseGadget {
fillFightProps(configGadget); fillFightProps(configGadget);
} }
@Override
public int getGadgetId() {
return gadgetId;
}
@Override
public Int2FloatMap getFightProperties() {
return fightProp;
}
@Override
public Position getPosition() {
return pos;
}
@Override
public Position getRotation() {
return rot;
}
@Override @Override
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() { public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
var platform = PlatformInfoOuterClass.PlatformInfo.newBuilder() var platform = PlatformInfoOuterClass.PlatformInfo.newBuilder()

View File

@ -2,6 +2,7 @@ package emu.grasscutter.game.gacha;
import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.config.Configuration.*;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo; import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
@ -10,65 +11,123 @@ import emu.grasscutter.utils.Utils;
import lombok.Getter; import lombok.Getter;
public class GachaBanner { public class GachaBanner {
@Getter private int gachaType; @Getter private int gachaType = -1;
@Getter private int scheduleId; @Getter int scheduleId = -1;
@Getter int sortId = -1;
@Getter private String prefabPath; @Getter private String prefabPath;
private String previewPrefabPath; @Getter private String previewPrefabPath;
@Getter private String titlePath; @Getter private String titlePath;
private int costItemId = 0; private int costItemId = 0;
private int costItemAmount = 1; private int costItemAmount = 1;
private int costItemId10 = 0; private int costItemId10 = 0;
private int costItemAmount10 = 10; private int costItemAmount10 = 10;
@Getter private int beginTime; @Getter private int beginTime = 0;
@Getter private int endTime; @Getter private int endTime = 1924992000;
@Getter private int sortId;
@Getter private int gachaTimesLimit = Integer.MAX_VALUE; @Getter private int gachaTimesLimit = Integer.MAX_VALUE;
private int[] rateUpItems4 = {}; @Getter private int[] rateUpItems4 = {};
private int[] rateUpItems5 = {}; @Getter private int[] rateUpItems5 = {};
@Getter private int[] fallbackItems3 = {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304}; // This now handles default values for the fields below
@Getter private int[] fallbackItems4Pool1 = {1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1064};
@Getter private int[] fallbackItems4Pool2 = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405};
@Getter private int[] fallbackItems5Pool1 = {1003, 1016, 1042, 1035, 1041};
@Getter private int[] fallbackItems5Pool2 = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502};
@Getter private boolean removeC6FromPool = false;
@Getter private boolean autoStripRateUpFromFallback = true;
private int[][] weights4 = {{1,510}, {8,510}, {10,10000}};
private int[][] weights5 = {{1,75}, {73,150}, {90,10000}};
private int[][] poolBalanceWeights4 = {{1,255}, {17,255}, {21,10455}};
private int[][] poolBalanceWeights5 = {{1,30}, {147,150}, {181,10230}};
private int eventChance4 = 50; // Chance to win a featured event item
private int eventChance5 = 50; // Chance to win a featured event item
@Getter private BannerType bannerType = BannerType.STANDARD; @Getter private BannerType bannerType = BannerType.STANDARD;
// Constants used by the BannerType enum
// Kinda wanna deprecate these but they're in people's configs static final int[][] DEFAULT_WEIGHTS_4 = {{1,510}, {8,510}, {10,10000}};
private int[] rateUpItems1 = {}; static final int[][] DEFAULT_WEIGHTS_4_WEAPON = {{1, 600}, {7, 600}, {8, 6600}, {10, 12600}};
private int[] rateUpItems2 = {}; static final int[][] DEFAULT_WEIGHTS_5 = {{1,75}, {73,150}, {90,10000}};
private int eventChance = -1; static final int[][] DEFAULT_WEIGHTS_5_CHARACTER = {{1,80}, {73,80}, {90,10000}};
private int costItem = 0; static final int[][] DEFAULT_WEIGHTS_5_WEAPON = {{1,100}, {62,100}, {73,7800}, {80,10000}};
static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_1 = {1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072}; // Default avatars
static final int[] DEFAULT_FALLBACK_ITEMS_4_POOL_2 = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405}; // Default weapons
static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_1 = {1003, 1016, 1042, 1035, 1041, 1069}; // Default avatars
static final int[] DEFAULT_FALLBACK_ITEMS_5_POOL_2 = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502}; // Default weapons
static final int[] EMPTY_POOL = {}; // Used to remove a type of fallback
// These don't change between banner types (apart from Standard having three extra 4star avatars)
@Getter private int[] fallbackItems3 = {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304};
@Getter private int[] fallbackItems4Pool1 = DEFAULT_FALLBACK_ITEMS_4_POOL_1;
@Getter private int[] fallbackItems4Pool2 = DEFAULT_FALLBACK_ITEMS_4_POOL_2;
// Different banner types have different defaults, see above for default values and the enum for which are used where.
@Getter private int[] fallbackItems5Pool1;
@Getter private int[] fallbackItems5Pool2;
private int[][] weights4;
private int[][] weights5;
private int eventChance4 = -1; // Chance to win a featured event item
private int eventChance5 = -1; // Chance to win a featured event item
//
@Getter private boolean removeC6FromPool = false;
@Getter private boolean autoStripRateUpFromFallback = true; // Ensures that featured items won't "double dip" into the losing pool
private int[][] poolBalanceWeights4 = {{1,255}, {17,255}, {21,10455}}; // Used to ensure that players won't go too many rolls without getting something from pool 1 (avatar) or pool 2 (weapon)
private int[][] poolBalanceWeights5 = {{1,30}, {147,150}, {181,10230}};
@Getter private int wishMaxProgress = 2; @Getter private int wishMaxProgress = 2;
public String getPreviewPrefabPath() { // Deprecated fields that were tolerated in early May 2022 but have apparently still being circulating in new custom configs
if (this.previewPrefabPath != null && !this.previewPrefabPath.isEmpty()) // For now, throw up big scary errors on load telling people that they will be banned outright in a future version
return this.previewPrefabPath; @Deprecated private int[] rateUpItems1 = {};
return "UI_Tab_" + this.prefabPath; @Deprecated private int[] rateUpItems2 = {};
@Deprecated private int eventChance = -1;
@Deprecated private int costItem = 0;
@Deprecated private int softPity = -1;
@Deprecated private int hardPity = -1;
@Deprecated private int minItemType = -1;
@Deprecated private int maxItemType = -1;
@Getter private boolean deprecated = false;
@Getter private boolean disabled = false;
private void warnDeprecated(String name, String replacement) {
Grasscutter.getLogger().error("Deprecated field found in Banners config: "+name+" was replaced back in early May 2022, use "+replacement+" instead. You MUST remove this field from your config.");
this.deprecated = true;
}
public void onLoad() {
// Handle deprecated configs
if (eventChance != -1)
warnDeprecated("eventChance", "eventChance4 & eventChance5");
if (costItem != 0)
warnDeprecated("costItem", "costItemId");
if (softPity != -1)
warnDeprecated("softPity", "weights5");
if (hardPity != -1)
warnDeprecated("hardPity", "weights5");
if (minItemType != -1)
warnDeprecated("minItemType", "fallbackItems[4,5]Pool[1,2]");
if (maxItemType != -1)
warnDeprecated("maxItemType", "fallbackItems[4,5]Pool[1,2]");
if (rateUpItems1.length > 0)
warnDeprecated("rateUpItems1", "rateUpItems5");
if (rateUpItems2.length > 0)
warnDeprecated("rateUpItems2", "rateUpItems4");
// Handle default values
if (this.previewPrefabPath != null && this.previewPrefabPath.equals("UI_Tab_" + this.prefabPath))
Grasscutter.getLogger().error("Redundant field found in Banners config: previewPrefabPath does not need to be specified if it is identical to prefabPath prefixed with \"UI_Tab_\".");
if (this.previewPrefabPath == null || this.previewPrefabPath.isEmpty())
this.previewPrefabPath = "UI_Tab_" + this.prefabPath;
if (this.gachaType < 0)
this.gachaType = this.bannerType.gachaType;
if (this.costItemId == 0)
this.costItemId = this.bannerType.costItemId;
if (this.costItemId10 == 0)
this.costItemId10 = this.costItemId;
if (this.weights4 == null)
this.weights4 = this.bannerType.weights4;
if (this.weights5 == null)
this.weights5 = this.bannerType.weights5;
if (this.eventChance4 < 0)
this.eventChance4 = this.bannerType.eventChance4;
if (this.eventChance5 < 0)
this.eventChance5 = this.bannerType.eventChance5;
if (this.fallbackItems5Pool1 == null)
this.fallbackItems5Pool1 = this.bannerType.fallbackItems5Pool1;
if (this.fallbackItems5Pool2 == null)
this.fallbackItems5Pool2 = this.bannerType.fallbackItems5Pool2;
} }
public ItemParamData getCost(int numRolls) { public ItemParamData getCost(int numRolls) {
return switch (numRolls) { return switch (numRolls) {
case 10 -> new ItemParamData((costItemId10 > 0) ? costItemId10 : getCostItem(), costItemAmount10); case 10 -> new ItemParamData(costItemId10, costItemAmount10);
default -> new ItemParamData(getCostItem(), costItemAmount * numRolls); default -> new ItemParamData(costItemId, costItemAmount * numRolls);
}; };
} }
@Deprecated
public int getCostItem() { public int getCostItem() {
return (costItem > 0) ? costItem : costItemId; return costItemId;
}
public int[] getRateUpItems4() {
return (rateUpItems2.length > 0) ? rateUpItems2 : rateUpItems4;
}
public int[] getRateUpItems5() {
return (rateUpItems1.length > 0) ? rateUpItems1 : rateUpItems5;
} }
public boolean hasEpitomized() { public boolean hasEpitomized() {
@ -92,7 +151,7 @@ public class GachaBanner {
public int getEventChance(int rarity) { public int getEventChance(int rarity) {
return switch (rarity) { return switch (rarity) {
case 4 -> eventChance4; case 4 -> eventChance4;
default -> (eventChance > -1) ? eventChance : eventChance5; default -> eventChance5;
}; };
} }
@ -110,8 +169,6 @@ public class GachaBanner {
+ "/gacha/details?s=" + sessionKey + "&scheduleId=" + scheduleId; + "/gacha/details?s=" + sessionKey + "&scheduleId=" + scheduleId;
// Grasscutter.getLogger().info("record = " + record); // Grasscutter.getLogger().info("record = " + record);
ItemParamData costItem1 = this.getCost(1);
ItemParamData costItem10 = this.getCost(10);
PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this); PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this);
int leftGachaTimes = switch (gachaTimesLimit) { int leftGachaTimes = switch (gachaTimesLimit) {
case Integer.MAX_VALUE -> Integer.MAX_VALUE; case Integer.MAX_VALUE -> Integer.MAX_VALUE;
@ -122,10 +179,10 @@ public class GachaBanner {
.setScheduleId(this.getScheduleId()) .setScheduleId(this.getScheduleId())
.setBeginTime(this.getBeginTime()) .setBeginTime(this.getBeginTime())
.setEndTime(this.getEndTime()) .setEndTime(this.getEndTime())
.setCostItemId(costItem1.getId()) .setCostItemId(this.costItemId)
.setCostItemNum(costItem1.getCount()) .setCostItemNum(this.costItemAmount)
.setTenCostItemId(costItem10.getId()) .setTenCostItemId(this.costItemId10)
.setTenCostItemNum(costItem10.getCount()) .setTenCostItemNum(this.costItemAmount10)
.setGachaPrefabPath(this.getPrefabPath()) .setGachaPrefabPath(this.getPrefabPath())
.setGachaPreviewPrefabPath(this.getPreviewPrefabPath()) .setGachaPreviewPrefabPath(this.getPreviewPrefabPath())
.setGachaProbUrl(details) .setGachaProbUrl(details)
@ -174,6 +231,31 @@ public class GachaBanner {
} }
public enum BannerType { public enum BannerType {
STANDARD, EVENT, WEAPON; STANDARD(200, 224, DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_5, 50, 50, DEFAULT_FALLBACK_ITEMS_5_POOL_1, DEFAULT_FALLBACK_ITEMS_5_POOL_2),
BEGINNER(100, 224, DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_5, 50, 50, DEFAULT_FALLBACK_ITEMS_5_POOL_1, DEFAULT_FALLBACK_ITEMS_5_POOL_2),
EVENT(301, 223, DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_5_CHARACTER, 50, 50, DEFAULT_FALLBACK_ITEMS_5_POOL_1, DEFAULT_FALLBACK_ITEMS_5_POOL_2), // Legacy value for CHARACTER
CHARACTER(301, 223, DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_5_CHARACTER, 50, 50, DEFAULT_FALLBACK_ITEMS_5_POOL_1, EMPTY_POOL),
CHARACTER2(400, 223, DEFAULT_WEIGHTS_4, DEFAULT_WEIGHTS_5_CHARACTER, 50, 50, DEFAULT_FALLBACK_ITEMS_5_POOL_1, EMPTY_POOL),
WEAPON(302, 223, DEFAULT_WEIGHTS_4_WEAPON, DEFAULT_WEIGHTS_5_WEAPON, 75, 75, EMPTY_POOL, DEFAULT_FALLBACK_ITEMS_5_POOL_2);
public final int gachaType;
public final int costItemId;
public final int[][] weights4;
public final int[][] weights5;
public final int eventChance4;
public final int eventChance5;
public final int[] fallbackItems5Pool1;
public final int[] fallbackItems5Pool2;
BannerType(int gachaType, int costItemId, int[][] weights4, int[][] weights5, int eventChance4, int eventChance5, int[] fallbackItems5Pool1, int[] fallbackItems5Pool2) {
this.gachaType = gachaType;
this.costItemId = costItemId;
this.weights4 = weights4;
this.weights5 = weights5;
this.eventChance4 = eventChance4;
this.eventChance5 = eventChance5;
this.fallbackItems5Pool1 = fallbackItems5Pool1;
this.fallbackItems5Pool2 = fallbackItems5Pool2;
}
} }
} }

View File

@ -45,8 +45,6 @@ public class GachaSystem extends BaseGameSystem {
private static final int starglitterId = 221; private static final int starglitterId = 221;
private static final int stardustId = 222; private static final int stardustId = 222;
private int[] fallbackItems4Pool2Default = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405};
private int[] fallbackItems5Pool2Default = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502};
public GachaSystem(GameServer server) { public GachaSystem(GameServer server) {
super(server); super(server);
@ -69,11 +67,24 @@ public class GachaSystem extends BaseGameSystem {
public synchronized void load() { public synchronized void load() {
getGachaBanners().clear(); getGachaBanners().clear();
int autoScheduleId = 1000;
int autoSortId = 9000;
try { try {
List<GachaBanner> banners = DataLoader.loadList("Banners.json", GachaBanner.class); List<GachaBanner> banners = DataLoader.loadTableToList("Banners", GachaBanner.class);
if (banners.size() > 0) { if (banners.size() > 0) {
for (GachaBanner banner : banners) { for (GachaBanner banner : banners) {
getGachaBanners().put(banner.getScheduleId(), banner); banner.onLoad();
if (banner.isDeprecated()) {
Grasscutter.getLogger().error("A Banner has not been loaded because it contains one or more deprecated fields. Remove the fields mentioned above and reload.");
} else if (banner.isDisabled()) {
Grasscutter.getLogger().debug("A Banner has not been loaded because it is disabled.");
} else {
if (banner.scheduleId < 0)
banner.scheduleId = autoScheduleId++;
if (banner.sortId < 0)
banner.sortId = autoSortId--;
getGachaBanners().put(banner.scheduleId, banner);
}
} }
Grasscutter.getLogger().debug("Banners successfully loaded."); Grasscutter.getLogger().debug("Banners successfully loaded.");
} else { } else {
@ -155,7 +166,7 @@ public class GachaSystem extends BaseGameSystem {
private synchronized int doFallbackRarePull(int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) { private synchronized int doFallbackRarePull(int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) {
if (fallback1.length < 1) { if (fallback1.length < 1) {
if (fallback2.length < 1) { if (fallback2.length < 1) {
return getRandom((rarity==5)? fallbackItems5Pool2Default : fallbackItems4Pool2Default); return getRandom((rarity==5)? GachaBanner.DEFAULT_FALLBACK_ITEMS_5_POOL_2 : GachaBanner.DEFAULT_FALLBACK_ITEMS_4_POOL_2);
} else { } else {
return getRandom(fallback2); return getRandom(fallback2);
} }

View File

@ -4,37 +4,43 @@ import dev.morphia.annotations.Entity;
@Entity @Entity
public class PlayerGachaInfo { public class PlayerGachaInfo {
private PlayerGachaBannerInfo standardBanner; private PlayerGachaBannerInfo standardBanner;
private PlayerGachaBannerInfo eventCharacterBanner; private PlayerGachaBannerInfo beginnerBanner;
private PlayerGachaBannerInfo eventWeaponBanner; private PlayerGachaBannerInfo eventCharacterBanner;
private PlayerGachaBannerInfo eventWeaponBanner;
public PlayerGachaInfo() { public PlayerGachaInfo() {
this.standardBanner = new PlayerGachaBannerInfo(); this.standardBanner = new PlayerGachaBannerInfo();
this.eventCharacterBanner = new PlayerGachaBannerInfo(); this.eventCharacterBanner = new PlayerGachaBannerInfo();
this.eventWeaponBanner = new PlayerGachaBannerInfo(); this.eventWeaponBanner = new PlayerGachaBannerInfo();
} }
public PlayerGachaBannerInfo getStandardBanner() { public PlayerGachaBannerInfo getStandardBanner() {
return standardBanner; if (this.standardBanner == null) this.standardBanner = new PlayerGachaBannerInfo();
} return this.standardBanner;
}
public PlayerGachaBannerInfo getEventCharacterBanner() { public PlayerGachaBannerInfo getBeginnerBanner() {
return eventCharacterBanner; if (this.beginnerBanner == null) this.beginnerBanner = new PlayerGachaBannerInfo();
} return this.beginnerBanner;
}
public PlayerGachaBannerInfo getEventWeaponBanner() { public PlayerGachaBannerInfo getEventCharacterBanner() {
return eventWeaponBanner; if (this.eventCharacterBanner == null) this.eventCharacterBanner = new PlayerGachaBannerInfo();
} return this.eventCharacterBanner;
}
public PlayerGachaBannerInfo getBannerInfo(GachaBanner banner) { public PlayerGachaBannerInfo getEventWeaponBanner() {
switch (banner.getBannerType()) { if (this.eventWeaponBanner == null) this.eventWeaponBanner = new PlayerGachaBannerInfo();
case EVENT: return this.eventWeaponBanner;
return this.eventCharacterBanner; }
case WEAPON:
return this.eventWeaponBanner; public PlayerGachaBannerInfo getBannerInfo(GachaBanner banner) {
case STANDARD: return switch (banner.getBannerType()) {
default: case STANDARD -> this.getStandardBanner();
return this.standardBanner; case BEGINNER -> this.getBeginnerBanner();
} case EVENT, CHARACTER, CHARACTER2 -> this.getEventCharacterBanner();
} case WEAPON -> this.getEventWeaponBanner();
};
}
} }

View File

@ -11,6 +11,7 @@ import emu.grasscutter.data.excels.HomeWorldLevelData;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -20,6 +21,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Entity(value = "homes", useDiscriminator = false) @Entity(value = "homes", useDiscriminator = false)
@Data @Data
@ -57,6 +59,7 @@ public class GameHome {
.ownerUid(uid) .ownerUid(uid)
.level(1) .level(1)
.sceneMap(new ConcurrentHashMap<>()) .sceneMap(new ConcurrentHashMap<>())
.unlockedHomeBgmList(new HashSet<>())
.build(); .build();
} }
@ -93,7 +96,7 @@ public class GameHome {
} }
public boolean addUnlockedHomeBgm(int homeBgmId) { public boolean addUnlockedHomeBgm(int homeBgmId) {
if (getUnlockedHomeBgmList().add(homeBgmId)) return false; if (!getUnlockedHomeBgmList().add(homeBgmId)) return false;
var player = this.getPlayer(); var player = this.getPlayer();
player.sendPacket(new PacketUnlockHomeBgmNotify(homeBgmId)); player.sendPacket(new PacketUnlockHomeBgmNotify(homeBgmId));
@ -102,20 +105,22 @@ public class GameHome {
return true; return true;
} }
public Set<Integer> getUnlockedHomeBgmListInfo() { public Set<Integer> getUnlockedHomeBgmList() {
if (this.unlockedHomeBgmList == null) { if (this.unlockedHomeBgmList == null) {
this.unlockedHomeBgmList = new HashSet<>(); this.unlockedHomeBgmList = new HashSet<>();
addAllDefaultUnlockedBgmIds(this.unlockedHomeBgmList); }
if (this.unlockedHomeBgmList.addAll(getDefaultUnlockedHomeBgmIds())) {
save(); save();
} }
return this.unlockedHomeBgmList; return this.unlockedHomeBgmList;
} }
private void addAllDefaultUnlockedBgmIds(Set<Integer> list) { private Set<Integer> getDefaultUnlockedHomeBgmIds() {
GameData.getHomeWorldBgmDataMap().forEach((id, data) -> { return GameData.getHomeWorldBgmDataMap().int2ObjectEntrySet().stream()
if (data.isDefaultUnlock()) .filter(e -> e.getValue().isDefaultUnlock())
list.add(id); .map(Int2ObjectMap.Entry::getIntKey)
}); .collect(Collectors.toUnmodifiableSet());
} }
} }

View File

@ -140,7 +140,14 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
List<GameItem> changedItems = new ArrayList<>(); List<GameItem> changedItems = new ArrayList<>();
for (var item : items) { for (var item : items) {
if (item.getItemId() == 0) continue; if (item.getItemId() == 0) continue;
GameItem result = putItem(item); GameItem result = null;
try {
// putItem might throws exception
// ignore that exception and continue
result = putItem(item);
} catch (Exception e) {
e.printStackTrace();
}
if (result != null) { if (result != null) {
getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount()); getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount());
changedItems.add(result); changedItems.add(result);
@ -174,6 +181,7 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
if (data.isUseOnGain()) { if (data.isUseOnGain()) {
var params = new UseItemParams(this.player, data.getUseTarget()); var params = new UseItemParams(this.player, data.getUseTarget());
params.usedItemId = data.getId();
this.player.getServer().getInventorySystem().useItemDirect(data, params); this.player.getServer().getInventorySystem().useItemDirect(data, params);
return null; return null;
} }

View File

@ -36,6 +36,11 @@ public class DeforestationManager extends BasePlayerManager {
ColliderTypeToWoodItemID.put(10,101310); ColliderTypeToWoodItemID.put(10,101310);
ColliderTypeToWoodItemID.put(11,101311); ColliderTypeToWoodItemID.put(11,101311);
ColliderTypeToWoodItemID.put(12,101312); ColliderTypeToWoodItemID.put(12,101312);
ColliderTypeToWoodItemID.put(13,101313);
ColliderTypeToWoodItemID.put(14,101314);
ColliderTypeToWoodItemID.put(15,101315);
ColliderTypeToWoodItemID.put(16,101316);
ColliderTypeToWoodItemID.put(17,101317);
} }
public DeforestationManager(Player player) { public DeforestationManager(Player player) {

View File

@ -314,7 +314,7 @@ public class Player {
public Account getAccount() { public Account getAccount() {
if (this.account == null) if (this.account == null)
this.account = DatabaseHelper.getAccountById(Integer.toString(this.id)); this.account = DatabaseHelper.getAccountById(this.accountId);
return this.account; return this.account;
} }

View File

@ -1,6 +1,6 @@
package emu.grasscutter.game.player; package emu.grasscutter.game.player;
import java.util.LinkedList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -15,11 +15,8 @@ import emu.grasscutter.server.packet.send.PacketServerBuffChangeNotify;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.val;
@Getter(AccessLevel.PRIVATE)
public class PlayerBuffManager extends BasePlayerManager { public class PlayerBuffManager extends BasePlayerManager {
private int nextBuffUid; private int nextBuffUid;
@ -29,7 +26,7 @@ public class PlayerBuffManager extends BasePlayerManager {
public PlayerBuffManager(Player player) { public PlayerBuffManager(Player player) {
super(player); super(player);
this.buffs = new Int2ObjectOpenHashMap<>(); this.buffs = new Int2ObjectOpenHashMap<>();
this.pendingBuffs = new LinkedList<>(); this.pendingBuffs = new ArrayList<>();
} }
/** /**
@ -46,7 +43,7 @@ public class PlayerBuffManager extends BasePlayerManager {
* @return True if a buff with this group id exists * @return True if a buff with this group id exists
*/ */
public synchronized boolean hasBuff(int groupId) { public synchronized boolean hasBuff(int groupId) {
return this.getBuffs().containsKey(groupId); return this.buffs.containsKey(groupId);
} }
/** /**
@ -55,11 +52,11 @@ public class PlayerBuffManager extends BasePlayerManager {
public synchronized void clearBuffs() { public synchronized void clearBuffs() {
// Remove from player // Remove from player
getPlayer().sendPacket( getPlayer().sendPacket(
new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, getBuffs().values()) new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, this.buffs.values())
); );
// Clear // Clear
getBuffs().clear(); this.buffs.clear();
} }
/** /**
@ -133,13 +130,11 @@ public class PlayerBuffManager extends BasePlayerManager {
} }
// Clear previous buff if it exists // Clear previous buff if it exists
if (this.hasBuff(buffData.getGroupId())) { this.removeBuff(buffData.getGroupId());
this.removeBuff(buffData.getGroupId());
}
// Create and store buff // Create and store buff
PlayerBuff buff = new PlayerBuff(getNextBuffUid(), buffData, duration); PlayerBuff buff = new PlayerBuff(getNextBuffUid(), buffData, duration);
getBuffs().put(buff.getGroupId(), buff); this.buffs.put(buff.getGroupId(), buff);
// Packet // Packet
getPlayer().sendPacket(new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_ADD_SERVER_BUFF, buff)); getPlayer().sendPacket(new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_ADD_SERVER_BUFF, buff));
@ -153,7 +148,7 @@ public class PlayerBuffManager extends BasePlayerManager {
* @return True if a buff was remove * @return True if a buff was remove
*/ */
public synchronized boolean removeBuff(int buffGroupId) { public synchronized boolean removeBuff(int buffGroupId) {
PlayerBuff buff = this.getBuffs().get(buffGroupId); PlayerBuff buff = this.buffs.remove(buffGroupId);
if (buff != null) { if (buff != null) {
getPlayer().sendPacket( getPlayer().sendPacket(
@ -167,28 +162,24 @@ public class PlayerBuffManager extends BasePlayerManager {
public synchronized void onTick() { public synchronized void onTick() {
// Skip if no buffs // Skip if no buffs
if (getBuffs().size() == 0) return; if (this.buffs.isEmpty()) return;
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
// Add to pending buffs to remove if buff has expired // Add to pending buffs to remove if buff has expired
for (PlayerBuff buff : getBuffs().values()) { this.buffs.values().removeIf(buff -> {
if (currentTime > buff.getEndTime()) { if (currentTime <= buff.getEndTime())
this.getPendingBuffs().add(buff); return false;
} this.pendingBuffs.add(buff);
} return true;
});
if (this.getPendingBuffs().size() > 0) { if (this.pendingBuffs.size() > 0) {
// Send packet // Send packet
getPlayer().sendPacket( getPlayer().sendPacket(
new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, this.pendingBuffs) new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, this.pendingBuffs)
); );
this.pendingBuffs.clear();
// Remove buff from player buff map
for (PlayerBuff buff : this.getPendingBuffs()) {
getBuffs().remove(buff.getGroupId());
}
this.getPendingBuffs().clear();
} }
} }

View File

@ -4,6 +4,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import static java.util.Map.entry; import static java.util.Map.entry;
@ -12,133 +13,134 @@ import java.util.stream.Stream;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
public enum FightProperty { public enum FightProperty {
FIGHT_PROP_NONE(0), FIGHT_PROP_NONE(0),
FIGHT_PROP_BASE_HP(1), FIGHT_PROP_BASE_HP(1),
FIGHT_PROP_HP(2), FIGHT_PROP_HP(2),
FIGHT_PROP_HP_PERCENT(3), FIGHT_PROP_HP_PERCENT(3),
FIGHT_PROP_BASE_ATTACK(4), FIGHT_PROP_BASE_ATTACK(4),
FIGHT_PROP_ATTACK(5), FIGHT_PROP_ATTACK(5),
FIGHT_PROP_ATTACK_PERCENT(6), FIGHT_PROP_ATTACK_PERCENT(6),
FIGHT_PROP_BASE_DEFENSE(7), FIGHT_PROP_BASE_DEFENSE(7),
FIGHT_PROP_DEFENSE(8), FIGHT_PROP_DEFENSE(8),
FIGHT_PROP_DEFENSE_PERCENT(9), FIGHT_PROP_DEFENSE_PERCENT(9),
FIGHT_PROP_BASE_SPEED(10), FIGHT_PROP_BASE_SPEED(10),
FIGHT_PROP_SPEED_PERCENT(11), FIGHT_PROP_SPEED_PERCENT(11),
FIGHT_PROP_HP_MP_PERCENT(12), FIGHT_PROP_HP_MP_PERCENT(12),
FIGHT_PROP_ATTACK_MP_PERCENT(13), FIGHT_PROP_ATTACK_MP_PERCENT(13),
FIGHT_PROP_CRITICAL(20), FIGHT_PROP_CRITICAL(20),
FIGHT_PROP_ANTI_CRITICAL(21), FIGHT_PROP_ANTI_CRITICAL(21),
FIGHT_PROP_CRITICAL_HURT(22), FIGHT_PROP_CRITICAL_HURT(22),
FIGHT_PROP_CHARGE_EFFICIENCY(23), FIGHT_PROP_CHARGE_EFFICIENCY(23),
FIGHT_PROP_ADD_HURT(24), FIGHT_PROP_ADD_HURT(24),
FIGHT_PROP_SUB_HURT(25), FIGHT_PROP_SUB_HURT(25),
FIGHT_PROP_HEAL_ADD(26), FIGHT_PROP_HEAL_ADD(26),
FIGHT_PROP_HEALED_ADD(27), FIGHT_PROP_HEALED_ADD(27),
FIGHT_PROP_ELEMENT_MASTERY(28), FIGHT_PROP_ELEMENT_MASTERY(28),
FIGHT_PROP_PHYSICAL_SUB_HURT(29), FIGHT_PROP_PHYSICAL_SUB_HURT(29),
FIGHT_PROP_PHYSICAL_ADD_HURT(30), FIGHT_PROP_PHYSICAL_ADD_HURT(30),
FIGHT_PROP_DEFENCE_IGNORE_RATIO(31), FIGHT_PROP_DEFENCE_IGNORE_RATIO(31),
FIGHT_PROP_DEFENCE_IGNORE_DELTA(32), FIGHT_PROP_DEFENCE_IGNORE_DELTA(32),
FIGHT_PROP_FIRE_ADD_HURT(40), FIGHT_PROP_FIRE_ADD_HURT(40),
FIGHT_PROP_ELEC_ADD_HURT(41), FIGHT_PROP_ELEC_ADD_HURT(41),
FIGHT_PROP_WATER_ADD_HURT(42), FIGHT_PROP_WATER_ADD_HURT(42),
FIGHT_PROP_GRASS_ADD_HURT(43), FIGHT_PROP_GRASS_ADD_HURT(43),
FIGHT_PROP_WIND_ADD_HURT(44), FIGHT_PROP_WIND_ADD_HURT(44),
FIGHT_PROP_ROCK_ADD_HURT(45), FIGHT_PROP_ROCK_ADD_HURT(45),
FIGHT_PROP_ICE_ADD_HURT(46), FIGHT_PROP_ICE_ADD_HURT(46),
FIGHT_PROP_HIT_HEAD_ADD_HURT(47), FIGHT_PROP_HIT_HEAD_ADD_HURT(47),
FIGHT_PROP_FIRE_SUB_HURT(50), FIGHT_PROP_FIRE_SUB_HURT(50),
FIGHT_PROP_ELEC_SUB_HURT(51), FIGHT_PROP_ELEC_SUB_HURT(51),
FIGHT_PROP_WATER_SUB_HURT(52), FIGHT_PROP_WATER_SUB_HURT(52),
FIGHT_PROP_GRASS_SUB_HURT(53), FIGHT_PROP_GRASS_SUB_HURT(53),
FIGHT_PROP_WIND_SUB_HURT(54), FIGHT_PROP_WIND_SUB_HURT(54),
FIGHT_PROP_ROCK_SUB_HURT(55), FIGHT_PROP_ROCK_SUB_HURT(55),
FIGHT_PROP_ICE_SUB_HURT(56), FIGHT_PROP_ICE_SUB_HURT(56),
FIGHT_PROP_EFFECT_HIT(60), FIGHT_PROP_EFFECT_HIT(60),
FIGHT_PROP_EFFECT_RESIST(61), FIGHT_PROP_EFFECT_RESIST(61),
FIGHT_PROP_FREEZE_RESIST(62), FIGHT_PROP_FREEZE_RESIST(62),
FIGHT_PROP_TORPOR_RESIST(63), FIGHT_PROP_TORPOR_RESIST(63),
FIGHT_PROP_DIZZY_RESIST(64), FIGHT_PROP_DIZZY_RESIST(64),
FIGHT_PROP_FREEZE_SHORTEN(65), FIGHT_PROP_FREEZE_SHORTEN(65),
FIGHT_PROP_TORPOR_SHORTEN(66), FIGHT_PROP_TORPOR_SHORTEN(66),
FIGHT_PROP_DIZZY_SHORTEN(67), FIGHT_PROP_DIZZY_SHORTEN(67),
FIGHT_PROP_MAX_FIRE_ENERGY(70), FIGHT_PROP_MAX_FIRE_ENERGY(70),
FIGHT_PROP_MAX_ELEC_ENERGY(71), FIGHT_PROP_MAX_ELEC_ENERGY(71),
FIGHT_PROP_MAX_WATER_ENERGY(72), FIGHT_PROP_MAX_WATER_ENERGY(72),
FIGHT_PROP_MAX_GRASS_ENERGY(73), FIGHT_PROP_MAX_GRASS_ENERGY(73),
FIGHT_PROP_MAX_WIND_ENERGY(74), FIGHT_PROP_MAX_WIND_ENERGY(74),
FIGHT_PROP_MAX_ICE_ENERGY(75), FIGHT_PROP_MAX_ICE_ENERGY(75),
FIGHT_PROP_MAX_ROCK_ENERGY(76), FIGHT_PROP_MAX_ROCK_ENERGY(76),
FIGHT_PROP_SKILL_CD_MINUS_RATIO(80), FIGHT_PROP_SKILL_CD_MINUS_RATIO(80),
FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81), FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81),
FIGHT_PROP_CUR_FIRE_ENERGY(1000), FIGHT_PROP_CUR_FIRE_ENERGY(1000),
FIGHT_PROP_CUR_ELEC_ENERGY(1001), FIGHT_PROP_CUR_ELEC_ENERGY(1001),
FIGHT_PROP_CUR_WATER_ENERGY(1002), FIGHT_PROP_CUR_WATER_ENERGY(1002),
FIGHT_PROP_CUR_GRASS_ENERGY(1003), FIGHT_PROP_CUR_GRASS_ENERGY(1003),
FIGHT_PROP_CUR_WIND_ENERGY(1004), FIGHT_PROP_CUR_WIND_ENERGY(1004),
FIGHT_PROP_CUR_ICE_ENERGY(1005), FIGHT_PROP_CUR_ICE_ENERGY(1005),
FIGHT_PROP_CUR_ROCK_ENERGY(1006), FIGHT_PROP_CUR_ROCK_ENERGY(1006),
FIGHT_PROP_CUR_HP(1010), FIGHT_PROP_CUR_HP(1010),
FIGHT_PROP_MAX_HP(2000), FIGHT_PROP_MAX_HP(2000),
FIGHT_PROP_CUR_ATTACK(2001), FIGHT_PROP_CUR_ATTACK(2001),
FIGHT_PROP_CUR_DEFENSE(2002), FIGHT_PROP_CUR_DEFENSE(2002),
FIGHT_PROP_CUR_SPEED(2003), FIGHT_PROP_CUR_SPEED(2003),
FIGHT_PROP_NONEXTRA_ATTACK(3000), FIGHT_PROP_NONEXTRA_ATTACK(3000),
FIGHT_PROP_NONEXTRA_DEFENSE(3001), FIGHT_PROP_NONEXTRA_DEFENSE(3001),
FIGHT_PROP_NONEXTRA_CRITICAL(3002), FIGHT_PROP_NONEXTRA_CRITICAL(3002),
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003), FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003),
FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004), FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004),
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005), FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005),
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006), FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006),
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007), FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007),
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008), FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008),
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009), FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009),
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010), FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010),
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011), FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011),
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012), FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012),
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013), FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013),
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014), FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014),
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015), FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015),
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016), FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016),
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017), FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017),
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018), FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018),
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019), FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019),
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020), FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020),
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021), FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021),
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022), FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022),
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023), FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023),
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024); FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024);
private final int id; private final int id;
private static final Int2ObjectMap<FightProperty> map = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FightProperty> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, FightProperty> stringMap = new HashMap<>(); private static final Map<String, FightProperty> stringMap = new HashMap<>();
public static final int[] fightProps = new int[] {1, 4, 7, 20, 21, 22, 23, 26, 27, 28, 29, 30, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 55, 56, 2000, 2001, 2002, 2003, 1010}; public static final int[] fightProps = new int[] {1, 4, 7, 20, 21, 22, 23, 26, 27, 28, 29, 30, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 55, 56, 2000, 2001, 2002, 2003, 1010};
static { static {
Stream.of(values()).forEach(e -> { Stream.of(values()).forEach(e -> {
map.put(e.getId(), e); map.put(e.getId(), e);
stringMap.put(e.name(), e); stringMap.put(e.name(), e);
}); });
} }
private FightProperty(int id) { private FightProperty(int id) {
this.id = id; this.id = id;
} }
public int getId() { public int getId() {
return id; return id;
} }
public static FightProperty getPropById(int value) { public static FightProperty getPropById(int value) {
return map.getOrDefault(value, FIGHT_PROP_NONE); return map.getOrDefault(value, FIGHT_PROP_NONE);
} }
public static FightProperty getPropByName(String name) { public static FightProperty getPropByName(String name) {
return stringMap.getOrDefault(name, FIGHT_PROP_NONE); return stringMap.getOrDefault(name, FIGHT_PROP_NONE);
} }
public static FightProperty getPropByShortName(String name) { public static FightProperty getPropByShortName(String name) {
return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE); return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE);
@ -151,28 +153,28 @@ public enum FightProperty {
// This was originally for relic properties so some names might not be applicable for e.g. setstats // This was originally for relic properties so some names might not be applicable for e.g. setstats
private static final Map<String, FightProperty> shortNameMap = Map.ofEntries( private static final Map<String, FightProperty> shortNameMap = Map.ofEntries(
// Normal relic stats // Normal relic stats
entry("hp", FIGHT_PROP_HP), entry("hp", FIGHT_PROP_HP),
entry("atk", FIGHT_PROP_ATTACK), entry("atk", FIGHT_PROP_ATTACK),
entry("def", FIGHT_PROP_DEFENSE), entry("def", FIGHT_PROP_DEFENSE),
entry("hp%", FIGHT_PROP_HP_PERCENT), entry("hp%", FIGHT_PROP_HP_PERCENT),
entry("atk%", FIGHT_PROP_ATTACK_PERCENT), entry("atk%", FIGHT_PROP_ATTACK_PERCENT),
entry("def%", FIGHT_PROP_DEFENSE_PERCENT), entry("def%", FIGHT_PROP_DEFENSE_PERCENT),
entry("em", FIGHT_PROP_ELEMENT_MASTERY), entry("em", FIGHT_PROP_ELEMENT_MASTERY),
entry("er", FIGHT_PROP_CHARGE_EFFICIENCY), entry("er", FIGHT_PROP_CHARGE_EFFICIENCY),
entry("hb", FIGHT_PROP_HEAL_ADD), entry("hb", FIGHT_PROP_HEAL_ADD),
entry("heal", FIGHT_PROP_HEAL_ADD), entry("heal", FIGHT_PROP_HEAL_ADD),
entry("cd", FIGHT_PROP_CRITICAL_HURT), entry("cd", FIGHT_PROP_CRITICAL_HURT),
entry("cdmg", FIGHT_PROP_CRITICAL_HURT), entry("cdmg", FIGHT_PROP_CRITICAL_HURT),
entry("cr", FIGHT_PROP_CRITICAL), entry("cr", FIGHT_PROP_CRITICAL),
entry("crate", FIGHT_PROP_CRITICAL), entry("crate", FIGHT_PROP_CRITICAL),
entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT), entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT),
entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT), entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT),
entry("geo%", FIGHT_PROP_ROCK_ADD_HURT), entry("geo%", FIGHT_PROP_ROCK_ADD_HURT),
entry("anemo%", FIGHT_PROP_WIND_ADD_HURT), entry("anemo%", FIGHT_PROP_WIND_ADD_HURT),
entry("hydro%", FIGHT_PROP_WATER_ADD_HURT), entry("hydro%", FIGHT_PROP_WATER_ADD_HURT),
entry("cryo%", FIGHT_PROP_ICE_ADD_HURT), entry("cryo%", FIGHT_PROP_ICE_ADD_HURT),
entry("electro%", FIGHT_PROP_ELEC_ADD_HURT), entry("electro%", FIGHT_PROP_ELEC_ADD_HURT),
entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT), entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT),
// Other stats // Other stats
entry("maxhp", FIGHT_PROP_MAX_HP), entry("maxhp", FIGHT_PROP_MAX_HP),
entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks
@ -189,7 +191,7 @@ public enum FightProperty {
entry("reshydro", FIGHT_PROP_WATER_SUB_HURT), entry("reshydro", FIGHT_PROP_WATER_SUB_HURT),
entry("respyro", FIGHT_PROP_FIRE_SUB_HURT), entry("respyro", FIGHT_PROP_FIRE_SUB_HURT),
entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT) entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT)
); );
private static final List<FightProperty> flatProps = Arrays.asList( private static final List<FightProperty> flatProps = Arrays.asList(
FIGHT_PROP_BASE_HP, FIGHT_PROP_HP, FIGHT_PROP_BASE_ATTACK, FIGHT_PROP_ATTACK, FIGHT_PROP_BASE_DEFENSE, FIGHT_PROP_BASE_HP, FIGHT_PROP_HP, FIGHT_PROP_BASE_ATTACK, FIGHT_PROP_ATTACK, FIGHT_PROP_BASE_DEFENSE,
@ -197,6 +199,35 @@ public enum FightProperty {
FIGHT_PROP_CUR_WATER_ENERGY, FIGHT_PROP_CUR_GRASS_ENERGY, FIGHT_PROP_CUR_WIND_ENERGY, FIGHT_PROP_CUR_ICE_ENERGY, FIGHT_PROP_CUR_WATER_ENERGY, FIGHT_PROP_CUR_GRASS_ENERGY, FIGHT_PROP_CUR_WIND_ENERGY, FIGHT_PROP_CUR_ICE_ENERGY,
FIGHT_PROP_CUR_ROCK_ENERGY, FIGHT_PROP_CUR_HP, FIGHT_PROP_MAX_HP, FIGHT_PROP_CUR_ATTACK, FIGHT_PROP_CUR_DEFENSE); FIGHT_PROP_CUR_ROCK_ENERGY, FIGHT_PROP_CUR_HP, FIGHT_PROP_MAX_HP, FIGHT_PROP_CUR_ATTACK, FIGHT_PROP_CUR_DEFENSE);
@Getter
public static class CompoundProperty {
private FightProperty result;
private FightProperty base;
private FightProperty percent;
private FightProperty flat;
public CompoundProperty(FightProperty result, FightProperty base, FightProperty percent, FightProperty flat) {
this.result = result;
this.base = base;
this.percent = percent;
this.flat = flat;
}
}
private static Map<FightProperty, CompoundProperty> compoundProperties = Map.ofEntries(
entry(FIGHT_PROP_MAX_HP, new CompoundProperty(FIGHT_PROP_MAX_HP, FIGHT_PROP_BASE_HP, FIGHT_PROP_HP_PERCENT, FIGHT_PROP_HP)),
entry(FIGHT_PROP_CUR_ATTACK, new CompoundProperty(FIGHT_PROP_CUR_ATTACK, FIGHT_PROP_BASE_ATTACK, FIGHT_PROP_ATTACK_PERCENT, FIGHT_PROP_ATTACK)),
entry(FIGHT_PROP_CUR_DEFENSE, new CompoundProperty(FIGHT_PROP_CUR_DEFENSE, FIGHT_PROP_BASE_DEFENSE, FIGHT_PROP_DEFENSE_PERCENT, FIGHT_PROP_DEFENSE))
);
public static CompoundProperty getCompoundProperty(FightProperty result) {
return compoundProperties.get(result);
}
public static void forEachCompoundProperty(Consumer<CompoundProperty> consumer) {
compoundProperties.values().forEach(consumer);
}
public static boolean isPercentage(FightProperty prop) { public static boolean isPercentage(FightProperty prop) {
return !flatProps.contains(prop); return !flatProps.contains(prop);
} }

View File

@ -24,7 +24,7 @@ public class ItemUseAction {
case ITEM_USE_GAIN_AVATAR -> new ItemUseGainAvatar(useParam); case ITEM_USE_GAIN_AVATAR -> new ItemUseGainAvatar(useParam);
case ITEM_USE_GAIN_COSTUME -> new ItemUseGainCostume(useParam); // TODO - real success/fail case ITEM_USE_GAIN_COSTUME -> new ItemUseGainCostume(useParam); // TODO - real success/fail
case ITEM_USE_GAIN_FLYCLOAK -> new ItemUseGainFlycloak(useParam); // TODO - real success/fail case ITEM_USE_GAIN_FLYCLOAK -> new ItemUseGainFlycloak(useParam); // TODO - real success/fail
case ITEM_USE_GAIN_NAME_CARD -> new ItemUseGainNameCard(useParam); // TODO case ITEM_USE_GAIN_NAME_CARD -> new ItemUseGainNameCard(useParam);
case ITEM_USE_CHEST_SELECT_ITEM -> new ItemUseChestSelectItem(useParam); case ITEM_USE_CHEST_SELECT_ITEM -> new ItemUseChestSelectItem(useParam);
case ITEM_USE_ADD_SELECT_ITEM -> new ItemUseAddSelectItem(useParam); case ITEM_USE_ADD_SELECT_ITEM -> new ItemUseAddSelectItem(useParam);
case ITEM_USE_GRANT_SELECT_REWARD -> new ItemUseGrantSelectReward(useParam); case ITEM_USE_GRANT_SELECT_REWARD -> new ItemUseGrantSelectReward(useParam);

View File

@ -1,19 +1,18 @@
package emu.grasscutter.game.props.ItemUseAction; package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.ItemUseOp;
import lombok.Getter;
public class ItemUseAddExp extends ItemUseAction {
@Getter private int exp = 0;
public class ItemUseAddExp extends ItemUseInt {
@Override @Override
public ItemUseOp getItemUseOp() { public ItemUseOp getItemUseOp() {
return ItemUseOp.ITEM_USE_ADD_EXP; return ItemUseOp.ITEM_USE_ADD_EXP;
} }
public ItemUseAddExp(String[] useParam) { public ItemUseAddExp(String[] useParam) {
try { super(useParam);
this.exp = Integer.parseInt(useParam[0]); }
} catch (NumberFormatException ignored) {}
public int getExp() {
return this.i;
} }
} }

View File

@ -14,7 +14,7 @@ public class ItemUseAddItem extends ItemUseInt {
super(useParam); super(useParam);
try { try {
this.count = Integer.parseInt(useParam[1]); this.count = Integer.parseInt(useParam[1]);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
} }
@Override @Override

View File

@ -1,19 +1,14 @@
package emu.grasscutter.game.props.ItemUseAction; package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.ItemUseOp;
import lombok.Getter;
public class ItemUseAddReliquaryExp extends ItemUseAction {
@Getter private int exp = 0;
public class ItemUseAddReliquaryExp extends ItemUseAddExp {
@Override @Override
public ItemUseOp getItemUseOp() { public ItemUseOp getItemUseOp() {
return ItemUseOp.ITEM_USE_ADD_RELIQUARY_EXP; return ItemUseOp.ITEM_USE_ADD_RELIQUARY_EXP;
} }
public ItemUseAddReliquaryExp(String[] useParam) { public ItemUseAddReliquaryExp(String[] useParam) {
try { super(useParam);
this.exp = Integer.parseInt(useParam[0]);
} catch (NumberFormatException ignored) {}
} }
} }

View File

@ -14,7 +14,7 @@ public class ItemUseAddServerBuff extends ItemUseInt {
super(useParam); super(useParam);
try { try {
this.duration = Integer.parseInt(useParam[1]); this.duration = Integer.parseInt(useParam[1]);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
} }
@Override @Override

View File

@ -1,19 +1,14 @@
package emu.grasscutter.game.props.ItemUseAction; package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.ItemUseOp;
import lombok.Getter;
public class ItemUseAddWeaponExp extends ItemUseAction {
@Getter private int exp = 0;
public class ItemUseAddWeaponExp extends ItemUseAddExp {
@Override @Override
public ItemUseOp getItemUseOp() { public ItemUseOp getItemUseOp() {
return ItemUseOp.ITEM_USE_ADD_WEAPON_EXP; return ItemUseOp.ITEM_USE_ADD_WEAPON_EXP;
} }
public ItemUseAddWeaponExp(String[] useParam) { public ItemUseAddWeaponExp(String[] useParam) {
try { super(useParam);
this.exp = Integer.parseInt(useParam[0]);
} catch (NumberFormatException ignored) {}
} }
} }

View File

@ -15,10 +15,10 @@ public class ItemUseCombineItem extends ItemUseInt {
super(useParam); super(useParam);
try { try {
this.resultId = Integer.parseInt(useParam[1]); this.resultId = Integer.parseInt(useParam[1]);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
try { try {
this.resultCount = Integer.parseInt(useParam[2]); this.resultCount = Integer.parseInt(useParam[2]);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
} }
@Override @Override

View File

@ -19,10 +19,10 @@ public class ItemUseGainAvatar extends ItemUseInt {
super(useParam); super(useParam);
try { try {
this.level = Integer.parseInt(useParam[1]); this.level = Integer.parseInt(useParam[1]);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
try { try {
this.constellation = Integer.parseInt(useParam[2]); this.constellation = Integer.parseInt(useParam[2]);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
} }
@Override @Override

View File

@ -2,6 +2,8 @@ package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.ItemUseOp;
import emu.grasscutter.data.GameData;
public class ItemUseGainCostume extends ItemUseInt { public class ItemUseGainCostume extends ItemUseInt {
@Override @Override
public ItemUseOp getItemUseOp() { public ItemUseOp getItemUseOp() {
@ -14,7 +16,9 @@ public class ItemUseGainCostume extends ItemUseInt {
@Override @Override
public boolean useItem(UseItemParams params) { public boolean useItem(UseItemParams params) {
params.player.getInventory().addItem(this.i); // TODO: Currently this returns false for all virtual items - need to have a proper success/fail if (GameData.getAvatarCostumeDataMap().containsKey(this.i)) {
params.player.addCostume(this.i);
}
return true; return true;
} }
} }

View File

@ -2,6 +2,8 @@ package emu.grasscutter.game.props.ItemUseAction;
import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.ItemUseOp;
import emu.grasscutter.data.GameData;
public class ItemUseGainFlycloak extends ItemUseInt { public class ItemUseGainFlycloak extends ItemUseInt {
@Override @Override
public ItemUseOp getItemUseOp() { public ItemUseOp getItemUseOp() {
@ -14,7 +16,9 @@ public class ItemUseGainFlycloak extends ItemUseInt {
@Override @Override
public boolean useItem(UseItemParams params) { public boolean useItem(UseItemParams params) {
params.player.getInventory().addItem(this.i); // TODO: Currently this returns false for all virtual items - need to have a proper success/fail if (GameData.getAvatarFlycloakDataMap().containsKey(this.i)) {
params.player.addFlycloak(this.i);
}
return true; return true;
} }
} }

View File

@ -13,6 +13,7 @@ public class ItemUseGainNameCard extends ItemUseAction {
@Override @Override
public boolean useItem(UseItemParams params) { public boolean useItem(UseItemParams params) {
return false; // TODO: work out if this is actually used and how to get the namecard id params.player.addNameCard(params.usedItemId);
return true;
} }
} }

View File

@ -8,6 +8,6 @@ public abstract class ItemUseInt extends ItemUseAction {
public ItemUseInt(String[] useParam) { public ItemUseInt(String[] useParam) {
try { try {
this.i = Integer.parseInt(useParam[0]); this.i = Integer.parseInt(useParam[0]);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
} }
} }

Some files were not shown because too many files have changed in this diff Show More