mirror of
https://github.com/Anime-Game-Servers/Grasscutter-Quests.git
synced 2024-12-04 02:31:06 +00:00
Merge pull request #47 from Hartie95/upstream_3.2
Update to newest 3.2 upstream GC
This commit is contained in:
commit
ede2346400
@ -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>
|
||||
|
||||
[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).
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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).
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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.
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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).
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
|
||||
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
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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).
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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).
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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.
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
* Daftar teman
|
||||
* Teleportasi
|
||||
* Sistem gacha
|
||||
* Co-op *sebahagian* berfungsi
|
||||
* Co-op *sebagian* berfungsi
|
||||
* Memunculkan monster melalui konsol
|
||||
* 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`
|
||||
|
||||
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
|
||||
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
|
||||
@ -103,6 +103,6 @@ Anda bisa menemukan output jar di root folder proyek.
|
||||
# Quick Troubleshooting
|
||||
|
||||
* 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
|
||||
* Urutan startup: MongoDB > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Game
|
||||
|
108
README_it-IT.md
Normal file
108
README_it-IT.md
Normal 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
|
@ -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>
|
||||
|
||||
[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)
|
||||
|
||||
***:** サーバーを動作させるだけならjreのみで十分です。 開発をしたい場合JDKが必要になるかもしれません。
|
||||
***:** サーバーを動作させるだけならjreのみで十分です。 開発をしたい場合JDKが必要になるかもしれません。
|
||||
|
||||
* [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`を入手する
|
||||
- [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) を参照してください.)*
|
||||
3. コマンドプロンプトに`java -jar grasscutter.jar`を入力しGrasscutterを起動してください。 **このときMongoDBも実行する必要があります。**
|
||||
- [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) を参照してください.)*
|
||||
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. 通信内容をリダイレクトする: (どちらか一つを選択してください)
|
||||
- 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
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
##### Windows
|
||||
@ -96,13 +95,13 @@ chmod +x gradlew
|
||||
./gradlew jar # コンパイル
|
||||
```
|
||||
|
||||
コンパイルされたjarファイルはプロゼクトフォルダーのルートに有ります。
|
||||
生成されたjarファイルはプロジェクトフォルダのルートに有ります。
|
||||
|
||||
### コマンドリストは[wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)へ移動しました。
|
||||
|
||||
# トラブルシューティング
|
||||
|
||||
* コンパイルが失敗した場合JDKがインストールされているか確認してください (JDKの17以降と環境変数でJAVAのパスが設定されている必要があります)
|
||||
* クライアントが接続できない、 ログインできない、 エラーコード4206、 その他... - ほとんどの場合、プロキシ デーモンの設定が問題です。
|
||||
Fiddlerを使用している場合はポートが8888以外に設定されていることを確認してください。
|
||||
* 起動シーケンス(順番): MongoDB > Grasscutter > プロキシツール (mitmdumpかfiddler、その他) > ゲーム
|
||||
* コンパイルが失敗した場合JDKがインストールされているか確認してください。(JDKのバージョンが17以降であることと、環境変数でJDKのパスが設定されている必要があります)
|
||||
* クライアントが接続できない・ログインできない・エラーコード4206・またその他場合、ほとんどは、プロキシデーモンの設定が問題です。Fiddlerを使っている場合はデフォルトポートを8888以外の別のポートに変更してみてください。
|
||||
Fiddlerを使用している場合はポートが8888以外に設定されていることを確認してください。
|
||||
* 起動シーケンス(順番): MongoDB > Grasscutter > プロキシツール (mitmdumpかfiddler、その他) > ゲーム
|
||||
|
@ -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>
|
||||
|
||||
[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)을 주의 깊게 읽어주세요.
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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).
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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).
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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)。
|
||||
|
||||
|
@ -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>
|
||||
|
||||
[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)。
|
||||
|
||||
|
@ -45,7 +45,7 @@ sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
group = 'xyz.grasscutters'
|
||||
version = '1.4.3-dev'
|
||||
version = '1.4.4-dev'
|
||||
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
270
gradlew
vendored
270
gradlew
vendored
@ -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");
|
||||
# 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
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
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.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
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."
|
||||
fi
|
||||
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.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
@ -105,84 +140,95 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
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" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --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
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
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
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# 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
|
||||
|
||||
# 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" "$@"
|
||||
|
189
gradlew.bat
vendored
189
gradlew.bat
vendored
@ -1,100 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@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"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
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
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@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%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
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.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
@ -6,7 +6,7 @@ import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
|
||||
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 MAX_TEAMS = 10;
|
||||
|
@ -293,8 +293,8 @@ public final class Grasscutter {
|
||||
Grasscutter.getLogger().info("EOF detected.");
|
||||
continue;
|
||||
} catch (IOError e) {
|
||||
Grasscutter.getLogger().error("An IO error occurred.", e);
|
||||
continue;
|
||||
Grasscutter.getLogger().error("An IO error occurred while trying to read from console.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
isLastInterrupted = false;
|
||||
|
@ -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) {
|
||||
for (int i = args.size() - 1; i >= 0; i--) {
|
||||
String arg = args.get(i).toLowerCase();
|
||||
args.removeIf(arg -> {
|
||||
var argL = arg.toLowerCase();
|
||||
boolean deleteArg = false;
|
||||
int argNum;
|
||||
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);
|
||||
deleteArg = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (deleteArg) {
|
||||
args.remove(i);
|
||||
}
|
||||
}
|
||||
return deleteArg;
|
||||
});
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public final class CommandMap {
|
||||
}
|
||||
|
||||
public List<Command> getAnnotationsAsList() {
|
||||
return new LinkedList<>(this.annotations.values());
|
||||
return new ArrayList<>(this.annotations.values());
|
||||
}
|
||||
|
||||
public Map<String, Command> getAnnotations() {
|
||||
@ -102,7 +102,7 @@ public final class CommandMap {
|
||||
* @return All command handlers as a list.
|
||||
*/
|
||||
public List<CommandHandler> getHandlersAsList() {
|
||||
return new LinkedList<>(this.commands.values());
|
||||
return new ArrayList<>(this.commands.values());
|
||||
}
|
||||
|
||||
public Map<String, CommandHandler> getHandlers() {
|
||||
@ -234,8 +234,8 @@ public final class CommandMap {
|
||||
|
||||
// Parse message.
|
||||
String[] split = rawMessage.split(" ");
|
||||
List<String> args = new LinkedList<>(Arrays.asList(split));
|
||||
String label = args.remove(0).toLowerCase();
|
||||
String label = split[0].toLowerCase();
|
||||
List<String> args = new ArrayList<>(Arrays.asList(split).subList(1, split.length));
|
||||
String playerId = (player == null) ? consoleId : player.getAccount().getId();
|
||||
|
||||
// Check for special cases - currently only target command.
|
||||
|
@ -9,6 +9,7 @@ import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
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);
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", mailBuilder.recipient));
|
||||
} else {
|
||||
for (Player player : DatabaseHelper.getAllPlayers()) {
|
||||
Grasscutter.getGameServer().getPlayerByUid(player.getUid(), true).sendMail(mailBuilder.mail);
|
||||
}
|
||||
DatabaseHelper.getByGameClass(Player.class).forEach(player -> {
|
||||
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"));
|
||||
}
|
||||
mailBeingConstructed.remove(senderId);
|
||||
|
@ -67,9 +67,10 @@ public final class SetStatsCommand implements CommandHandler {
|
||||
|
||||
// Compatibility aliases
|
||||
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("atk", new Stat(FightProperty.FIGHT_PROP_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("hp", this.stats.get("_cur_hp")); // Overrides FIGHT_PROP_HP
|
||||
this.stats.put("atk", this.stats.get("_cur_attack")); // Overrides FIGHT_PROP_ATTACK
|
||||
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("ecryo", this.stats.get("cryo%"));
|
||||
this.stats.put("edendro", this.stats.get("dendro%"));
|
||||
|
@ -5,6 +5,8 @@ import emu.grasscutter.server.http.handlers.GachaHandler;
|
||||
import emu.grasscutter.tools.Tools;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
import emu.grasscutter.utils.JsonUtils;
|
||||
import emu.grasscutter.utils.TsvUtils;
|
||||
import lombok.val;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
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() {
|
||||
try {
|
||||
List<Path> filenames = FileUtils.getPathsFromResource("/defaults/data/");
|
||||
|
@ -6,21 +6,22 @@ import emu.grasscutter.data.binout.*;
|
||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
|
||||
import emu.grasscutter.data.binout.routes.SceneRoutes;
|
||||
import emu.grasscutter.data.common.PointData;
|
||||
import emu.grasscutter.data.excels.QuestData;
|
||||
import emu.grasscutter.data.server.GadgetMapping;
|
||||
import emu.grasscutter.game.dungeons.DungeonDrop;
|
||||
import emu.grasscutter.game.managers.blossom.BlossomConfig;
|
||||
import emu.grasscutter.game.quest.QuestEncryptionKey;
|
||||
import emu.grasscutter.game.quest.RewindData;
|
||||
import emu.grasscutter.game.quest.TeleportData;
|
||||
import emu.grasscutter.game.quest.enums.QuestCond;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry.GridBlockId;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
|
||||
import emu.grasscutter.scripts.EntityControllerScriptManager;
|
||||
import emu.grasscutter.scripts.SceneIndexManager;
|
||||
import emu.grasscutter.scripts.ScriptLoader;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
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.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntArraySet;
|
||||
@ -32,6 +33,8 @@ import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.Collectors;
|
||||
@ -45,8 +48,9 @@ import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
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() {
|
||||
Reflections reflections = new Reflections(ResourceLoader.class.getPackage().getName());
|
||||
Set<?> classes = reflections.getSubTypesOf(GameResource.class);
|
||||
@ -64,6 +68,25 @@ public class ResourceLoader {
|
||||
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;
|
||||
public static void loadAll() {
|
||||
if (loadedAll) return;
|
||||
@ -105,48 +128,66 @@ public class ResourceLoader {
|
||||
}
|
||||
|
||||
public static void loadResources(boolean doReload) {
|
||||
for (Class<?> resourceDefinition : getResourceDefClasses()) {
|
||||
ResourceType type = resourceDefinition.getAnnotation(ResourceType.class);
|
||||
long startTime = System.nanoTime();
|
||||
val errors = new ConcurrentLinkedQueue<Pair<String, Exception>>(); // Logger in a parallel stream will deadlock
|
||||
|
||||
if (type == null) {
|
||||
continue;
|
||||
}
|
||||
getResourceDefClassesPrioritySets().forEach(classes -> {
|
||||
classes.stream()
|
||||
.parallel().unordered()
|
||||
.forEach(c -> {
|
||||
val type = c.getAnnotation(ResourceType.class);
|
||||
if (type == null) return;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
Int2ObjectMap map = GameData.getMapByResourceDef(resourceDefinition);
|
||||
val map = GameData.getMapByResourceDef(c);
|
||||
if (map == null) return;
|
||||
|
||||
if (map == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
loadFromResource(resourceDefinition, type, map, doReload);
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error("Error loading resource file: " + Arrays.toString(type.name()), e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
loadFromResource(c, type, map, doReload);
|
||||
} catch (Exception e) {
|
||||
errors.add(Pair.of(Arrays.toString(type.name()), e));
|
||||
}
|
||||
});
|
||||
});
|
||||
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")
|
||||
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()) {
|
||||
loadFromResource(c, name, map);
|
||||
loadFromResource(c, FileUtils.getExcelPath(name), map);
|
||||
}
|
||||
loadedResources.add(c.getSimpleName());
|
||||
Grasscutter.getLogger().debug("Loaded " + map.size() + " " + c.getSimpleName() + "s.");
|
||||
loadedResources.add(simpleName);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
protected static <T> void loadFromResource(Class<T> c, String fileName, Int2ObjectMap map) throws Exception {
|
||||
List<T> list = JsonUtils.loadToList(getResourcePath("ExcelBinOutput/" + fileName), c);
|
||||
|
||||
for (T o : list) {
|
||||
protected static <T> void loadFromResource(Class<T> c, Path filename, Int2ObjectMap map) throws Exception {
|
||||
val results = switch (FileUtils.getFileExtension(filename)) {
|
||||
case "json" -> JsonUtils.loadToList(filename, c);
|
||||
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;
|
||||
res.onLoad();
|
||||
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 static class ScenePointConfig { // Sadly this doesn't work as a local class in loadScenePoints()
|
||||
|
@ -2,6 +2,8 @@ package emu.grasscutter.data;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ResourceType {
|
||||
@ -28,5 +30,9 @@ public @interface ResourceType {
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static List<LoadPriority> getInOrder() {
|
||||
return Stream.of(LoadPriority.values()).sorted((x, y) -> y.value() - x.value()).toList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,18 +13,15 @@ import java.util.List;
|
||||
@Getter
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class ActivityWatcherData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
int id;
|
||||
int rewardID;
|
||||
int progress;
|
||||
WatcherTrigger triggerConfig;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ public class AvatarData extends GameResource {
|
||||
private float criticalHurt;
|
||||
|
||||
private List<PropGrowCurve> propGrowCurves;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
|
||||
// Transient
|
||||
@ -60,11 +61,6 @@ public class AvatarData extends GameResource {
|
||||
@Getter private int nameCardRewardId;
|
||||
@Getter private int nameCardId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public float getBaseHp(int level) {
|
||||
try {
|
||||
return this.hpBase * this.hpGrowthCurve[level - 1];
|
||||
|
@ -7,7 +7,9 @@ import emu.grasscutter.game.props.ElementType;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "AvatarSkillExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)
|
||||
@Getter
|
||||
public class AvatarSkillData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
@Getter private float cdTime;
|
||||
@Getter private float costElemVal; // fight prop update uses float
|
||||
@ -19,14 +21,4 @@ public class AvatarSkillData extends GameResource {
|
||||
@Getter private long nameTextMapHash;
|
||||
@Getter private long descTextMapHash;
|
||||
@Getter private String abilityName;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,31 +18,27 @@ import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "AvatarSkillDepotExcelConfigData.json", loadPriority = LoadPriority.HIGH)
|
||||
@Getter
|
||||
public class AvatarSkillDepotData extends GameResource {
|
||||
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
@Getter private int energySkill;
|
||||
@Getter private int attackModeSkill;
|
||||
private int energySkill;
|
||||
private int attackModeSkill;
|
||||
|
||||
@Getter private List<Integer> skills;
|
||||
@Getter private List<Integer> subSkills;
|
||||
@Getter private List<String> extraAbilities;
|
||||
@Getter private List<Integer> talents;
|
||||
@Getter private List<InherentProudSkillOpens> inherentProudSkillOpens;
|
||||
private List<Integer> skills;
|
||||
private List<Integer> subSkills;
|
||||
private List<String> extraAbilities;
|
||||
private List<Integer> talents;
|
||||
private List<InherentProudSkillOpens> inherentProudSkillOpens;
|
||||
|
||||
@Getter private String talentStarName;
|
||||
@Getter private String skillDepotAbilityGroup;
|
||||
private String talentStarName;
|
||||
private String skillDepotAbilityGroup;
|
||||
|
||||
// Transient
|
||||
@Getter private AvatarSkillData energySkillData;
|
||||
@Getter private ElementType elementType;
|
||||
@Getter private IntList abilities;
|
||||
@Getter private int talentCostItemId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
private AvatarSkillData energySkillData;
|
||||
private ElementType elementType;
|
||||
private IntList abilities;
|
||||
private int talentCostItemId;
|
||||
|
||||
public void setAbilities(AbilityEmbryoEntry info) {
|
||||
this.abilities = new IntArrayList(info.getAbilities().length);
|
||||
@ -77,9 +73,10 @@ public class AvatarSkillDepotData extends GameResource {
|
||||
.ifPresent(itemId -> this.talentCostItemId = itemId);
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class InherentProudSkillOpens {
|
||||
@Getter private int proudSkillGroupId;
|
||||
@Getter private int needAvatarPromoteLevel;
|
||||
private int proudSkillGroupId;
|
||||
private int needAvatarPromoteLevel;
|
||||
}
|
||||
|
||||
public IntStream getSkillsAndEnergySkill() {
|
||||
|
@ -9,65 +9,61 @@ import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.props.BattlePassMissionRefreshType;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@ResourceType(name = {"BattlePassMissionExcelConfigData.json"})
|
||||
@Getter
|
||||
public class BattlePassMissionData extends GameResource {
|
||||
private int addPoint;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private int addPoint;
|
||||
private int scheduleId;
|
||||
private int progress;
|
||||
private TriggerConfig triggerConfig;
|
||||
private BattlePassMissionRefreshType refreshType;
|
||||
|
||||
|
||||
private transient Set<Integer> mainParams;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public WatcherTriggerType getTriggerType() {
|
||||
return this.getTriggerConfig().getTriggerType();
|
||||
}
|
||||
|
||||
public boolean isCycleRefresh() {
|
||||
return getRefreshType() == null || getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE;
|
||||
}
|
||||
|
||||
public boolean isValidRefreshType() {
|
||||
return getRefreshType() == null ||
|
||||
getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE ||
|
||||
getScheduleId() == 2701;
|
||||
return this.getTriggerConfig().getTriggerType();
|
||||
}
|
||||
|
||||
|
||||
public boolean isCycleRefresh() {
|
||||
return getRefreshType() == null || getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE;
|
||||
}
|
||||
|
||||
public boolean isValidRefreshType() {
|
||||
return getRefreshType() == null ||
|
||||
getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE ||
|
||||
getScheduleId() == 2701;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
if (this.getTriggerConfig() != null && getTriggerConfig().getParamList()[0].length() > 0) {
|
||||
this.mainParams = Arrays.stream(getTriggerConfig().getParamList()[0].split("[:;,]")).map(Integer::parseInt).collect(Collectors.toSet());
|
||||
}
|
||||
if (this.getTriggerConfig() != null) {
|
||||
var params = getTriggerConfig().getParamList()[0];
|
||||
if ((params != null) && !params.isEmpty()) {
|
||||
this.mainParams = Arrays.stream(params.split("[:;,]")).map(Integer::parseInt).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Getter
|
||||
public static class TriggerConfig {
|
||||
private WatcherTriggerType triggerType;
|
||||
private String[] paramList;
|
||||
private WatcherTriggerType triggerType;
|
||||
private String[] paramList;
|
||||
}
|
||||
|
||||
|
||||
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
|
||||
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
|
||||
|
||||
protoBuilder
|
||||
.setMissionId(getId())
|
||||
.setTotalProgress(this.getProgress())
|
||||
.setRewardBattlePassPoint(this.getAddPoint())
|
||||
.setMissionStatus(MissionStatus.MISSION_STATUS_UNFINISHED)
|
||||
.setMissionType(this.getRefreshType() == null ? 0 : this.getRefreshType().getValue());
|
||||
|
||||
return protoBuilder.build();
|
||||
}
|
||||
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
|
||||
|
||||
protoBuilder
|
||||
.setMissionId(getId())
|
||||
.setTotalProgress(this.getProgress())
|
||||
.setRewardBattlePassPoint(this.getAddPoint())
|
||||
.setMissionStatus(MissionStatus.MISSION_STATUS_UNFINISHED)
|
||||
.setMissionType(this.getRefreshType() == null ? 0 : this.getRefreshType().getValue());
|
||||
|
||||
return protoBuilder.build();
|
||||
}
|
||||
}
|
||||
|
@ -7,40 +7,39 @@ import emu.grasscutter.data.ResourceType;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "BlossomRefreshExcelConfigData.json")
|
||||
@Getter
|
||||
public class BlossomRefreshExcelConfigData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
// Map details
|
||||
@Getter private long nameTextMapHash;
|
||||
@Getter private long descTextMapHash;
|
||||
@Getter private String icon;
|
||||
@Getter private String clientShowType; // BLOSSOM_SHOWTYPE_CHALLENGE, BLOSSOM_SHOWTYPE_NPCTALK
|
||||
private long nameTextMapHash;
|
||||
private long descTextMapHash;
|
||||
private String icon;
|
||||
private String clientShowType; // BLOSSOM_SHOWTYPE_CHALLENGE, BLOSSOM_SHOWTYPE_NPCTALK
|
||||
|
||||
// Refresh details
|
||||
@Getter 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)
|
||||
@Getter private String refreshTime; // Server time-of-day to refresh at
|
||||
@Getter private RefreshCond[] refreshCondVec; // AR requirements etc.
|
||||
private String refreshType; // Leyline blossoms, magical ore outcrops
|
||||
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 String refreshTime; // Server time-of-day to refresh at
|
||||
private RefreshCond[] refreshCondVec; // AR requirements etc.
|
||||
|
||||
@Getter private int cityId;
|
||||
@Getter private int blossomChestId; // 1 for mora, 2 for exp
|
||||
@Getter private Drop[] dropVec;
|
||||
private int cityId;
|
||||
private int blossomChestId; // 1 for mora, 2 for exp
|
||||
private Drop[] dropVec;
|
||||
|
||||
// Unknown details
|
||||
// @Getter private int reviseLevel;
|
||||
// @Getter private int campUpdateNeedCount; // Always 1 if specified
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class Drop {
|
||||
@Getter int dropId;
|
||||
@Getter int previewReward;
|
||||
int dropId;
|
||||
int previewReward;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class RefreshCond {
|
||||
@Getter String type;
|
||||
@Getter List<Integer> param;
|
||||
String type;
|
||||
List<Integer> param;
|
||||
}
|
||||
}
|
||||
|
@ -8,27 +8,23 @@ import lombok.Setter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ResourceType(name = "ChapterExcelConfigData.json")
|
||||
@Getter
|
||||
@Setter
|
||||
@Setter // TODO: remove on next API break
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class ChapterData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
int id;
|
||||
int beginQuestId;
|
||||
int endQuestId;
|
||||
int needPlayerLevel;
|
||||
|
||||
// Why public? TODO: privatise next API break
|
||||
public static final Map<Integer, ChapterData> beginQuestChapterMap = new HashMap<>();
|
||||
public static final Map<Integer, ChapterData> endQuestChapterMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
beginQuestChapterMap.put(beginQuestId, this);
|
||||
|
@ -22,9 +22,4 @@ public class CityData extends GameResource {
|
||||
public int getId() {
|
||||
return this.cityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
super.onLoad();
|
||||
}
|
||||
}
|
||||
|
@ -7,18 +7,15 @@ import emu.grasscutter.data.ResourceType;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = {"AnimalCodexExcelConfigData.json"})
|
||||
@Getter
|
||||
public class CodexAnimalData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int Id;
|
||||
@Getter private String type;
|
||||
@Getter private int describeId;
|
||||
@Getter private int sortOrder;
|
||||
private String type;
|
||||
private int describeId;
|
||||
private int sortOrder;
|
||||
@SerializedName(value="countType", alternate={"OCCLHPBCDGL"})
|
||||
@Getter private CountType countType;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
private CountType countType;
|
||||
|
||||
public enum CountType {
|
||||
CODEX_COUNT_TYPE_KILL,
|
||||
|
@ -8,19 +8,15 @@ import lombok.Getter;
|
||||
import java.util.List;
|
||||
|
||||
@ResourceType(name = {"CompoundExcelConfigData.json"},loadPriority = ResourceType.LoadPriority.LOW)
|
||||
@Getter
|
||||
public class CompoundData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
|
||||
@Override
|
||||
public int getId() {return this.id;}
|
||||
@Getter private int groupId;
|
||||
@Getter private int rankLevel;
|
||||
@Getter private boolean isDefaultUnlocked;
|
||||
@Getter private int costTime;
|
||||
@Getter private int queueSize;
|
||||
@Getter private List<ItemParamData> inputVec;
|
||||
@Getter private List<ItemParamData> outputVec;
|
||||
|
||||
@Override
|
||||
public void onLoad(){}
|
||||
private int groupId;
|
||||
private int rankLevel;
|
||||
private boolean isDefaultUnlocked;
|
||||
private int costTime;
|
||||
private int queueSize;
|
||||
private List<ItemParamData> inputVec;
|
||||
private List<ItemParamData> outputVec;
|
||||
}
|
||||
|
@ -9,21 +9,15 @@ import emu.grasscutter.data.common.ItemParamData;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = {"CookRecipeExcelConfigData.json"}, loadPriority = LoadPriority.LOW)
|
||||
@Getter
|
||||
public class CookRecipeData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
|
||||
@Getter private int rankLevel;
|
||||
@Getter boolean isDefaultUnlocked;
|
||||
@Getter int maxProficiency;
|
||||
private int rankLevel;
|
||||
private boolean isDefaultUnlocked;
|
||||
private int maxProficiency;
|
||||
|
||||
@Getter List<ItemParamData> qualityOutputVec;
|
||||
@Getter List<ItemParamData> inputVec;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
@Override
|
||||
public void onLoad() {
|
||||
}
|
||||
private List<ItemParamData> qualityOutputVec;
|
||||
private List<ItemParamData> inputVec;
|
||||
}
|
||||
|
@ -7,9 +7,11 @@ import emu.grasscutter.data.ResourceType;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "DailyDungeonConfigData.json")
|
||||
public class DailyDungeonData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private int[] monday;
|
||||
private int[] tuesday;
|
||||
@ -26,11 +28,6 @@ public class DailyDungeonData extends GameResource {
|
||||
this.map = new Int2ObjectOpenHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int[] getDungeonsByDay(int day) {
|
||||
return map.getOrDefault(day, empty);
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import java.util.List;
|
||||
|
||||
@ResourceType(name = "DungeonExcelConfigData.json")
|
||||
public class DungeonData extends GameResource {
|
||||
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
@Getter private int sceneId;
|
||||
@Getter private int showLevel;
|
||||
@ -28,13 +30,9 @@ public class DungeonData extends GameResource {
|
||||
@Getter private int statueCostID;
|
||||
@Getter private int statueCostCount;
|
||||
|
||||
// not part of DungeonExcelConfigData
|
||||
@Getter private RewardPreviewData rewardPreviewData;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public DungeonType getType() {
|
||||
if (type == null) {
|
||||
return DungeonType.DUNGEON_NONE;
|
||||
|
@ -13,11 +13,12 @@ import java.util.List;
|
||||
|
||||
@ResourceType(name = "DungeonEntryExcelConfigData.json")
|
||||
@Getter
|
||||
@Setter
|
||||
@Setter // TODO: remove this next API break
|
||||
public class DungeonEntryData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private int dungeonEntryId;
|
||||
private int sceneId;
|
||||
private int id;
|
||||
private DungunEntryType type;
|
||||
private LogicType condComb;
|
||||
private List<SatisfiedCond> satisfiedCond;
|
||||
@ -25,16 +26,6 @@ public class DungeonEntryData extends GameResource {
|
||||
private boolean isShowInAdvHandbook;
|
||||
private boolean isDailyRefresh;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SatisfiedCond{
|
||||
DungeonEntrySatisfiedConditionType type;
|
||||
|
@ -6,9 +6,12 @@ import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = {"ForgeExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST)
|
||||
@Getter
|
||||
public class ForgeData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private int playerLevel;
|
||||
private int forgeType;
|
||||
@ -21,57 +24,4 @@ public class ForgeData extends GameResource {
|
||||
private int priority;
|
||||
private int forgePoint;
|
||||
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() {
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,12 @@ package emu.grasscutter.data.excels;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "GadgetExcelConfigData.json")
|
||||
@Getter
|
||||
public class GadgetData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
|
||||
private EntityType type;
|
||||
@ -15,42 +18,4 @@ public class GadgetData extends GameResource {
|
||||
private String itemJsonName;
|
||||
private long nameTextMapHash;
|
||||
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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -29,9 +29,4 @@ public class HomeWorldLevelData extends GameResource {
|
||||
public int getId() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
super.onLoad();
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@ -14,6 +13,7 @@ import java.util.List;
|
||||
@Getter
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class InvestigationMonsterData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
int id;
|
||||
int cityId;
|
||||
List<Integer> monsterIdList;
|
||||
@ -23,10 +23,6 @@ public class InvestigationMonsterData extends GameResource {
|
||||
String monsterCategory;
|
||||
|
||||
CityData cityData;
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
@ -25,6 +25,7 @@ import lombok.Getter;
|
||||
@Getter
|
||||
public class ItemData extends GameResource {
|
||||
// Main
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private int stackLimit = 1;
|
||||
private int maxUseCount;
|
||||
@ -81,17 +82,12 @@ public class ItemData extends GameResource {
|
||||
private List<Integer> furnType;
|
||||
private List<Integer> furnitureGadgetID;
|
||||
|
||||
@SerializedName(value="roomSceneId", alternate={"DANFGGLKLNO", "JFDLJGDFIGL", "OHIANNAEEAK"})
|
||||
@SerializedName(value="roomSceneId", alternate={"BMEPAMCNABE", "DANFGGLKLNO", "JFDLJGDFIGL", "OHIANNAEEAK"})
|
||||
private int roomSceneId;
|
||||
|
||||
// Custom
|
||||
private transient IntSet addPropLevelSet;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public WeaponProperty[] getWeaponProperties() {
|
||||
return this.weaponProp;
|
||||
}
|
||||
|
@ -2,24 +2,28 @@ package emu.grasscutter.data.excels;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||
import emu.grasscutter.data.common.PropGrowCurve;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.MonsterType;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW)
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@Data
|
||||
@Getter
|
||||
public class MonsterData extends GameResource {
|
||||
private int id;
|
||||
|
||||
private String monsterName;
|
||||
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);
|
||||
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
|
||||
private String monsterName;
|
||||
private MonsterType type;
|
||||
private String serverScript;
|
||||
private List<Integer> affix;
|
||||
@ -34,9 +38,14 @@ public class MonsterData extends GameResource {
|
||||
private int describeId;
|
||||
private int combatBGMLevel;
|
||||
private int entityBudgetLevel;
|
||||
private float hpBase;
|
||||
private float attackBase;
|
||||
private float defenseBase;
|
||||
|
||||
@SerializedName("hpBase")
|
||||
private float baseHp;
|
||||
@SerializedName("attackBase")
|
||||
private float baseAttack;
|
||||
@SerializedName("defenseBase")
|
||||
private float baseDefense;
|
||||
|
||||
private float fireSubHurt;
|
||||
private float elecSubHurt;
|
||||
private float grassSubHurt;
|
||||
@ -48,28 +57,12 @@ public class MonsterData extends GameResource {
|
||||
private List<PropGrowCurve> propGrowCurves;
|
||||
private long nameTextMapHash;
|
||||
private int campID;
|
||||
|
||||
|
||||
// Transient
|
||||
private int weaponId;
|
||||
private MonsterDescribeData describeData;
|
||||
|
||||
private int specialNameId; // will only be set if describe data is available
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public float getBaseHp() {
|
||||
return hpBase;
|
||||
}
|
||||
|
||||
public float getBaseAttack() {
|
||||
return attackBase;
|
||||
}
|
||||
|
||||
public float getBaseDefense() {
|
||||
return defenseBase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
@ -98,16 +91,27 @@ public class MonsterData extends GameResource {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HpDrops {
|
||||
private int DropId;
|
||||
private int HpPercent;
|
||||
|
||||
public int getDropId(){
|
||||
return this.DropId;
|
||||
}
|
||||
public int getHpPercent(){
|
||||
return this.HpPercent;
|
||||
}
|
||||
}
|
||||
public float getFightProperty(FightProperty prop) {
|
||||
return switch (prop) {
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
@Getter
|
||||
public class HpDrops {
|
||||
private int DropId;
|
||||
private int HpPercent;
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,17 @@
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "MonsterDescribeExcelConfigData.json", loadPriority = LoadPriority.HIGH)
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@Data
|
||||
@Getter
|
||||
public class MonsterDescribeData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private long nameTextMapHash;
|
||||
private int titleId;
|
||||
private int specialNameLabId;
|
||||
private MonsterSpecialNameData specialNameData;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,8 @@ import lombok.experimental.FieldDefaults;
|
||||
@Getter
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class MusicGameBasicData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
int id;
|
||||
int musicID;
|
||||
int musicLevel;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,15 @@ package emu.grasscutter.data.excels;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "NpcExcelConfigData.json")
|
||||
@Getter
|
||||
public class NpcData extends GameResource {
|
||||
private int id;
|
||||
|
||||
private String jsonName;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
|
||||
private String jsonName;
|
||||
private String alias;
|
||||
private String scriptDataPath;
|
||||
private String luaDataPath;
|
||||
@ -19,54 +22,4 @@ public class NpcData extends GameResource {
|
||||
|
||||
private long nameTextMapHash;
|
||||
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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,14 @@ package emu.grasscutter.data.excels;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@ResourceType(name = "OpenStateConfigData.json", loadPriority = ResourceType.LoadPriority.HIGHEST)
|
||||
public class OpenStateData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
@Getter private boolean defaultState;
|
||||
@Getter private boolean allowClientOpen;
|
||||
@ -32,11 +31,6 @@ public class OpenStateData extends GameResource {
|
||||
OPEN_STATE_COND_PARENT_QUEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Add this open state to the global list.
|
||||
|
@ -11,18 +11,13 @@ import java.util.List;
|
||||
|
||||
@ResourceType(name = "PersonalLineExcelConfigData.json")
|
||||
@Getter
|
||||
@Setter
|
||||
@Setter // TODO: remove setters next API break
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class PersonalLineData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
int id;
|
||||
int avatarID;
|
||||
List<Integer> preQuestId;
|
||||
int startQuestId;
|
||||
int chapterId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,46 +1,23 @@
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "ReliquaryAffixExcelConfigData.json")
|
||||
@Getter
|
||||
public class ReliquaryAffixData extends GameResource {
|
||||
private int id;
|
||||
|
||||
private int depotId;
|
||||
private int groupId;
|
||||
private FightProperty propType;
|
||||
private float propValue;
|
||||
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;
|
||||
}
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
|
||||
private int depotId;
|
||||
private int groupId;
|
||||
@SerializedName("propType")
|
||||
private FightProperty fightProp;
|
||||
private float propValue;
|
||||
private int weight;
|
||||
private int upgradeWeight;
|
||||
}
|
||||
|
@ -7,36 +7,19 @@ import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "ReliquaryLevelExcelConfigData.json")
|
||||
public class ReliquaryLevelData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private Int2FloatMap propMap;
|
||||
|
||||
private int rank;
|
||||
private int level;
|
||||
private int exp;
|
||||
@Getter private int rank;
|
||||
@Getter private int level;
|
||||
@Getter private int exp;
|
||||
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) {
|
||||
return getPropValue(prop.getId());
|
||||
}
|
||||
@ -54,16 +37,9 @@ public class ReliquaryLevelData extends GameResource {
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public class RelicLevelProperty {
|
||||
private String propType;
|
||||
private float value;
|
||||
|
||||
public String getPropType() {
|
||||
return propType;
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,20 @@
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "ReliquaryMainPropExcelConfigData.json")
|
||||
@Getter
|
||||
public class ReliquaryMainPropData extends GameResource {
|
||||
private int id;
|
||||
|
||||
private int propDepotId;
|
||||
private FightProperty propType;
|
||||
private int weight;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getPropDepotId() {
|
||||
return propDepotId;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
|
||||
public FightProperty getFightProp() {
|
||||
return propType;
|
||||
}
|
||||
private int propDepotId;
|
||||
@SerializedName("propType")
|
||||
private FightProperty fightProp;
|
||||
private int weight;
|
||||
}
|
||||
|
@ -1,43 +1,35 @@
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
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.ResourceType;
|
||||
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
|
||||
import lombok.Getter;
|
||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.common.ItemParamStringData;
|
||||
|
||||
@ResourceType(name = "RewardPreviewExcelConfigData.json", loadPriority = LoadPriority.HIGH)
|
||||
public class RewardPreviewData extends GameResource {
|
||||
private int id;
|
||||
private ItemParamStringData[] previewItems;
|
||||
private ItemParamData[] previewItemsArray;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private ItemParamStringData[] previewItems;
|
||||
private ItemParamData[] previewItemsArray;
|
||||
|
||||
public ItemParamData[] getPreviewItems() {
|
||||
return previewItemsArray;
|
||||
}
|
||||
public ItemParamData[] getPreviewItems() {
|
||||
return previewItemsArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
if (this.previewItems != null && this.previewItems.length > 0) {
|
||||
this.previewItemsArray = Arrays.stream(this.previewItems)
|
||||
.filter(d -> d.getId() > 0 && d.getCount() != null && !d.getCount().isEmpty())
|
||||
.map(ItemParamStringData::toItemParamData)
|
||||
.toArray(size -> new ItemParamData[size]);
|
||||
} else {
|
||||
this.previewItemsArray = new ItemParamData[0];
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onLoad() {
|
||||
if (this.previewItems != null && this.previewItems.length > 0) {
|
||||
this.previewItemsArray = Arrays.stream(this.previewItems)
|
||||
.filter(d -> d.getId() > 0 && d.getCount() != null && !d.getCount().isEmpty())
|
||||
.map(ItemParamStringData::toItemParamData)
|
||||
.toArray(size -> new ItemParamData[size]);
|
||||
} else {
|
||||
this.previewItemsArray = new ItemParamData[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,24 @@
|
||||
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.ResourceType;
|
||||
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "SceneExcelConfigData.json")
|
||||
@Getter
|
||||
public class SceneData extends GameResource {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private int id;
|
||||
private SceneType type;
|
||||
@SerializedName("type")
|
||||
private SceneType sceneType;
|
||||
private String scriptData;
|
||||
@Getter private String levelEntityConfig;
|
||||
@Getter private List<Integer> specifiedAvatarList;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public SceneType getSceneType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getScriptData() {
|
||||
return scriptData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package emu.grasscutter.data.excels;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = "TowerFloorExcelConfigData.json")
|
||||
@Getter
|
||||
public class TowerFloorData extends GameResource {
|
||||
|
||||
private int floorId;
|
||||
private int floorIndex;
|
||||
private int levelGroupId;
|
||||
@ -17,33 +18,4 @@ public class TowerFloorData extends GameResource {
|
||||
public int getId() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package emu.grasscutter.database;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public static <T> Stream<T> getByGameClass(Class<T> classType) {
|
||||
return DatabaseManager.getGameDatastore().find(classType).stream();
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public static List<Player> getAllPlayers() {
|
||||
return DatabaseManager.getGameDatastore().find(Player.class).stream().toList();
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ public class Avatar {
|
||||
private float currentEnergy;
|
||||
|
||||
@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 Set<String> extraAbilityEmbryos;
|
||||
|
||||
@ -96,12 +96,12 @@ public class Avatar {
|
||||
@Getter @Setter private int fromParentQuestId = 0;
|
||||
// so far no outer class or prop value has information of this, but from packet i sniff
|
||||
// 1 = normal, 2 = trial avatar
|
||||
@Getter @Setter private int avatarType = 1;
|
||||
@Getter @Setter private int avatarType = 1;
|
||||
|
||||
@Deprecated // Do not use. Morhpia only!
|
||||
public Avatar() {
|
||||
this.equips = new Int2ObjectOpenHashMap<>();
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.fightProperties = new Int2FloatOpenHashMap();
|
||||
this.fightPropOverrides = new Int2FloatOpenHashMap();
|
||||
this.extraAbilityEmbryos = new HashSet<>();
|
||||
this.fetters = new ArrayList<>(); // TODO Move to avatar
|
||||
@ -293,10 +293,6 @@ public class Avatar {
|
||||
}
|
||||
}
|
||||
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return fightProp;
|
||||
}
|
||||
|
||||
public void setFightProperty(FightProperty prop, float value) {
|
||||
this.getFightProperties().put(prop.getId(), value);
|
||||
}
|
||||
@ -416,9 +412,9 @@ public class Avatar {
|
||||
|
||||
public void recalcStats(boolean forceSendAbilityChange) {
|
||||
// Setup
|
||||
AvatarData data = this.getAvatarData();
|
||||
AvatarPromoteData promoteData = GameData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel());
|
||||
Int2IntOpenHashMap setMap = new Int2IntOpenHashMap();
|
||||
var data = this.getAvatarData();
|
||||
var promoteData = GameData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel());
|
||||
var setMap = new Int2IntOpenHashMap();
|
||||
|
||||
// Extra ability embryos
|
||||
Set<String> prevExtraAbilityEmbryos = this.getExtraAbilityEmbryos();
|
||||
@ -596,21 +592,11 @@ public class Avatar {
|
||||
// Add any skill strings from this constellation
|
||||
|
||||
// Set % stats
|
||||
this.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_MAX_HP,
|
||||
(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)
|
||||
);
|
||||
FightProperty.forEachCompoundProperty(c -> this.setFightProperty(c.getResult(),
|
||||
this.getFightProperty(c.getFlat()) + (this.getFightProperty(c.getBase()) * (1f + this.getFightProperty(c.getPercent())))));
|
||||
|
||||
// Reapply all overrides
|
||||
this.fightProp.putAll(this.fightPropOverrides);
|
||||
this.fightProperties.putAll(this.fightPropOverrides);
|
||||
|
||||
// Set current hp
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
|
||||
@ -978,7 +964,7 @@ public class Avatar {
|
||||
weapon.setPromoteLevel(0);
|
||||
getEquips().put(weapon.getEquipSlot(), weapon);
|
||||
|
||||
int trialAvatarTemplateLevel = trialAvatarLevel <= 9 ? 1 :
|
||||
int trialAvatarTemplateLevel = trialAvatarLevel <= 9 ? 1 :
|
||||
(int) (Math.floor(trialAvatarLevel / 10) * 10); // round trial level to fit template levels
|
||||
|
||||
TrialAvatarTemplateData templateData = GameData.getTrialAvatarTemplateDataMap().get(trialAvatarTemplateLevel);
|
||||
@ -1019,7 +1005,7 @@ public class Avatar {
|
||||
if (item.getItemData().getEquipType() == EquipType.EQUIP_WEAPON && getPlayer().getWorld() != null) {
|
||||
item.setWeaponEntityId(this.getPlayer().getWorld().getNextEntityId(EntityIdType.WEAPON));
|
||||
getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(this, item));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1045,7 +1031,7 @@ public class Avatar {
|
||||
trialAvatar.addTrialEquipList(itemCount, item.toProto());
|
||||
itemCount++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return trialAvatar.build();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -21,7 +21,6 @@ import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason;
|
||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
||||
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.PropChangeReasonOuterClass.PropChangeReason;
|
||||
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.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
|
||||
public class EntityAvatar extends GameEntity {
|
||||
private final Avatar avatar;
|
||||
@Getter private final Avatar avatar;
|
||||
|
||||
private PlayerDieType killedType;
|
||||
private int killedBy;
|
||||
@Getter private PlayerDieType killedType;
|
||||
@Getter private int killedBy;
|
||||
|
||||
public EntityAvatar(Avatar avatar) {
|
||||
this(null, avatar);
|
||||
}
|
||||
|
||||
public EntityAvatar(Scene scene, Avatar avatar) {
|
||||
super(scene);
|
||||
this.avatar = avatar;
|
||||
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();
|
||||
if (weapon != null) {
|
||||
@ -59,19 +63,13 @@ public class EntityAvatar extends GameEntity {
|
||||
}
|
||||
}
|
||||
|
||||
public EntityAvatar(Avatar avatar) {
|
||||
super(null);
|
||||
this.avatar = avatar;
|
||||
this.avatar.setCurrentEnergy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEntityTypeId() {
|
||||
return getAvatar().getAvatarId();
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return avatar.getPlayer();
|
||||
return this.avatar.getPlayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -84,25 +82,13 @@ public class EntityAvatar extends GameEntity {
|
||||
return getPlayer().getRotation();
|
||||
}
|
||||
|
||||
public Avatar getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public int getKilledBy() {
|
||||
return killedBy;
|
||||
}
|
||||
|
||||
public PlayerDieType getKilledType() {
|
||||
return killedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
public Int2FloatMap getFightProperties() {
|
||||
return getAvatar().getFightProperties();
|
||||
}
|
||||
|
||||
@ -150,11 +136,8 @@ public class EntityAvatar extends GameEntity {
|
||||
|
||||
public void clearEnergy(ChangeEnergyReason reason) {
|
||||
// Fight props.
|
||||
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
||||
|
||||
// Get max energy.
|
||||
float maxEnergy = this.avatar.getFightProperty(maxEnergyProp);
|
||||
val curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||
|
||||
// Set energy to zero.
|
||||
this.avatar.setCurrentEnergy(curEnergyProp, 0);
|
||||
@ -163,7 +146,7 @@ public class EntityAvatar extends GameEntity {
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +154,7 @@ public class EntityAvatar extends GameEntity {
|
||||
public boolean addEnergy(float amount) {
|
||||
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||
if (curEnergy == amount){
|
||||
if (curEnergy == amount) {
|
||||
return false;
|
||||
}
|
||||
this.getAvatar().setCurrentEnergy(curEnergyProp, amount);
|
||||
@ -182,21 +165,19 @@ public class EntityAvatar extends GameEntity {
|
||||
public void addEnergy(float amount, PropChangeReason reason) {
|
||||
this.addEnergy(amount, reason, false);
|
||||
}
|
||||
|
||||
|
||||
public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) {
|
||||
// Get current and maximum energy for this avatar.
|
||||
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
||||
val elementType = this.getAvatar().getSkillDepot().getElementType();
|
||||
val curEnergyProp = elementType.getCurEnergyProp();
|
||||
val maxEnergyProp = elementType.getMaxEnergyProp();
|
||||
|
||||
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||
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.
|
||||
if (!isFlat) {
|
||||
amount *= energyRecharge;
|
||||
amount *= this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY);
|
||||
}
|
||||
|
||||
// Determine the new energy value.
|
||||
@ -206,8 +187,8 @@ public class EntityAvatar extends GameEntity {
|
||||
if (newEnergy != curEnergy) {
|
||||
this.avatar.setCurrentEnergy(curEnergyProp, newEnergy);
|
||||
|
||||
// I only see EntityFightPropUpdataNotify being sent by the official server, and without any prop reason,
|
||||
// not sure how that differs to this
|
||||
// I only see EntityFightPropUpdataNotify being sent by the official server, and without any prop reason,
|
||||
// not sure how that differs to this
|
||||
this.getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp));
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, reason));
|
||||
}
|
||||
@ -217,20 +198,20 @@ public class EntityAvatar extends GameEntity {
|
||||
val avatar = this.getAvatar();
|
||||
val player = this.getPlayer();
|
||||
SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder()
|
||||
.setUid(player.getUid())
|
||||
.setAvatarId(avatar.getAvatarId())
|
||||
.setGuid(avatar.getGuid())
|
||||
.setPeerId(player.getPeerId())
|
||||
.addAllTalentIdList(avatar.getTalentIdList())
|
||||
.setCoreProudSkillLevel(avatar.getCoreProudSkillLevel())
|
||||
.putAllSkillLevelMap(avatar.getSkillLevelMap())
|
||||
.setSkillDepotId(avatar.getSkillDepotId())
|
||||
.addAllInherentProudSkillList(avatar.getProudSkillList())
|
||||
.putAllProudSkillExtraLevelMap(avatar.getProudSkillBonusMap())
|
||||
.addAllTeamResonanceList(player.getTeamManager().getTeamResonances())
|
||||
.setWearingFlycloakId(avatar.getFlyCloak())
|
||||
.setCostumeId(avatar.getCostume())
|
||||
.setBornTime(avatar.getBornTime());
|
||||
.setUid(player.getUid())
|
||||
.setAvatarId(avatar.getAvatarId())
|
||||
.setGuid(avatar.getGuid())
|
||||
.setPeerId(player.getPeerId())
|
||||
.addAllTalentIdList(avatar.getTalentIdList())
|
||||
.setCoreProudSkillLevel(avatar.getCoreProudSkillLevel())
|
||||
.putAllSkillLevelMap(avatar.getSkillLevelMap())
|
||||
.setSkillDepotId(avatar.getSkillDepotId())
|
||||
.addAllInherentProudSkillList(avatar.getProudSkillList())
|
||||
.putAllProudSkillExtraLevelMap(avatar.getProudSkillBonusMap())
|
||||
.addAllTeamResonanceList(player.getTeamManager().getTeamResonances())
|
||||
.setWearingFlycloakId(avatar.getFlyCloak())
|
||||
.setCostumeId(avatar.getCostume())
|
||||
.setBornTime(avatar.getBornTime());
|
||||
|
||||
for (GameItem item : avatar.getEquips().values()) {
|
||||
if (item.getItemData().getEquipType() == EquipType.EQUIP_WEAPON) {
|
||||
@ -247,21 +228,21 @@ public class EntityAvatar extends GameEntity {
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_AVATAR)
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs())
|
||||
.setLastMoveReliableSeq(this.getLastMoveReliableSeq())
|
||||
.setLifeState(this.getLifeState().getValue());
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_AVATAR)
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs())
|
||||
.setLastMoveReliableSeq(this.getLastMoveReliableSeq())
|
||||
.setLifeState(this.getLifeState().getValue());
|
||||
|
||||
if (this.getScene() != null) {
|
||||
entityInfo.setMotionInfo(this.getMotionInfo());
|
||||
@ -270,9 +251,9 @@ public class EntityAvatar extends GameEntity {
|
||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel()))
|
||||
.build();
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel()))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
entityInfo.setAvatar(this.getSceneAvatarInfo());
|
||||
@ -289,29 +270,29 @@ public class EntityAvatar extends GameEntity {
|
||||
if (data.getAbilities() != null) {
|
||||
for (int id : data.getAbilities()) {
|
||||
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(id)
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(id)
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||
}
|
||||
}
|
||||
// Add default abilities
|
||||
for (int id : GameConstants.DEFAULT_ABILITY_HASHES) {
|
||||
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(id)
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(id)
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||
}
|
||||
// Add team resonances
|
||||
for (int id : this.getPlayer().getTeamManager().getTeamResonancesConfig()) {
|
||||
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(id)
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(id)
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||
}
|
||||
// Add skill depot abilities
|
||||
@ -319,10 +300,10 @@ public class EntityAvatar extends GameEntity {
|
||||
if (skillDepot != null && skillDepot.getAbilities() != null) {
|
||||
for (int id : skillDepot.getAbilities()) {
|
||||
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(id)
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(id)
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||
}
|
||||
}
|
||||
@ -330,10 +311,10 @@ public class EntityAvatar extends GameEntity {
|
||||
if (this.getAvatar().getExtraAbilityEmbryos().size() > 0) {
|
||||
for (String skill : this.getAvatar().getExtraAbilityEmbryos()) {
|
||||
AbilityEmbryo emb = AbilityEmbryo.newBuilder()
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(Utils.abilityHash(skill))
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
.setAbilityId(++embryoId)
|
||||
.setAbilityNameHash(Utils.abilityHash(skill))
|
||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||
.build();
|
||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||
}
|
||||
}
|
||||
@ -345,15 +326,18 @@ public class EntityAvatar extends GameEntity {
|
||||
/**
|
||||
* Move this entity to a new position.
|
||||
* Additionally invoke player move event.
|
||||
*
|
||||
* @param newPosition The new position.
|
||||
* @param rotation The new rotation.
|
||||
* @param rotation The new rotation.
|
||||
*/
|
||||
@Override public void move(Position newPosition, Position rotation) {
|
||||
@Override
|
||||
public void move(Position newPosition, Position rotation) {
|
||||
// Invoke player move event.
|
||||
PlayerMoveEvent event = new PlayerMoveEvent(
|
||||
this.getPlayer(), PlayerMoveEvent.MoveType.PLAYER,
|
||||
this.getPosition(), newPosition
|
||||
); event.call();
|
||||
);
|
||||
event.call();
|
||||
|
||||
// Set position and rotation.
|
||||
super.move(event.getDestination(), rotation);
|
||||
|
@ -6,13 +6,25 @@ import emu.grasscutter.game.quest.enums.QuestContent;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.event.entity.EntityDamageEvent;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import lombok.Getter;
|
||||
|
||||
import static emu.grasscutter.scripts.constants.EventType.EVENT_SPECIFIC_GADGET_HP_CHANGE;
|
||||
|
||||
public abstract class EntityBaseGadget extends GameEntity {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
protected final Position position;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
protected final Position rotation;
|
||||
|
||||
public EntityBaseGadget(Scene scene) {
|
||||
this(scene, null, null);
|
||||
}
|
||||
|
||||
public EntityBaseGadget(Scene scene, Position position, Position rotation) {
|
||||
super(scene);
|
||||
this.position = position != null ? position.clone() : new Position();
|
||||
this.rotation = rotation != null ? rotation.clone() : new Position();
|
||||
}
|
||||
|
||||
public abstract int getGadgetId();
|
||||
|
@ -19,30 +19,28 @@ import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.utils.Position;
|
||||
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 {
|
||||
private final Player owner;
|
||||
@Getter private final Player owner;
|
||||
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private final int gadgetId;
|
||||
|
||||
private int configId;
|
||||
private int campId;
|
||||
private int campType;
|
||||
private int ownerEntityId;
|
||||
private int targetEntityId;
|
||||
private boolean asyncLoad;
|
||||
@Getter private final int campId;
|
||||
@Getter private final int campType;
|
||||
@Getter private final int ownerEntityId;
|
||||
@Getter private final int targetEntityId;
|
||||
@Getter private final boolean asyncLoad;
|
||||
|
||||
private int originalOwnerEntityId;
|
||||
@Getter private final int originalOwnerEntityId;
|
||||
|
||||
public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) {
|
||||
super(scene);
|
||||
super(scene, new Position(notify.getInitPos()), new Position(notify.getInitEulerAngles()));
|
||||
this.owner = player;
|
||||
this.id = notify.getEntityId();
|
||||
this.pos = new Position(notify.getInitPos());
|
||||
this.rot = new Position(notify.getInitEulerAngles());
|
||||
this.configId = notify.getConfigId();
|
||||
this.gadgetId = notify.getConfigId();
|
||||
this.campId = notify.getCampId();
|
||||
this.campType = notify.getCampType();
|
||||
this.ownerEntityId = notify.getPropOwnerEntityId();
|
||||
@ -52,107 +50,60 @@ public class EntityClientGadget extends EntityBaseGadget {
|
||||
GameEntity owner = scene.getEntityById(this.ownerEntityId);
|
||||
if (owner instanceof EntityClientGadget ownerGadget) {
|
||||
this.originalOwnerEntityId = ownerGadget.getOriginalOwnerEntityId();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.originalOwnerEntityId = this.ownerEntityId;
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
public void onDeath(int killerId) {
|
||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
// TODO Auto-generated method stub
|
||||
public Int2FloatMap getFightProperties() {
|
||||
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
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget = ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder()
|
||||
.setCampId(this.getCampId())
|
||||
.setCampType(this.getCampType())
|
||||
.setOwnerEntityId(this.getOwnerEntityId())
|
||||
.setTargetEntityId(this.getTargetEntityId())
|
||||
.setAsyncLoad(this.isAsyncLoad())
|
||||
.build();
|
||||
.setCampId(this.getCampId())
|
||||
.setCampType(this.getCampType())
|
||||
.setOwnerEntityId(this.getOwnerEntityId())
|
||||
.setTargetEntityId(this.getTargetEntityId())
|
||||
.setAsyncLoad(this.isAsyncLoad())
|
||||
.build();
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setOwnerEntityId(this.getOwnerEntityId())
|
||||
.setIsEnableInteract(true)
|
||||
.setClientGadget(clientGadget)
|
||||
.setPropOwnerEntityId(this.getOwnerEntityId())
|
||||
.setAuthorityPeerId(this.getOwner().getPeerId());
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setOwnerEntityId(this.getOwnerEntityId())
|
||||
.setIsEnableInteract(true)
|
||||
.setClientGadget(clientGadget)
|
||||
.setPropOwnerEntityId(this.getOwnerEntityId())
|
||||
.setAuthorityPeerId(this.getOwner().getPeerId());
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
|
||||
|
@ -7,7 +7,6 @@ import emu.grasscutter.game.entity.gadget.*;
|
||||
import emu.grasscutter.game.entity.gadget.platform.BaseRoute;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
@ -35,31 +34,34 @@ import emu.grasscutter.server.packet.send.PacketPlatformStopRouteNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneTimeNotify;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ToString(callSuper = true)
|
||||
public class EntityGadget extends EntityBaseGadget {
|
||||
private final GadgetData data;
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
@Getter private final GadgetData gadgetData;
|
||||
@Getter(onMethod = @__(@Override)) @Setter
|
||||
private int gadgetId;
|
||||
@Getter private final Position bornPos;
|
||||
@Getter private final Position bornRot;
|
||||
private int gadgetId;
|
||||
@Getter @Setter private GameEntity owner = null;
|
||||
@Getter @Setter private List<GameEntity> children = new ArrayList<>();
|
||||
|
||||
private int state;
|
||||
private int pointType;
|
||||
private GadgetContent content;
|
||||
private Int2FloatOpenHashMap fightProp;
|
||||
private SceneGadget metaGadget;
|
||||
@Getter @Setter private int state;
|
||||
@Getter @Setter private int pointType;
|
||||
@Getter private GadgetContent content;
|
||||
@Getter(onMethod = @__(@Override), lazy = true)
|
||||
private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
|
||||
@Getter @Setter private SceneGadget metaGadget;
|
||||
@Nullable @Getter
|
||||
private ConfigGadget configGadget;
|
||||
@Getter @Setter private BaseRoute routeConfig;
|
||||
@ -68,18 +70,26 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
@Getter @Setter private int startValue = 0; //Controller related, inited to zero
|
||||
@Getter @Setter private int ticksSinceChange;
|
||||
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||
this(scene, gadgetId, pos, null, null);
|
||||
}
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) {
|
||||
super(scene);
|
||||
this.data = GameData.getGadgetDataMap().get(gadgetId);
|
||||
if (data!=null && data.getJsonName()!=null) {
|
||||
this.configGadget = GameData.getGadgetConfigData().get(data.getJsonName());
|
||||
this(scene, gadgetId, pos, rot, null);
|
||||
}
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
|
||||
super(scene, pos, rot);
|
||||
this.gadgetData = GameData.getGadgetDataMap().get(gadgetId);
|
||||
if (gadgetData!=null && gadgetData.getJsonName()!=null) {
|
||||
this.configGadget = GameData.getGadgetConfigData().get(gadgetData.getJsonName());
|
||||
}
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.id = this.getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.gadgetId = gadgetId;
|
||||
this.pos = pos.clone();
|
||||
this.bornPos = this.pos.clone();
|
||||
this.rot = rot != null ? rot.clone() : new Position();
|
||||
this.bornRot = this.rot.clone();
|
||||
this.content = content;
|
||||
this.bornPos = this.getPosition().clone();
|
||||
this.bornRot = this.getRotation().clone();
|
||||
fillFightProps(configGadget);
|
||||
if(GameData.getGadgetMappingMap().containsKey(gadgetId)) {
|
||||
String controllerName = GameData.getGadgetMappingMap().get(gadgetId).getServerController();
|
||||
@ -87,45 +97,6 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
}
|
||||
}
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||
this(scene, gadgetId, pos, new Position());
|
||||
}
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
|
||||
this(scene, gadgetId, pos, rot);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void updateState(int state) {
|
||||
if(state == this.getState()) return; //Don't triggers events
|
||||
|
||||
@ -135,39 +106,18 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
getScene().getScriptManager().callEvent(new ScriptArgs(EventType.EVENT_GADGET_STATE_CHANGE, state, this.getConfigId()));
|
||||
}
|
||||
|
||||
public int getPointType() {
|
||||
return pointType;
|
||||
}
|
||||
|
||||
public void setPointType(int pointType) {
|
||||
this.pointType = pointType;
|
||||
}
|
||||
|
||||
public GadgetContent getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Deprecated // Dont use!
|
||||
@Deprecated(forRemoval = true) // Dont use!
|
||||
public void setContent(GadgetContent content) {
|
||||
this.content = this.content == null ? content : this.content;
|
||||
}
|
||||
|
||||
public SceneGadget getMetaGadget() {
|
||||
return metaGadget;
|
||||
}
|
||||
|
||||
public void setMetaGadget(SceneGadget metaGadget) {
|
||||
this.metaGadget = metaGadget;
|
||||
}
|
||||
|
||||
// TODO refactor
|
||||
public void buildContent() {
|
||||
if (getContent() != null || getGadgetData() == null || getGadgetData().getType() == null) {
|
||||
if (this.getContent() != null || this.getGadgetData() == null || this.getGadgetData().getType() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityType type = getGadgetData().getType();
|
||||
GadgetContent content = switch (type) {
|
||||
this.content = switch (this.getGadgetData().getType()) {
|
||||
case GatherPoint -> new GadgetGatherPoint(this);
|
||||
case GatherObject -> new GadgetGatherObject(this);
|
||||
case Worktop, SealGadget -> new GadgetWorktop(this);
|
||||
@ -176,14 +126,6 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
case Gadget -> new GadgetObject(this);
|
||||
default -> null;
|
||||
};
|
||||
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
if (this.fightProp == null) this.fightProp = new Int2FloatOpenHashMap();
|
||||
return this.fightProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -281,7 +223,7 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
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
|
||||
if (this.fightProp != null) {
|
||||
if (this.fightProperties != null) {
|
||||
addAllFightPropsToEntityInfo(entityInfo);
|
||||
}
|
||||
|
||||
|
@ -25,57 +25,33 @@ import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
||||
import emu.grasscutter.utils.Position;
|
||||
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 {
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
|
||||
private final GameItem item;
|
||||
private final long guid;
|
||||
|
||||
private final boolean share;
|
||||
@Getter private final GameItem item;
|
||||
@Getter private final long guid;
|
||||
@Getter private final boolean share;
|
||||
|
||||
public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) {
|
||||
super(scene);
|
||||
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;
|
||||
this(scene, player, itemData, pos, count, true);
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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) {
|
||||
super(scene);
|
||||
super(scene, pos, null);
|
||||
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 = share;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
private GameItem getItem() {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
public ItemData getItemData() {
|
||||
return this.getItem().getItemData();
|
||||
}
|
||||
|
||||
public long getGuid() {
|
||||
return guid;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.getItem().getCount();
|
||||
}
|
||||
@ -85,24 +61,7 @@ public class EntityItem extends EntityBaseGadget {
|
||||
return this.getItemData().getGadgetId();
|
||||
}
|
||||
|
||||
@Override
|
||||
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 public Int2FloatMap getFightProperties() {return null;}
|
||||
|
||||
@Override
|
||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||
|
@ -32,28 +32,32 @@ import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static emu.grasscutter.scripts.constants.EventType.EVENT_SPECIFIC_MONSTER_HP_CHANGE;
|
||||
|
||||
public class EntityMonster extends GameEntity {
|
||||
private final MonsterData monsterData;
|
||||
private final Int2FloatOpenHashMap fightProp;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private final Int2FloatOpenHashMap fightProperties;
|
||||
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
private final Position bornPos;
|
||||
private final int level;
|
||||
private int weaponEntityId;
|
||||
private int poseId;
|
||||
@Getter @Setter
|
||||
private int aiId=-1;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private final Position position;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private final Position rotation;
|
||||
@Getter private final MonsterData monsterData;
|
||||
@Getter private final Position bornPos;
|
||||
@Getter private final int level;
|
||||
@Getter private int weaponEntityId;
|
||||
@Getter @Setter private int poseId;
|
||||
@Getter @Setter private int aiId = -1;
|
||||
|
||||
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
|
||||
super(scene);
|
||||
this.id = getWorld().getNextEntityId(EntityIdType.MONSTER);
|
||||
this.monsterData = monsterData;
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position();
|
||||
this.fightProperties = new Int2FloatOpenHashMap();
|
||||
this.position = new Position(pos);
|
||||
this.rotation = new Position();
|
||||
this.bornPos = getPosition().clone();
|
||||
this.level = level;
|
||||
|
||||
@ -65,64 +69,24 @@ public class EntityMonster extends GameEntity {
|
||||
this.recalcStats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEntityTypeId() {
|
||||
return getMonsterId();
|
||||
}
|
||||
|
||||
public MonsterData getMonsterData() {
|
||||
return monsterData;
|
||||
}
|
||||
|
||||
public int getMonsterWeaponId() {
|
||||
return getMonsterData().getWeaponId();
|
||||
return this.getMonsterData().getWeaponId();
|
||||
}
|
||||
|
||||
private int getMonsterId() {
|
||||
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
|
||||
public boolean isAlive() {
|
||||
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
|
||||
}
|
||||
|
||||
public int getPoseId() {
|
||||
return poseId;
|
||||
}
|
||||
|
||||
public void setPoseId(int poseId) {
|
||||
this.poseId = poseId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||
EnvAnimalGatherConfigData gatherData = GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId());
|
||||
@ -171,34 +135,34 @@ public class EntityMonster extends GameEntity {
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
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
|
||||
if (getScene().getChallenge() != null) {
|
||||
getScene().getChallenge().onMonsterDeath(this);
|
||||
}
|
||||
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) {
|
||||
if (getScene().getScriptManager().getScriptMonsterSpawnService() != null) {
|
||||
getScene().getScriptManager().getScriptMonsterSpawnService().onMonsterDead(this);
|
||||
}
|
||||
challenge.ifPresent(c -> c.onMonsterDeath(this));
|
||||
|
||||
if (scriptManager.isInit() && this.getGroupId() > 0) {
|
||||
Optional.ofNullable(scriptManager.getScriptMonsterSpawnService()).ifPresent(s -> s.onMonsterDead(this));
|
||||
|
||||
// prevent spawn monster after success
|
||||
if (getScene().getChallenge() != null && getScene().getChallenge().inProgress()) {
|
||||
getScene().getScriptManager().callEvent(new ScriptArgs(EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()));
|
||||
}else if (getScene().getChallenge() == null) {
|
||||
getScene().getScriptManager().callEvent(new ScriptArgs(EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()));
|
||||
if (challenge.map(c -> c.inProgress()).orElse(true)) {
|
||||
scriptManager.callEvent(new ScriptArgs(EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()));
|
||||
} else if (getScene().getChallenge() == null) {
|
||||
scriptManager.callEvent(new ScriptArgs(EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()));
|
||||
}
|
||||
}
|
||||
// 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));
|
||||
|
||||
getScene().getPlayers().forEach(p -> p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_MONSTER_DIE, this.getMonsterId()));
|
||||
getScene().getPlayers().forEach(p -> p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_KILL_MONSTER, this.getMonsterId()));
|
||||
scene.getPlayers().forEach(p -> p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_MONSTER_DIE, this.getMonsterId()));
|
||||
scene.getPlayers().forEach(p -> p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_KILL_MONSTER, this.getMonsterId()));
|
||||
|
||||
getScene().triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_GROUP_MONSTER, this.getGroupId());
|
||||
getScene().triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_TYPE_MONSTER, this.getMonsterData().getType().getValue());
|
||||
getScene().triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER, this.getMonsterId());
|
||||
scene.triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_GROUP_MONSTER, this.getGroupId());
|
||||
scene.triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_TYPE_MONSTER, this.getMonsterData().getType().getValue());
|
||||
scene.triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER, this.getMonsterId());
|
||||
}
|
||||
|
||||
public void recalcStats() {
|
||||
@ -212,18 +176,7 @@ public class EntityMonster extends GameEntity {
|
||||
this.getFightProperties().clear();
|
||||
|
||||
// Base stats
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp());
|
||||
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());
|
||||
MonsterData.definedFightProperties.forEach(prop -> this.setFightProperty(prop, data.getFightProperty(prop)));
|
||||
|
||||
// Level curve
|
||||
MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel());
|
||||
@ -235,18 +188,8 @@ public class EntityMonster extends GameEntity {
|
||||
}
|
||||
|
||||
// Set % stats
|
||||
this.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_MAX_HP,
|
||||
(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)
|
||||
);
|
||||
FightProperty.forEachCompoundProperty(c -> this.setFightProperty(c.getResult(),
|
||||
this.getFightProperty(c.getFlat()) + (this.getFightProperty(c.getBase()) * (1f + this.getFightProperty(c.getPercent())))));
|
||||
|
||||
// Set current hp
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
|
||||
@ -254,41 +197,40 @@ public class EntityMonster extends GameEntity {
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto()))
|
||||
.setBornPos(this.getBornPos().toProto())
|
||||
.build();
|
||||
var authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto()))
|
||||
.setBornPos(this.getBornPos().toProto())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
|
||||
.setMotionInfo(this.getMotionInfo())
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(this.getLifeState().getValue());
|
||||
var entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
|
||||
.setMotionInfo(this.getMotionInfo())
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(this.getLifeState().getValue());
|
||||
|
||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel()))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
entityInfo.addPropList(PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel()))
|
||||
.build());
|
||||
|
||||
SceneMonsterInfo.Builder monsterInfo = SceneMonsterInfo.newBuilder()
|
||||
.setMonsterId(getMonsterId())
|
||||
.setGroupId(this.getGroupId())
|
||||
.setConfigId(this.getConfigId())
|
||||
.addAllAffixList(getMonsterData().getAffix())
|
||||
.setAuthorityPeerId(getWorld().getHostPeerId())
|
||||
.setPoseId(this.getPoseId())
|
||||
.setBlockId(getScene().getId())
|
||||
.setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT);
|
||||
var monsterInfo = SceneMonsterInfo.newBuilder()
|
||||
.setMonsterId(getMonsterId())
|
||||
.setGroupId(this.getGroupId())
|
||||
.setConfigId(this.getConfigId())
|
||||
.addAllAffixList(getMonsterData().getAffix())
|
||||
.setAuthorityPeerId(getWorld().getHostPeerId())
|
||||
.setPoseId(this.getPoseId())
|
||||
.setBlockId(getScene().getId())
|
||||
.setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT);
|
||||
|
||||
if (getMonsterData().getDescribeData() != null){
|
||||
if (getMonsterData().getDescribeData() != null) {
|
||||
monsterInfo.setTitleId(getMonsterData().getDescribeData().getTitleId())
|
||||
.setSpecialNameId(getMonsterData().getSpecialNameId());
|
||||
|
||||
@ -296,14 +238,14 @@ public class EntityMonster extends GameEntity {
|
||||
|
||||
if (this.getMonsterWeaponId() > 0) {
|
||||
SceneWeaponInfo weaponInfo = SceneWeaponInfo.newBuilder()
|
||||
.setEntityId(this.weaponEntityId)
|
||||
.setGadgetId(this.getMonsterWeaponId())
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.build();
|
||||
.setEntityId(this.weaponEntityId)
|
||||
.setGadgetId(this.getMonsterWeaponId())
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.build();
|
||||
|
||||
monsterInfo.addWeaponList(weaponInfo);
|
||||
}
|
||||
if (this.aiId!=-1) {
|
||||
if (this.aiId != -1) {
|
||||
monsterInfo.setAiConfigId(aiId);
|
||||
}
|
||||
|
||||
|
@ -5,14 +5,16 @@ import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.*;
|
||||
import emu.grasscutter.scripts.data.SceneNPC;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityNPC extends GameEntity{
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import lombok.Getter;
|
||||
|
||||
public class EntityNPC extends GameEntity {
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private final Position position;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private final Position rotation;
|
||||
private final SceneNPC metaNpc;
|
||||
private final int suiteId;
|
||||
@Getter private final int suiteId;
|
||||
|
||||
public EntityNPC(Scene scene, SceneNPC metaNPC, int blockId, int suiteId) {
|
||||
super(scene);
|
||||
@ -33,53 +35,39 @@ public class EntityNPC extends GameEntity{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
public Int2FloatMap getFightProperties() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public int getSuiteId() {
|
||||
return suiteId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
||||
|
||||
EntityAuthorityInfoOuterClass.EntityAuthorityInfo authority = EntityAuthorityInfoOuterClass.EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfoOuterClass.SceneEntityAiInfo.newBuilder()
|
||||
.setIsAiOpen(true)
|
||||
.setBornPos(getPosition().toProto()))
|
||||
.setBornPos(getPosition().toProto())
|
||||
.build();
|
||||
EntityAuthorityInfoOuterClass.EntityAuthorityInfo authority = EntityAuthorityInfoOuterClass.EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfoOuterClass.SceneEntityAiInfo.newBuilder()
|
||||
.setIsAiOpen(true)
|
||||
.setBornPos(getPosition().toProto()))
|
||||
.setBornPos(getPosition().toProto())
|
||||
.build();
|
||||
|
||||
SceneEntityInfoOuterClass.SceneEntityInfo.Builder entityInfo = SceneEntityInfoOuterClass.SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityTypeOuterClass.ProtEntityType.PROT_ENTITY_TYPE_NPC)
|
||||
.setMotionInfo(MotionInfoOuterClass.MotionInfo.newBuilder()
|
||||
.setPos(getPosition().toProto())
|
||||
.setRot(getRotation().toProto())
|
||||
.setSpeed(VectorOuterClass.Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientDataOuterClass.EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityTypeOuterClass.ProtEntityType.PROT_ENTITY_TYPE_NPC)
|
||||
.setMotionInfo(MotionInfoOuterClass.MotionInfo.newBuilder()
|
||||
.setPos(getPosition().toProto())
|
||||
.setRot(getRotation().toProto())
|
||||
.setSpeed(VectorOuterClass.Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientDataOuterClass.EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
|
||||
entityInfo.setNpc(SceneNpcInfoOuterClass.SceneNpcInfo.newBuilder()
|
||||
.setNpcId(metaNpc.npc_id)
|
||||
.setBlockId(getBlockId())
|
||||
.build());
|
||||
.setNpcId(metaNpc.npc_id)
|
||||
.setBlockId(getBlockId())
|
||||
.build());
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass;
|
||||
import emu.grasscutter.scripts.data.SceneRegion;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Set;
|
||||
@ -62,20 +62,11 @@ public class EntityRegion extends GameEntity{
|
||||
}
|
||||
public boolean entityLeave() {return this.entityLeave;}
|
||||
public void resetEntityLeave() {this.entityLeave = false;}
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return null;
|
||||
}
|
||||
@Override public Int2FloatMap getFightProperties() {return null;}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
@Override public Position getPosition() {return position;}
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return null;
|
||||
}
|
||||
@Override public Position getRotation() {return null;}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
||||
|
@ -12,7 +12,6 @@ import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncState
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||
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.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
@ -36,25 +35,21 @@ import java.util.List;
|
||||
public class EntityVehicle extends EntityBaseGadget {
|
||||
|
||||
@Getter private final Player owner;
|
||||
private final Int2FloatMap fightProp;
|
||||
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
@Getter(onMethod = @__(@Override))
|
||||
private final Int2FloatMap fightProperties;
|
||||
|
||||
@Getter private final int pointId;
|
||||
@Getter private final int gadgetId;
|
||||
|
||||
@Getter @Setter private float curStamina;
|
||||
@Getter private List<VehicleMember> vehicleMembers;
|
||||
@Getter private final List<VehicleMember> vehicleMembers;
|
||||
@Nullable @Getter private ConfigGadget configGadget;
|
||||
|
||||
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
||||
super(scene);
|
||||
super(scene, pos, rot);
|
||||
this.owner = player;
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position(rot);
|
||||
this.fightProperties = new Int2FloatOpenHashMap();
|
||||
this.gadgetId = gadgetId;
|
||||
this.pointId = pointId;
|
||||
this.curStamina = 240; // might be in configGadget.GCALKECLLLP.JBAKBEFIMBN.ANBMPHPOALP
|
||||
@ -74,53 +69,40 @@ public class EntityVehicle extends EntityBaseGadget {
|
||||
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
|
||||
public SceneEntityInfo toProto() {
|
||||
|
||||
VehicleInfo vehicle = VehicleInfo.newBuilder()
|
||||
.setOwnerUid(this.owner.getUid())
|
||||
.setCurStamina(getCurStamina())
|
||||
.build();
|
||||
.setOwnerUid(this.owner.getUid())
|
||||
.setCurStamina(getCurStamina())
|
||||
.build();
|
||||
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto()))
|
||||
.setBornPos(getPosition().toProto())
|
||||
.build();
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto()))
|
||||
.setBornPos(getPosition().toProto())
|
||||
.build();
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setAuthorityPeerId(this.getOwner().getPeerId())
|
||||
.setIsEnableInteract(true)
|
||||
.setVehicleInfo(vehicle);
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setAuthorityPeerId(this.getOwner().getPeerId())
|
||||
.setIsEnableInteract(true)
|
||||
.setVehicleInfo(vehicle);
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setGadget(gadgetInfo)
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setGadget(gadgetInfo)
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
|
||||
.build();
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
|
||||
.build();
|
||||
|
||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
||||
entityInfo.addPropList(pair);
|
||||
|
@ -27,15 +27,15 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public abstract class GameEntity {
|
||||
@Getter protected int id;
|
||||
@Getter private final Scene scene;
|
||||
@Getter protected int id;
|
||||
@Getter @Setter private SpawnDataEntry spawnEntry;
|
||||
|
||||
@Getter @Setter private int blockId;
|
||||
@Getter @Setter private int configId;
|
||||
@Getter @Setter private int groupId;
|
||||
|
||||
private MotionState moveState;
|
||||
@Getter @Setter private MotionState motionState;
|
||||
@Getter @Setter private int lastMoveSceneTimeMs;
|
||||
@Getter @Setter private int lastMoveReliableSeq;
|
||||
|
||||
@ -51,7 +51,7 @@ public abstract class GameEntity {
|
||||
|
||||
public GameEntity(Scene scene) {
|
||||
this.scene = scene;
|
||||
this.moveState = MotionState.MOTION_STATE_NONE;
|
||||
this.motionState = MotionState.MOTION_STATE_NONE;
|
||||
}
|
||||
|
||||
public int getEntityType() {
|
||||
@ -92,14 +92,6 @@ public abstract class GameEntity {
|
||||
|
||||
public abstract Position getRotation();
|
||||
|
||||
public MotionState getMotionState() {
|
||||
return moveState;
|
||||
}
|
||||
|
||||
public void setMotionState(MotionState moveState) {
|
||||
this.moveState = moveState;
|
||||
}
|
||||
|
||||
public void setFightProperty(FightProperty prop, float value) {
|
||||
this.getFightProperties().put(prop.getId(), value);
|
||||
}
|
||||
@ -129,11 +121,11 @@ public abstract class GameEntity {
|
||||
|
||||
protected MotionInfo getMotionInfo() {
|
||||
MotionInfo proto = MotionInfo.newBuilder()
|
||||
.setPos(this.getPosition().toProto())
|
||||
.setRot(this.getRotation().toProto())
|
||||
.setSpeed(Vector.newBuilder())
|
||||
.setState(this.getMotionState())
|
||||
.build();
|
||||
.setPos(this.getPosition().toProto())
|
||||
.setRot(this.getRotation().toProto())
|
||||
.setSpeed(Vector.newBuilder())
|
||||
.setState(this.getMotionState())
|
||||
.build();
|
||||
|
||||
return proto;
|
||||
}
|
||||
@ -204,14 +196,15 @@ public abstract class GameEntity {
|
||||
}
|
||||
}
|
||||
|
||||
public void callLuaHPEvent(EntityDamageEvent event){
|
||||
if(entityController != null){
|
||||
public void callLuaHPEvent(EntityDamageEvent event) {
|
||||
if (entityController != null) {
|
||||
entityController.onBeHurt(this, event.getAttackElementType(), true);//todo is host handling
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move this entity to a new position.
|
||||
*
|
||||
* @param position The new position.
|
||||
* @param rotation The new rotation.
|
||||
*/
|
||||
@ -223,7 +216,8 @@ public abstract class GameEntity {
|
||||
|
||||
/**
|
||||
* Called when a player interacts with this entity
|
||||
* @param player Player that is interacting with this entity
|
||||
*
|
||||
* @param player Player that is interacting with this entity
|
||||
* @param interactReq Interact request protobuf data
|
||||
*/
|
||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||
@ -241,14 +235,14 @@ public abstract class GameEntity {
|
||||
|
||||
}
|
||||
|
||||
public void onTick(int sceneTime){
|
||||
if(entityController!=null){
|
||||
public void onTick(int sceneTime) {
|
||||
if (entityController != null) {
|
||||
entityController.onTimer(this, sceneTime);
|
||||
}
|
||||
}
|
||||
|
||||
public int onClientExecuteRequest(int param1, int param2, int param3){
|
||||
if(entityController != null){
|
||||
public int onClientExecuteRequest(int param1, int param2, int param3) {
|
||||
if (entityController != null) {
|
||||
return entityController.onClientExecuteRequest(this, param1, param2, param3);
|
||||
}
|
||||
return 0;
|
||||
@ -256,6 +250,7 @@ public abstract class GameEntity {
|
||||
|
||||
/**
|
||||
* Called when this entity dies
|
||||
*
|
||||
* @param killerId Entity id of the entity that killed this entity
|
||||
*/
|
||||
public void onDeath(int killerId) {
|
||||
@ -263,7 +258,7 @@ public abstract class GameEntity {
|
||||
EntityDeathEvent event = new EntityDeathEvent(this, killerId);
|
||||
event.call();
|
||||
|
||||
if(entityController != null){
|
||||
if (entityController != null) {
|
||||
entityController.onDie(this, getLastAttackType());
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.game.gacha;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
|
||||
@ -10,65 +11,123 @@ import emu.grasscutter.utils.Utils;
|
||||
import lombok.Getter;
|
||||
|
||||
public class GachaBanner {
|
||||
@Getter private int gachaType;
|
||||
@Getter private int scheduleId;
|
||||
@Getter private int gachaType = -1;
|
||||
@Getter int scheduleId = -1;
|
||||
@Getter int sortId = -1;
|
||||
@Getter private String prefabPath;
|
||||
private String previewPrefabPath;
|
||||
@Getter private String previewPrefabPath;
|
||||
@Getter private String titlePath;
|
||||
private int costItemId = 0;
|
||||
private int costItemAmount = 1;
|
||||
private int costItemId10 = 0;
|
||||
private int costItemAmount10 = 10;
|
||||
@Getter private int beginTime;
|
||||
@Getter private int endTime;
|
||||
@Getter private int sortId;
|
||||
@Getter private int beginTime = 0;
|
||||
@Getter private int endTime = 1924992000;
|
||||
@Getter private int gachaTimesLimit = Integer.MAX_VALUE;
|
||||
private int[] rateUpItems4 = {};
|
||||
private int[] rateUpItems5 = {};
|
||||
@Getter private int[] fallbackItems3 = {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304};
|
||||
@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 int[] rateUpItems4 = {};
|
||||
@Getter private int[] rateUpItems5 = {};
|
||||
// This now handles default values for the fields below
|
||||
@Getter private BannerType bannerType = BannerType.STANDARD;
|
||||
|
||||
// Kinda wanna deprecate these but they're in people's configs
|
||||
private int[] rateUpItems1 = {};
|
||||
private int[] rateUpItems2 = {};
|
||||
private int eventChance = -1;
|
||||
private int costItem = 0;
|
||||
// Constants used by the BannerType enum
|
||||
static final int[][] DEFAULT_WEIGHTS_4 = {{1,510}, {8,510}, {10,10000}};
|
||||
static final int[][] DEFAULT_WEIGHTS_4_WEAPON = {{1, 600}, {7, 600}, {8, 6600}, {10, 12600}};
|
||||
static final int[][] DEFAULT_WEIGHTS_5 = {{1,75}, {73,150}, {90,10000}};
|
||||
static final int[][] DEFAULT_WEIGHTS_5_CHARACTER = {{1,80}, {73,80}, {90,10000}};
|
||||
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;
|
||||
|
||||
public String getPreviewPrefabPath() {
|
||||
if (this.previewPrefabPath != null && !this.previewPrefabPath.isEmpty())
|
||||
return this.previewPrefabPath;
|
||||
return "UI_Tab_" + this.prefabPath;
|
||||
// Deprecated fields that were tolerated in early May 2022 but have apparently still being circulating in new custom configs
|
||||
// For now, throw up big scary errors on load telling people that they will be banned outright in a future version
|
||||
@Deprecated private int[] rateUpItems1 = {};
|
||||
@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) {
|
||||
return switch (numRolls) {
|
||||
case 10 -> new ItemParamData((costItemId10 > 0) ? costItemId10 : getCostItem(), costItemAmount10);
|
||||
default -> new ItemParamData(getCostItem(), costItemAmount * numRolls);
|
||||
case 10 -> new ItemParamData(costItemId10, costItemAmount10);
|
||||
default -> new ItemParamData(costItemId, costItemAmount * numRolls);
|
||||
};
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int getCostItem() {
|
||||
return (costItem > 0) ? costItem : costItemId;
|
||||
}
|
||||
|
||||
public int[] getRateUpItems4() {
|
||||
return (rateUpItems2.length > 0) ? rateUpItems2 : rateUpItems4;
|
||||
}
|
||||
public int[] getRateUpItems5() {
|
||||
return (rateUpItems1.length > 0) ? rateUpItems1 : rateUpItems5;
|
||||
return costItemId;
|
||||
}
|
||||
|
||||
public boolean hasEpitomized() {
|
||||
@ -92,7 +151,7 @@ public class GachaBanner {
|
||||
public int getEventChance(int rarity) {
|
||||
return switch (rarity) {
|
||||
case 4 -> eventChance4;
|
||||
default -> (eventChance > -1) ? eventChance : eventChance5;
|
||||
default -> eventChance5;
|
||||
};
|
||||
}
|
||||
|
||||
@ -110,8 +169,6 @@ public class GachaBanner {
|
||||
+ "/gacha/details?s=" + sessionKey + "&scheduleId=" + scheduleId;
|
||||
|
||||
// Grasscutter.getLogger().info("record = " + record);
|
||||
ItemParamData costItem1 = this.getCost(1);
|
||||
ItemParamData costItem10 = this.getCost(10);
|
||||
PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this);
|
||||
int leftGachaTimes = switch (gachaTimesLimit) {
|
||||
case Integer.MAX_VALUE -> Integer.MAX_VALUE;
|
||||
@ -122,10 +179,10 @@ public class GachaBanner {
|
||||
.setScheduleId(this.getScheduleId())
|
||||
.setBeginTime(this.getBeginTime())
|
||||
.setEndTime(this.getEndTime())
|
||||
.setCostItemId(costItem1.getId())
|
||||
.setCostItemNum(costItem1.getCount())
|
||||
.setTenCostItemId(costItem10.getId())
|
||||
.setTenCostItemNum(costItem10.getCount())
|
||||
.setCostItemId(this.costItemId)
|
||||
.setCostItemNum(this.costItemAmount)
|
||||
.setTenCostItemId(this.costItemId10)
|
||||
.setTenCostItemNum(this.costItemAmount10)
|
||||
.setGachaPrefabPath(this.getPrefabPath())
|
||||
.setGachaPreviewPrefabPath(this.getPreviewPrefabPath())
|
||||
.setGachaProbUrl(details)
|
||||
@ -174,6 +231,31 @@ public class GachaBanner {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,8 +45,6 @@ public class GachaSystem extends BaseGameSystem {
|
||||
|
||||
private static final int starglitterId = 221;
|
||||
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) {
|
||||
super(server);
|
||||
@ -69,11 +67,24 @@ public class GachaSystem extends BaseGameSystem {
|
||||
|
||||
public synchronized void load() {
|
||||
getGachaBanners().clear();
|
||||
int autoScheduleId = 1000;
|
||||
int autoSortId = 9000;
|
||||
try {
|
||||
List<GachaBanner> banners = DataLoader.loadList("Banners.json", GachaBanner.class);
|
||||
List<GachaBanner> banners = DataLoader.loadTableToList("Banners", GachaBanner.class);
|
||||
if (banners.size() > 0) {
|
||||
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.");
|
||||
} else {
|
||||
@ -155,7 +166,7 @@ public class GachaSystem extends BaseGameSystem {
|
||||
private synchronized int doFallbackRarePull(int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) {
|
||||
if (fallback1.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 {
|
||||
return getRandom(fallback2);
|
||||
}
|
||||
|
@ -4,37 +4,43 @@ import dev.morphia.annotations.Entity;
|
||||
|
||||
@Entity
|
||||
public class PlayerGachaInfo {
|
||||
private PlayerGachaBannerInfo standardBanner;
|
||||
private PlayerGachaBannerInfo eventCharacterBanner;
|
||||
private PlayerGachaBannerInfo eventWeaponBanner;
|
||||
|
||||
public PlayerGachaInfo() {
|
||||
this.standardBanner = new PlayerGachaBannerInfo();
|
||||
this.eventCharacterBanner = new PlayerGachaBannerInfo();
|
||||
this.eventWeaponBanner = new PlayerGachaBannerInfo();
|
||||
}
|
||||
|
||||
public PlayerGachaBannerInfo getStandardBanner() {
|
||||
return standardBanner;
|
||||
}
|
||||
private PlayerGachaBannerInfo standardBanner;
|
||||
private PlayerGachaBannerInfo beginnerBanner;
|
||||
private PlayerGachaBannerInfo eventCharacterBanner;
|
||||
private PlayerGachaBannerInfo eventWeaponBanner;
|
||||
|
||||
public PlayerGachaBannerInfo getEventCharacterBanner() {
|
||||
return eventCharacterBanner;
|
||||
}
|
||||
|
||||
public PlayerGachaBannerInfo getEventWeaponBanner() {
|
||||
return eventWeaponBanner;
|
||||
}
|
||||
public PlayerGachaInfo() {
|
||||
this.standardBanner = new PlayerGachaBannerInfo();
|
||||
this.eventCharacterBanner = new PlayerGachaBannerInfo();
|
||||
this.eventWeaponBanner = new PlayerGachaBannerInfo();
|
||||
}
|
||||
|
||||
public PlayerGachaBannerInfo getBannerInfo(GachaBanner banner) {
|
||||
switch (banner.getBannerType()) {
|
||||
case EVENT:
|
||||
return this.eventCharacterBanner;
|
||||
case WEAPON:
|
||||
return this.eventWeaponBanner;
|
||||
case STANDARD:
|
||||
default:
|
||||
return this.standardBanner;
|
||||
}
|
||||
}
|
||||
public PlayerGachaBannerInfo getStandardBanner() {
|
||||
if (this.standardBanner == null) this.standardBanner = new PlayerGachaBannerInfo();
|
||||
return this.standardBanner;
|
||||
}
|
||||
|
||||
public PlayerGachaBannerInfo getBeginnerBanner() {
|
||||
if (this.beginnerBanner == null) this.beginnerBanner = new PlayerGachaBannerInfo();
|
||||
return this.beginnerBanner;
|
||||
}
|
||||
|
||||
public PlayerGachaBannerInfo getEventCharacterBanner() {
|
||||
if (this.eventCharacterBanner == null) this.eventCharacterBanner = new PlayerGachaBannerInfo();
|
||||
return this.eventCharacterBanner;
|
||||
}
|
||||
|
||||
public PlayerGachaBannerInfo getEventWeaponBanner() {
|
||||
if (this.eventWeaponBanner == null) this.eventWeaponBanner = new PlayerGachaBannerInfo();
|
||||
return this.eventWeaponBanner;
|
||||
}
|
||||
|
||||
public PlayerGachaBannerInfo getBannerInfo(GachaBanner banner) {
|
||||
return switch (banner.getBannerType()) {
|
||||
case STANDARD -> this.getStandardBanner();
|
||||
case BEGINNER -> this.getBeginnerBanner();
|
||||
case EVENT, CHARACTER, CHARACTER2 -> this.getEventCharacterBanner();
|
||||
case WEAPON -> this.getEventWeaponBanner();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -193,6 +193,7 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
|
||||
|
||||
if (data.isUseOnGain()) {
|
||||
var params = new UseItemParams(this.player, data.getUseTarget());
|
||||
params.usedItemId = data.getId();
|
||||
this.player.getServer().getInventorySystem().useItemDirect(data, params);
|
||||
return null;
|
||||
}
|
||||
|
@ -36,6 +36,11 @@ public class DeforestationManager extends BasePlayerManager {
|
||||
ColliderTypeToWoodItemID.put(10,101310);
|
||||
ColliderTypeToWoodItemID.put(11,101311);
|
||||
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) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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.Int2ObjectOpenHashMap;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
|
||||
@Getter(AccessLevel.PRIVATE)
|
||||
public class PlayerBuffManager extends BasePlayerManager {
|
||||
private int nextBuffUid;
|
||||
|
||||
@ -29,7 +26,7 @@ public class PlayerBuffManager extends BasePlayerManager {
|
||||
public PlayerBuffManager(Player player) {
|
||||
super(player);
|
||||
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
|
||||
*/
|
||||
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() {
|
||||
// Remove from player
|
||||
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
|
||||
getBuffs().clear();
|
||||
this.buffs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,13 +130,11 @@ public class PlayerBuffManager extends BasePlayerManager {
|
||||
}
|
||||
|
||||
// Clear previous buff if it exists
|
||||
if (this.hasBuff(buffData.getGroupId())) {
|
||||
this.removeBuff(buffData.getGroupId());
|
||||
}
|
||||
this.removeBuff(buffData.getGroupId());
|
||||
|
||||
// Create and store buff
|
||||
PlayerBuff buff = new PlayerBuff(getNextBuffUid(), buffData, duration);
|
||||
getBuffs().put(buff.getGroupId(), buff);
|
||||
this.buffs.put(buff.getGroupId(), buff);
|
||||
|
||||
// Packet
|
||||
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
|
||||
*/
|
||||
public synchronized boolean removeBuff(int buffGroupId) {
|
||||
PlayerBuff buff = this.getBuffs().get(buffGroupId);
|
||||
PlayerBuff buff = this.buffs.remove(buffGroupId);
|
||||
|
||||
if (buff != null) {
|
||||
getPlayer().sendPacket(
|
||||
@ -167,28 +162,24 @@ public class PlayerBuffManager extends BasePlayerManager {
|
||||
|
||||
public synchronized void onTick() {
|
||||
// Skip if no buffs
|
||||
if (getBuffs().size() == 0) return;
|
||||
if (this.buffs.isEmpty()) return;
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
// Add to pending buffs to remove if buff has expired
|
||||
for (PlayerBuff buff : getBuffs().values()) {
|
||||
if (currentTime > buff.getEndTime()) {
|
||||
this.getPendingBuffs().add(buff);
|
||||
}
|
||||
}
|
||||
this.buffs.values().removeIf(buff -> {
|
||||
if (currentTime <= buff.getEndTime())
|
||||
return false;
|
||||
this.pendingBuffs.add(buff);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (this.getPendingBuffs().size() > 0) {
|
||||
if (this.pendingBuffs.size() > 0) {
|
||||
// Send packet
|
||||
getPlayer().sendPacket(
|
||||
new PacketServerBuffChangeNotify(getPlayer(), ServerBuffChangeType.SERVER_BUFF_CHANGE_TYPE_DEL_SERVER_BUFF, this.pendingBuffs)
|
||||
);
|
||||
|
||||
// Remove buff from player buff map
|
||||
for (PlayerBuff buff : this.getPendingBuffs()) {
|
||||
getBuffs().remove(buff.getGroupId());
|
||||
}
|
||||
this.getPendingBuffs().clear();
|
||||
this.pendingBuffs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
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.Int2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
public enum FightProperty {
|
||||
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<FightProperty> map = new Int2ObjectOpenHashMap<>();
|
||||
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};
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> {
|
||||
map.put(e.getId(), e);
|
||||
stringMap.put(e.name(), e);
|
||||
});
|
||||
}
|
||||
|
||||
private FightProperty(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
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);
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static FightProperty getPropById(int value) {
|
||||
return map.getOrDefault(value, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByName(String name) {
|
||||
return stringMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
private final int id;
|
||||
private static final Int2ObjectMap<FightProperty> map = new Int2ObjectOpenHashMap<>();
|
||||
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};
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> {
|
||||
map.put(e.getId(), e);
|
||||
stringMap.put(e.name(), e);
|
||||
});
|
||||
}
|
||||
|
||||
private FightProperty(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static FightProperty getPropById(int value) {
|
||||
return map.getOrDefault(value, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByName(String name) {
|
||||
return stringMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByShortName(String name) {
|
||||
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
|
||||
private static final Map<String, FightProperty> shortNameMap = Map.ofEntries(
|
||||
// Normal relic stats
|
||||
entry("hp", FIGHT_PROP_HP),
|
||||
entry("atk", FIGHT_PROP_ATTACK),
|
||||
entry("def", FIGHT_PROP_DEFENSE),
|
||||
entry("hp%", FIGHT_PROP_HP_PERCENT),
|
||||
entry("atk%", FIGHT_PROP_ATTACK_PERCENT),
|
||||
entry("def%", FIGHT_PROP_DEFENSE_PERCENT),
|
||||
entry("em", FIGHT_PROP_ELEMENT_MASTERY),
|
||||
entry("er", FIGHT_PROP_CHARGE_EFFICIENCY),
|
||||
entry("hb", FIGHT_PROP_HEAL_ADD),
|
||||
entry("hp", FIGHT_PROP_HP),
|
||||
entry("atk", FIGHT_PROP_ATTACK),
|
||||
entry("def", FIGHT_PROP_DEFENSE),
|
||||
entry("hp%", FIGHT_PROP_HP_PERCENT),
|
||||
entry("atk%", FIGHT_PROP_ATTACK_PERCENT),
|
||||
entry("def%", FIGHT_PROP_DEFENSE_PERCENT),
|
||||
entry("em", FIGHT_PROP_ELEMENT_MASTERY),
|
||||
entry("er", FIGHT_PROP_CHARGE_EFFICIENCY),
|
||||
entry("hb", FIGHT_PROP_HEAL_ADD),
|
||||
entry("heal", FIGHT_PROP_HEAL_ADD),
|
||||
entry("cd", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cdmg", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cr", FIGHT_PROP_CRITICAL),
|
||||
entry("crate", FIGHT_PROP_CRITICAL),
|
||||
entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT),
|
||||
entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT),
|
||||
entry("geo%", FIGHT_PROP_ROCK_ADD_HURT),
|
||||
entry("anemo%", FIGHT_PROP_WIND_ADD_HURT),
|
||||
entry("hydro%", FIGHT_PROP_WATER_ADD_HURT),
|
||||
entry("cryo%", FIGHT_PROP_ICE_ADD_HURT),
|
||||
entry("electro%", FIGHT_PROP_ELEC_ADD_HURT),
|
||||
entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT),
|
||||
entry("cd", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cdmg", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cr", FIGHT_PROP_CRITICAL),
|
||||
entry("crate", FIGHT_PROP_CRITICAL),
|
||||
entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT),
|
||||
entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT),
|
||||
entry("geo%", FIGHT_PROP_ROCK_ADD_HURT),
|
||||
entry("anemo%", FIGHT_PROP_WIND_ADD_HURT),
|
||||
entry("hydro%", FIGHT_PROP_WATER_ADD_HURT),
|
||||
entry("cryo%", FIGHT_PROP_ICE_ADD_HURT),
|
||||
entry("electro%", FIGHT_PROP_ELEC_ADD_HURT),
|
||||
entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT),
|
||||
// Other stats
|
||||
entry("maxhp", FIGHT_PROP_MAX_HP),
|
||||
entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks
|
||||
@ -189,14 +191,43 @@ public enum FightProperty {
|
||||
entry("reshydro", FIGHT_PROP_WATER_SUB_HURT),
|
||||
entry("respyro", FIGHT_PROP_FIRE_SUB_HURT),
|
||||
entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT)
|
||||
);
|
||||
);
|
||||
|
||||
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_DEFENSE, FIGHT_PROP_HEALED_ADD, FIGHT_PROP_CUR_FIRE_ENERGY, FIGHT_PROP_CUR_ELEC_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) {
|
||||
return !flatProps.contains(prop);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ public class ItemUseAction {
|
||||
case ITEM_USE_GAIN_AVATAR -> new ItemUseGainAvatar(useParam);
|
||||
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_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_ADD_SELECT_ITEM -> new ItemUseAddSelectItem(useParam);
|
||||
case ITEM_USE_GRANT_SELECT_REWARD -> new ItemUseGrantSelectReward(useParam);
|
||||
|
@ -1,19 +1,18 @@
|
||||
package emu.grasscutter.game.props.ItemUseAction;
|
||||
|
||||
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
|
||||
public ItemUseOp getItemUseOp() {
|
||||
return ItemUseOp.ITEM_USE_ADD_EXP;
|
||||
}
|
||||
|
||||
public ItemUseAddExp(String[] useParam) {
|
||||
try {
|
||||
this.exp = Integer.parseInt(useParam[0]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
super(useParam);
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return this.i;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ public class ItemUseAddItem extends ItemUseInt {
|
||||
super(useParam);
|
||||
try {
|
||||
this.count = Integer.parseInt(useParam[1]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,19 +1,14 @@
|
||||
package emu.grasscutter.game.props.ItemUseAction;
|
||||
|
||||
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
|
||||
public ItemUseOp getItemUseOp() {
|
||||
return ItemUseOp.ITEM_USE_ADD_RELIQUARY_EXP;
|
||||
}
|
||||
|
||||
public ItemUseAddReliquaryExp(String[] useParam) {
|
||||
try {
|
||||
this.exp = Integer.parseInt(useParam[0]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
super(useParam);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ public class ItemUseAddServerBuff extends ItemUseInt {
|
||||
super(useParam);
|
||||
try {
|
||||
this.duration = Integer.parseInt(useParam[1]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,19 +1,14 @@
|
||||
package emu.grasscutter.game.props.ItemUseAction;
|
||||
|
||||
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
|
||||
public ItemUseOp getItemUseOp() {
|
||||
return ItemUseOp.ITEM_USE_ADD_WEAPON_EXP;
|
||||
}
|
||||
|
||||
public ItemUseAddWeaponExp(String[] useParam) {
|
||||
try {
|
||||
this.exp = Integer.parseInt(useParam[0]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
super(useParam);
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,10 @@ public class ItemUseCombineItem extends ItemUseInt {
|
||||
super(useParam);
|
||||
try {
|
||||
this.resultId = Integer.parseInt(useParam[1]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||
try {
|
||||
this.resultCount = Integer.parseInt(useParam[2]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,10 +19,10 @@ public class ItemUseGainAvatar extends ItemUseInt {
|
||||
super(useParam);
|
||||
try {
|
||||
this.level = Integer.parseInt(useParam[1]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||
try {
|
||||
this.constellation = Integer.parseInt(useParam[2]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -13,6 +13,7 @@ public class ItemUseGainNameCard extends ItemUseAction {
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,6 @@ public abstract class ItemUseInt extends ItemUseAction {
|
||||
public ItemUseInt(String[] useParam) {
|
||||
try {
|
||||
this.i = Integer.parseInt(useParam[0]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ public class UseItemParams {
|
||||
public int count = 1;
|
||||
public int optionId = 0;
|
||||
public boolean isEnterMpDungeonTeam = false;
|
||||
public int usedItemId = 0;
|
||||
|
||||
public UseItemParams(Player player, ItemUseTarget itemUseTarget, Avatar targetAvatar, int count, int optionId, boolean isEnterMpDungeonTeam) {
|
||||
this.player = player;
|
||||
|
@ -1,17 +1,17 @@
|
||||
package emu.grasscutter.game.quest;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.excels.QuestData.QuestAcceptCondition;
|
||||
import emu.grasscutter.data.excels.QuestData.QuestContentCondition;
|
||||
import emu.grasscutter.data.excels.QuestData.QuestExecParam;
|
||||
import emu.grasscutter.game.quest.conditions.BaseCondition;
|
||||
import emu.grasscutter.game.quest.content.BaseContent;
|
||||
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
||||
import emu.grasscutter.server.game.BaseGameSystem;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.excels.QuestData.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class QuestSystem extends BaseGameSystem {
|
||||
@ -47,13 +47,13 @@ public class QuestSystem extends BaseGameSystem {
|
||||
public <T> void registerPacketHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
|
||||
try {
|
||||
int value = 0;
|
||||
if(handlerClass.isAnnotationPresent(QuestValueExec.class)) {
|
||||
if (handlerClass.isAnnotationPresent(QuestValueExec.class)) {
|
||||
QuestValueExec opcode = handlerClass.getAnnotation(QuestValueExec.class);
|
||||
value = opcode.value().getValue();
|
||||
} else if(handlerClass.isAnnotationPresent(QuestValueContent.class)) {
|
||||
} else if (handlerClass.isAnnotationPresent(QuestValueContent.class)) {
|
||||
QuestValueContent opcode = handlerClass.getAnnotation(QuestValueContent.class);
|
||||
value = opcode.value().getValue();
|
||||
} else if(handlerClass.isAnnotationPresent(QuestValueCond.class)) {
|
||||
} else if (handlerClass.isAnnotationPresent(QuestValueCond.class)) {
|
||||
QuestValueCond opcode = handlerClass.getAnnotation(QuestValueCond.class);
|
||||
value = opcode.value().getValue();
|
||||
} else {
|
||||
@ -64,7 +64,7 @@ public class QuestSystem extends BaseGameSystem {
|
||||
return;
|
||||
}
|
||||
|
||||
map.put(value, handlerClass.newInstance());
|
||||
map.put(value, handlerClass.getDeclaredConstructor().newInstance());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -103,7 +103,7 @@ public class QuestSystem extends BaseGameSystem {
|
||||
}
|
||||
|
||||
QuestManager.eventExecutor.submit(() -> {
|
||||
if(!handler.execute(quest, execParam, params)){
|
||||
if (!handler.execute(quest, execParam, params)) {
|
||||
Grasscutter.getLogger().debug("exec trigger failed {} at {}", execParam.getType().getValue(), quest.getQuestData());
|
||||
}
|
||||
});
|
||||
|
@ -744,6 +744,7 @@ public class InventorySystem extends BaseGameSystem {
|
||||
if (itemData == null) return null;
|
||||
|
||||
var params = new UseItemParams(player, itemData.getUseTarget(), target, count, optionId, isEnterMpDungeonTeam);
|
||||
params.usedItemId = item.getItemId();
|
||||
if (useItemDirect(itemData, params)) {
|
||||
player.getInventory().removeItem(item, count);
|
||||
var actions = itemData.getItemUseActions();
|
||||
|
@ -8,8 +8,9 @@ import emu.grasscutter.data.binout.routes.Route;
|
||||
import emu.grasscutter.data.excels.*;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.dungeons.DungeonManager;
|
||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||
import emu.grasscutter.game.dungeons.DungeonSettleListener;
|
||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||
import emu.grasscutter.game.entity.*;
|
||||
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
||||
import emu.grasscutter.game.managers.blossom.BlossomManager;
|
||||
@ -17,7 +18,6 @@ import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.TeamInfo;
|
||||
import emu.grasscutter.game.props.*;
|
||||
import emu.grasscutter.game.quest.QuestGroupSuite;
|
||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||
import emu.grasscutter.game.world.data.TeleportProperties;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||
@ -55,24 +55,23 @@ public class Scene {
|
||||
@Getter private final Set<SpawnDataEntry> deadSpawnedEntities;
|
||||
@Getter private final Set<SceneBlock> loadedBlocks;
|
||||
@Getter private final BlossomManager blossomManager;
|
||||
private final HashSet<Integer> unlockedForces;
|
||||
private final List<Runnable> afterLoadedCallbacks = new ArrayList<>();
|
||||
private final long startWorldTime;
|
||||
@Getter @Setter DungeonManager dungeonManager;
|
||||
@Getter Int2ObjectMap<Route> sceneRoutes;
|
||||
private Set<SpawnDataEntry.GridBlockId> loadedGridBlocks;
|
||||
@Getter @Setter private boolean dontDestroyWhenEmpty;
|
||||
|
||||
@Getter private SceneScriptManager scriptManager;
|
||||
@Getter private final SceneScriptManager scriptManager;
|
||||
@Getter @Setter private WorldChallenge challenge;
|
||||
@Getter private List<DungeonSettleListener> dungeonSettleListeners;
|
||||
@Getter @Setter DungeonManager dungeonManager;
|
||||
@Getter @Setter private int prevScene; // Id of the previous scene
|
||||
@Getter @Setter private int prevScenePoint;
|
||||
@Getter @Setter private int killedMonsterCount;
|
||||
@Getter Int2ObjectMap<Route> sceneRoutes;
|
||||
private Set<SceneNpcBornEntry> npcBornEntrySet;
|
||||
private final HashSet<Integer> unlockedForces;
|
||||
@Getter private boolean finishedLoading = false;
|
||||
private final List<Runnable> afterLoadedCallbacks = new ArrayList<>();
|
||||
@Getter private int tickCount = 0;
|
||||
@Getter private boolean isPaused = false;
|
||||
private final long startWorldTime;
|
||||
|
||||
public Scene(World world, SceneData sceneData) {
|
||||
this.world = world;
|
||||
@ -113,25 +112,25 @@ public class Scene {
|
||||
|
||||
public GameEntity getEntityByConfigId(int configId) {
|
||||
return this.entities.values().stream()
|
||||
.filter(x -> x.getConfigId() == configId)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
.filter(x -> x.getConfigId() == configId)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public GameEntity getEntityByConfigId(int configId, int groupId) {
|
||||
return this.entities.values().stream()
|
||||
.filter(x -> x.getConfigId() == configId && x.getGroupId() == groupId)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
.filter(x -> x.getConfigId() == configId && x.getGroupId() == groupId)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Route getSceneRouteById(int routeId){
|
||||
public Route getSceneRouteById(int routeId) {
|
||||
return sceneRoutes.get(routeId);
|
||||
}
|
||||
|
||||
public void setPaused(boolean paused) {
|
||||
if(isPaused != paused) {
|
||||
if (isPaused != paused) {
|
||||
isPaused = paused;
|
||||
broadcastPacket(new PacketSceneTimeNotify(this));
|
||||
}
|
||||
@ -142,7 +141,7 @@ public class Scene {
|
||||
}
|
||||
|
||||
public int getSceneTimeSeconds() {
|
||||
return getSceneTime()/1000;
|
||||
return getSceneTime() / 1000;
|
||||
}
|
||||
|
||||
public void addDungeonSettleObserver(DungeonSettleListener dungeonSettleListener) {
|
||||
@ -152,8 +151,8 @@ public class Scene {
|
||||
dungeonSettleListeners.add(dungeonSettleListener);
|
||||
}
|
||||
|
||||
public void triggerDungeonEvent(DungeonPassConditionType conditionType, int... params){
|
||||
if(dungeonManager==null){
|
||||
public void triggerDungeonEvent(DungeonPassConditionType conditionType, int... params) {
|
||||
if (dungeonManager == null) {
|
||||
return;
|
||||
}
|
||||
dungeonManager.triggerEvent(conditionType, params);
|
||||
@ -261,6 +260,7 @@ public class Scene {
|
||||
player.sendPacket(new PacketSceneEntityAppearNotify(entity));
|
||||
|
||||
}
|
||||
|
||||
public void addEntities(Collection<? extends GameEntity> entities) {
|
||||
addEntities(entities, VisionType.VISION_TYPE_BORN);
|
||||
}
|
||||
@ -294,14 +294,16 @@ public class Scene {
|
||||
this.broadcastPacket(new PacketSceneEntityDisappearNotify(removed, visionType));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeEntities(List<GameEntity> entity, VisionType visionType) {
|
||||
var toRemove = entity.stream()
|
||||
.map(this::removeEntityDirectly)
|
||||
.toList();
|
||||
.map(this::removeEntityDirectly)
|
||||
.toList();
|
||||
if (toRemove.size() > 0) {
|
||||
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, visionType));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void replaceEntity(EntityAvatar oldEntity, EntityAvatar newEntity) {
|
||||
this.removeEntityDirectly(oldEntity);
|
||||
this.addEntityDirectly(newEntity);
|
||||
@ -310,15 +312,8 @@ public class Scene {
|
||||
}
|
||||
|
||||
public void showOtherEntities(Player player) {
|
||||
List<GameEntity> entities = new LinkedList<>();
|
||||
GameEntity currentEntity = player.getTeamManager().getCurrentAvatarEntity();
|
||||
|
||||
for (GameEntity entity : this.getEntities().values()) {
|
||||
if (entity == currentEntity) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entity);
|
||||
}
|
||||
List<GameEntity> entities = this.getEntities().values().stream().filter(entity -> entity != currentEntity).toList();
|
||||
|
||||
player.sendPacket(new PacketSceneEntityAppearNotify(entities, VisionType.VISION_TYPE_MEET));
|
||||
}
|
||||
@ -409,17 +404,17 @@ public class Scene {
|
||||
checkNpcGroup();
|
||||
finishLoading();
|
||||
checkPlayerRespawn();
|
||||
if(tickCount%10 == 0){
|
||||
if (tickCount % 10 == 0) {
|
||||
broadcastPacket(new PacketSceneTimeNotify(this));
|
||||
}
|
||||
tickCount++;
|
||||
}
|
||||
|
||||
private void checkPlayerRespawn(){
|
||||
private void checkPlayerRespawn() {
|
||||
players.forEach(player -> {
|
||||
//Check if we need a respawn
|
||||
if(getScriptManager().getConfig() != null ) {
|
||||
if(getScriptManager().getConfig().die_y >= player.getPosition().getY()) {
|
||||
if (getScriptManager().getConfig() != null) {
|
||||
if (getScriptManager().getConfig().die_y >= player.getPosition().getY()) {
|
||||
//Respawn the player
|
||||
respawnPlayer(player);
|
||||
}
|
||||
@ -427,28 +422,29 @@ public class Scene {
|
||||
});
|
||||
}
|
||||
|
||||
public Position getDefaultLocation(Player player){
|
||||
public Position getDefaultLocation(Player player) {
|
||||
val defaultPosition = getScriptManager().getConfig().born_pos;
|
||||
return defaultPosition!=null ? defaultPosition : player.getPosition();
|
||||
return defaultPosition != null ? defaultPosition : player.getPosition();
|
||||
}
|
||||
|
||||
private Position getDefaultRot(Player player){
|
||||
private Position getDefaultRot(Player player) {
|
||||
val defaultRotation = getScriptManager().getConfig().born_rot;
|
||||
return defaultRotation!=null ? defaultRotation : player.getRotation();
|
||||
return defaultRotation != null ? defaultRotation : player.getRotation();
|
||||
}
|
||||
|
||||
private Position getRespawnLocation(Player player){
|
||||
private Position getRespawnLocation(Player player) {
|
||||
//TODO get last valid location the player stood on
|
||||
val lastCheckpointPos = dungeonManager!=null? dungeonManager.getRespawnLocation() : null;
|
||||
return lastCheckpointPos!=null ? lastCheckpointPos : getDefaultLocation(player);
|
||||
val lastCheckpointPos = dungeonManager != null ? dungeonManager.getRespawnLocation() : null;
|
||||
return lastCheckpointPos != null ? lastCheckpointPos : getDefaultLocation(player);
|
||||
}
|
||||
private Position getRespawnRotation(Player player){
|
||||
val lastCheckpointRot = dungeonManager!=null? dungeonManager.getRespawnRotation() : null;
|
||||
return lastCheckpointRot!=null ? lastCheckpointRot : getDefaultRot(player);
|
||||
|
||||
private Position getRespawnRotation(Player player) {
|
||||
val lastCheckpointRot = dungeonManager != null ? dungeonManager.getRespawnRotation() : null;
|
||||
return lastCheckpointRot != null ? lastCheckpointRot : getDefaultRot(player);
|
||||
|
||||
}
|
||||
|
||||
public boolean respawnPlayer(Player player){
|
||||
public boolean respawnPlayer(Player player) {
|
||||
player.getTeamManager().onAvatarDieDamage();
|
||||
|
||||
// todo should probably respawn the player at the last valid location
|
||||
@ -460,14 +456,14 @@ public class Scene {
|
||||
.teleportRot(targetRot)
|
||||
.teleportType(PlayerTeleportEvent.TeleportType.INTERNAL)
|
||||
.enterType(EnterTypeOuterClass.EnterType.ENTER_TYPE_GOTO)
|
||||
.enterReason(dungeonManager!=null ? EnterReason.DungeonReviveOnWaypoint: EnterReason.Revival);
|
||||
.enterReason(dungeonManager != null ? EnterReason.DungeonReviveOnWaypoint : EnterReason.Revival);
|
||||
|
||||
|
||||
return getWorld().transferPlayerToScene(player, teleportProps.build());
|
||||
}
|
||||
|
||||
public void finishLoading(){
|
||||
if(finishedLoading){
|
||||
public void finishLoading() {
|
||||
if (finishedLoading) {
|
||||
return;
|
||||
}
|
||||
this.finishedLoading = true;
|
||||
@ -475,8 +471,8 @@ public class Scene {
|
||||
afterLoadedCallbacks.clear();
|
||||
}
|
||||
|
||||
public void runWhenFinished(Runnable runnable){
|
||||
if(isFinishedLoading()){
|
||||
public void runWhenFinished(Runnable runnable) {
|
||||
if (isFinishedLoading()) {
|
||||
runnable.run();
|
||||
return;
|
||||
}
|
||||
@ -490,6 +486,7 @@ public class Scene {
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
public void checkNpcGroup() {
|
||||
Set<SceneNpcBornEntry> npcBornEntries = ConcurrentHashMap.newKeySet();
|
||||
for (Player player : this.getPlayers()) {
|
||||
@ -524,7 +521,7 @@ public class Scene {
|
||||
Set<SpawnDataEntry> visible = new HashSet<>();
|
||||
for (var block : loadedGridBlocks) {
|
||||
var spawns = spawnLists.get(block);
|
||||
if (spawns!=null) {
|
||||
if (spawns != null) {
|
||||
visible.addAll(spawns);
|
||||
}
|
||||
}
|
||||
@ -538,8 +535,8 @@ public class Scene {
|
||||
}
|
||||
|
||||
// Todo
|
||||
List<GameEntity> toAdd = new LinkedList<>();
|
||||
List<GameEntity> toRemove = new LinkedList<>();
|
||||
List<GameEntity> toAdd = new ArrayList<>();
|
||||
List<GameEntity> toRemove = new ArrayList<>();
|
||||
var spawnedEntities = this.getSpawnedEntities();
|
||||
for (SpawnDataEntry entry : visible) {
|
||||
// If spawn entry is in our view and hasnt been spawned/killed yet, we should spawn it
|
||||
@ -568,7 +565,7 @@ public class Scene {
|
||||
gadget.setConfigId(entry.getConfigId());
|
||||
gadget.setSpawnEntry(entry);
|
||||
int state = entry.getGadgetState();
|
||||
if (state>0) {
|
||||
if (state > 0) {
|
||||
gadget.setState(state);
|
||||
}
|
||||
gadget.buildContent();
|
||||
@ -611,7 +608,7 @@ public class Scene {
|
||||
public List<SceneBlock> getPlayerActiveBlocks(Player player) {
|
||||
// consider the borders' entities of blocks, so we check if contains by index
|
||||
return SceneIndexManager.queryNeighbors(getScriptManager().getBlocksIndex(),
|
||||
player.getPosition().toXZDoubleArray(), Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange);
|
||||
player.getPosition().toXZDoubleArray(), Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange);
|
||||
}
|
||||
|
||||
private boolean unloadBlockIfNotVisible(Collection<SceneBlock> visible, SceneBlock block) {
|
||||
@ -649,12 +646,12 @@ public class Scene {
|
||||
|
||||
public List<SceneGroup> playerMeetGroups(Player player, SceneBlock block) {
|
||||
List<SceneGroup> sceneGroups = SceneIndexManager.queryNeighbors(block.sceneGroupIndex, player.getPosition().toDoubleArray(),
|
||||
Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange);
|
||||
Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange);
|
||||
|
||||
List<SceneGroup> groups = sceneGroups.stream()
|
||||
.filter(group -> !scriptManager.getLoadedGroupSetPerBlock().get(block.id).contains(group))
|
||||
.peek(group -> scriptManager.getLoadedGroupSetPerBlock().get(block.id).add(group))
|
||||
.toList();
|
||||
.filter(group -> !scriptManager.getLoadedGroupSetPerBlock().get(block.id).contains(group))
|
||||
.peek(group -> scriptManager.getLoadedGroupSetPerBlock().get(block.id).add(group))
|
||||
.toList();
|
||||
|
||||
if (groups.size() == 0) {
|
||||
return List.of();
|
||||
@ -662,20 +659,22 @@ public class Scene {
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
public void onLoadBlock(SceneBlock block, List<Player> players) {
|
||||
this.getScriptManager().loadBlockFromScript(block);
|
||||
scriptManager.getLoadedGroupSetPerBlock().put(block.id , new HashSet<>());
|
||||
scriptManager.getLoadedGroupSetPerBlock().put(block.id, new HashSet<>());
|
||||
|
||||
// the groups form here is not added in current scene
|
||||
var groups = players.stream()
|
||||
.filter(player -> block.contains(player.getPosition()))
|
||||
.map(p -> playerMeetGroups(p, block))
|
||||
.flatMap(Collection::stream)
|
||||
.toList();
|
||||
.filter(player -> block.contains(player.getPosition()))
|
||||
.map(p -> playerMeetGroups(p, block))
|
||||
.flatMap(Collection::stream)
|
||||
.toList();
|
||||
|
||||
onLoadGroup(groups);
|
||||
Grasscutter.getLogger().info("Scene {} Block {} loaded.", this.getId(), block.id);
|
||||
}
|
||||
|
||||
public void loadTriggerFromGroup(SceneGroup group, String triggerName) {
|
||||
//Load triggers and regions
|
||||
getScriptManager().registerTrigger(group.triggers.values().stream().filter(p -> p.getName().contains(triggerName)).toList());
|
||||
@ -705,8 +704,8 @@ public class Scene {
|
||||
|
||||
if (garbageGadgets != null) {
|
||||
entities.addAll(garbageGadgets.stream().map(g -> scriptManager.createGadget(group.id, group.block_id, g))
|
||||
.filter(Objects::nonNull)
|
||||
.toList());
|
||||
.filter(Objects::nonNull)
|
||||
.toList());
|
||||
}
|
||||
|
||||
// Load suites
|
||||
@ -733,7 +732,7 @@ public class Scene {
|
||||
|
||||
public void onUnloadBlock(SceneBlock block) {
|
||||
List<GameEntity> toRemove = this.getEntities().values().stream()
|
||||
.filter(e -> e.getBlockId() == block.id).toList();
|
||||
.filter(e -> e.getBlockId() == block.id).toList();
|
||||
|
||||
if (toRemove.size() > 0) {
|
||||
toRemove.forEach(this::removeEntityDirectly);
|
||||
@ -831,9 +830,11 @@ public class Scene {
|
||||
addEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadNpcForPlayerEnter(Player player) {
|
||||
this.npcBornEntrySet.addAll(loadNpcForPlayer(player));
|
||||
}
|
||||
|
||||
private List<SceneNpcBornEntry> loadNpcForPlayer(Player player) {
|
||||
var pos = player.getPosition();
|
||||
var data = GameData.getSceneNpcBornData().get(getId());
|
||||
@ -842,7 +843,7 @@ public class Scene {
|
||||
}
|
||||
|
||||
var npcList = SceneIndexManager.queryNeighbors(data.getIndex(), pos.toDoubleArray(),
|
||||
Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange);
|
||||
Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange);
|
||||
|
||||
var sceneNpcBornEntries = npcList.stream()
|
||||
.filter(i -> !this.npcBornEntrySet.contains(i))
|
||||
@ -873,12 +874,12 @@ public class Scene {
|
||||
});
|
||||
}
|
||||
|
||||
public void unlockForce(int force){
|
||||
public void unlockForce(int force) {
|
||||
unlockedForces.add(force);
|
||||
broadcastPacket(new PacketSceneForceUnlockNotify(force, true));
|
||||
}
|
||||
|
||||
public void lockForce(int force){
|
||||
public void lockForce(int force) {
|
||||
unlockedForces.remove(force);
|
||||
broadcastPacket(new PacketSceneForceLockNotify(force));
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ public final class PluginManager {
|
||||
// Add the plugin to the list of loaded plugins.
|
||||
this.plugins.put(identifier.name, plugin);
|
||||
// Create a collection for the plugin's listeners.
|
||||
this.listeners.put(plugin, new LinkedList<>());
|
||||
this.listeners.put(plugin, new ArrayList<>());
|
||||
|
||||
// Call the plugin's onLoad method.
|
||||
try {
|
||||
@ -242,18 +242,14 @@ public final class PluginManager {
|
||||
* @param priority The priority to call for.
|
||||
*/
|
||||
private void checkAndFilter(Event event, HandlerPriority priority) {
|
||||
// Create a collection of listeners.
|
||||
List<EventHandler<? extends Event>> listeners = new LinkedList<>();
|
||||
|
||||
// Add all listeners from every plugin.
|
||||
this.listeners.values().forEach(listeners::addAll);
|
||||
|
||||
listeners.stream()
|
||||
this.listeners.values().stream()
|
||||
.flatMap(Collection::stream)
|
||||
// Filter the listeners by priority.
|
||||
.filter(handler -> handler.handles().isInstance(event))
|
||||
.filter(handler -> handler.getPriority() == priority)
|
||||
// Invoke the event.
|
||||
.toList().forEach(handler -> this.invokeHandler(event, handler));
|
||||
.forEach(handler -> this.invokeHandler(event, handler));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,8 +11,9 @@ import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.http.HttpServer;
|
||||
import emu.grasscutter.server.http.Router;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Hooks into the {@link GameServer} class, adding convenient ways to do certain things.
|
||||
@ -60,8 +61,17 @@ public final class ServerHook {
|
||||
* Gets all online players.
|
||||
* @return Players connected to the server.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public List<Player> getOnlinePlayers() {
|
||||
return new LinkedList<>(this.gameServer.getPlayers().values());
|
||||
return new ArrayList<>(this.gameServer.getPlayers().values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all online players.
|
||||
* @return Players connected to the server.
|
||||
*/
|
||||
public Stream<Player> getOnlinePlayersStream() {
|
||||
return this.gameServer.getPlayers().values().stream();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,8 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.PlayerBuffManager.PlayerBuff;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
@ -13,31 +13,25 @@ import emu.grasscutter.net.proto.ServerBuffChangeNotifyOuterClass.ServerBuffChan
|
||||
public class PacketServerBuffChangeNotify extends BasePacket {
|
||||
|
||||
public PacketServerBuffChangeNotify(Player player, ServerBuffChangeType changeType, PlayerBuff buff) {
|
||||
super(PacketOpcodes.ServerBuffChangeNotify);
|
||||
|
||||
var proto = ServerBuffChangeNotify.newBuilder();
|
||||
|
||||
for (EntityAvatar entity : player.getTeamManager().getActiveTeam()) {
|
||||
proto.addAvatarGuidList(entity.getAvatar().getGuid());
|
||||
}
|
||||
|
||||
proto.setServerBuffChangeType(changeType);
|
||||
proto.addServerBuffList(buff.toProto());
|
||||
|
||||
this.setData(proto);
|
||||
this(player, changeType, Stream.of(buff));
|
||||
}
|
||||
|
||||
public PacketServerBuffChangeNotify(Player player, ServerBuffChangeType changeType, Collection<PlayerBuff> buffs) {
|
||||
this(player, changeType, buffs.stream());
|
||||
}
|
||||
|
||||
public PacketServerBuffChangeNotify(Player player, ServerBuffChangeType changeType, Stream<PlayerBuff> buffs) {
|
||||
super(PacketOpcodes.ServerBuffChangeNotify);
|
||||
|
||||
var proto = ServerBuffChangeNotify.newBuilder();
|
||||
|
||||
for (EntityAvatar entity : player.getTeamManager().getActiveTeam()) {
|
||||
proto.addAvatarGuidList(entity.getAvatar().getGuid());
|
||||
}
|
||||
player.getTeamManager().getActiveTeam().stream()
|
||||
.mapToLong(entity -> entity.getAvatar().getGuid())
|
||||
.forEach(proto::addAvatarGuidList);
|
||||
|
||||
proto.setServerBuffChangeType(changeType);
|
||||
proto.addAllServerBuffList(buffs.stream().map(PlayerBuff::toProto).toList());
|
||||
buffs.map(PlayerBuff::toProto)
|
||||
.forEach(proto::addServerBuffList);
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
@ -1,174 +1,174 @@
|
||||
package emu.grasscutter.task;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
|
||||
import org.quartz.*;
|
||||
import org.quartz.impl.StdSchedulerFactory;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings({"UnusedReturnValue", "unused"})
|
||||
public final class TaskMap {
|
||||
private final Map<String, TaskHandler> tasks = new HashMap<>();
|
||||
private final Map<String, Task> annotations = new HashMap<>();
|
||||
private final Map<String, TaskHandler> afterReset = new HashMap<>();
|
||||
private final SchedulerFactory schedulerFactory = new StdSchedulerFactory();
|
||||
|
||||
public TaskMap() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public TaskMap(boolean scan) {
|
||||
if (scan) this.scan();
|
||||
}
|
||||
|
||||
public static TaskMap getInstance() {
|
||||
return Grasscutter.getGameServer().getTaskMap();
|
||||
}
|
||||
|
||||
public void resetNow() {
|
||||
// Unregister all tasks
|
||||
for (TaskHandler task : this.tasks.values()) {
|
||||
unregisterTask(task);
|
||||
}
|
||||
|
||||
// Run all afterReset tasks
|
||||
for (TaskHandler task : this.afterReset.values()) {
|
||||
try {
|
||||
task.restartExecute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all afterReset tasks
|
||||
this.afterReset.clear();
|
||||
|
||||
// Register all tasks
|
||||
for (TaskHandler task : this.tasks.values()) {
|
||||
registerTask(task.getClass().getAnnotation(Task.class).taskName(), task);
|
||||
}
|
||||
}
|
||||
|
||||
public TaskMap unregisterTask(TaskHandler task) {
|
||||
this.tasks.remove(task.getClass().getAnnotation(Task.class).taskName());
|
||||
this.annotations.remove(task.getClass().getAnnotation(Task.class).taskName());
|
||||
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
scheduler.deleteJob(new JobKey(task.getClass().getAnnotation(Task.class).taskName()));
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
task.onDisable();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean pauseTask(String taskName) {
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
scheduler.pauseJob(new JobKey(taskName));
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean resumeTask(String taskName) {
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
scheduler.resumeJob(new JobKey(taskName));
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean cancelTask(String taskName) {
|
||||
Task task = this.annotations.get(taskName);
|
||||
if (task == null) return false;
|
||||
try {
|
||||
this.unregisterTask(this.tasks.get(taskName));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public TaskMap registerTask(String taskName, TaskHandler task) {
|
||||
Task annotation = task.getClass().getAnnotation(Task.class);
|
||||
this.annotations.put(taskName, annotation);
|
||||
this.tasks.put(taskName, task);
|
||||
|
||||
// register task
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
JobDetail job = JobBuilder
|
||||
.newJob(task.getClass())
|
||||
.withIdentity(taskName)
|
||||
.build();
|
||||
|
||||
Trigger convTrigger = TriggerBuilder.newTrigger()
|
||||
.withIdentity(annotation.triggerName())
|
||||
.withSchedule(CronScheduleBuilder.cronSchedule(annotation.taskCronExpression()))
|
||||
.build();
|
||||
|
||||
scheduler.scheduleJob(job, convTrigger);
|
||||
|
||||
if (annotation.executeImmediately()) {
|
||||
task.execute(null);
|
||||
}
|
||||
task.onEnable();
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<TaskHandler> getHandlersAsList() {
|
||||
return new LinkedList<>(this.tasks.values());
|
||||
}
|
||||
|
||||
public HashMap<String, TaskHandler> getHandlers() {
|
||||
return new LinkedHashMap<>(this.tasks);
|
||||
}
|
||||
|
||||
public TaskHandler getHandler(String taskName) {
|
||||
return this.tasks.get(taskName);
|
||||
}
|
||||
|
||||
private void scan() {
|
||||
Reflections reflector = Grasscutter.reflector;
|
||||
Set<Class<?>> classes = reflector.getTypesAnnotatedWith(Task.class);
|
||||
classes.forEach(annotated -> {
|
||||
try {
|
||||
Task taskData = annotated.getAnnotation(Task.class);
|
||||
Object object = annotated.getDeclaredConstructor().newInstance();
|
||||
if (object instanceof TaskHandler) {
|
||||
this.registerTask(taskData.taskName(), (TaskHandler) object);
|
||||
if (taskData.executeImmediatelyAfterReset()) {
|
||||
this.afterReset.put(taskData.taskName(), (TaskHandler) object);
|
||||
}
|
||||
} else {
|
||||
Grasscutter.getLogger().error("Class " + annotated.getName() + " is not a TaskHandler!");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Grasscutter.getLogger().error("Failed to register task handler for " + annotated.getSimpleName(), exception);
|
||||
}
|
||||
});
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
scheduler.start();
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
package emu.grasscutter.task;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
|
||||
import org.quartz.*;
|
||||
import org.quartz.impl.StdSchedulerFactory;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings({"UnusedReturnValue", "unused"})
|
||||
public final class TaskMap {
|
||||
private final Map<String, TaskHandler> tasks = new HashMap<>();
|
||||
private final Map<String, Task> annotations = new HashMap<>();
|
||||
private final Map<String, TaskHandler> afterReset = new HashMap<>();
|
||||
private final SchedulerFactory schedulerFactory = new StdSchedulerFactory();
|
||||
|
||||
public TaskMap() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public TaskMap(boolean scan) {
|
||||
if (scan) this.scan();
|
||||
}
|
||||
|
||||
public static TaskMap getInstance() {
|
||||
return Grasscutter.getGameServer().getTaskMap();
|
||||
}
|
||||
|
||||
public void resetNow() {
|
||||
// Unregister all tasks
|
||||
for (TaskHandler task : this.tasks.values()) {
|
||||
unregisterTask(task);
|
||||
}
|
||||
|
||||
// Run all afterReset tasks
|
||||
for (TaskHandler task : this.afterReset.values()) {
|
||||
try {
|
||||
task.restartExecute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all afterReset tasks
|
||||
this.afterReset.clear();
|
||||
|
||||
// Register all tasks
|
||||
for (TaskHandler task : this.tasks.values()) {
|
||||
registerTask(task.getClass().getAnnotation(Task.class).taskName(), task);
|
||||
}
|
||||
}
|
||||
|
||||
public TaskMap unregisterTask(TaskHandler task) {
|
||||
this.tasks.remove(task.getClass().getAnnotation(Task.class).taskName());
|
||||
this.annotations.remove(task.getClass().getAnnotation(Task.class).taskName());
|
||||
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
scheduler.deleteJob(new JobKey(task.getClass().getAnnotation(Task.class).taskName()));
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
task.onDisable();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean pauseTask(String taskName) {
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
scheduler.pauseJob(new JobKey(taskName));
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean resumeTask(String taskName) {
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
scheduler.resumeJob(new JobKey(taskName));
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean cancelTask(String taskName) {
|
||||
Task task = this.annotations.get(taskName);
|
||||
if (task == null) return false;
|
||||
try {
|
||||
this.unregisterTask(this.tasks.get(taskName));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public TaskMap registerTask(String taskName, TaskHandler task) {
|
||||
Task annotation = task.getClass().getAnnotation(Task.class);
|
||||
this.annotations.put(taskName, annotation);
|
||||
this.tasks.put(taskName, task);
|
||||
|
||||
// register task
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
JobDetail job = JobBuilder
|
||||
.newJob(task.getClass())
|
||||
.withIdentity(taskName)
|
||||
.build();
|
||||
|
||||
Trigger convTrigger = TriggerBuilder.newTrigger()
|
||||
.withIdentity(annotation.triggerName())
|
||||
.withSchedule(CronScheduleBuilder.cronSchedule(annotation.taskCronExpression()))
|
||||
.build();
|
||||
|
||||
scheduler.scheduleJob(job, convTrigger);
|
||||
|
||||
if (annotation.executeImmediately()) {
|
||||
task.execute(null);
|
||||
}
|
||||
task.onEnable();
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<TaskHandler> getHandlersAsList() {
|
||||
return new ArrayList<>(this.tasks.values());
|
||||
}
|
||||
|
||||
public HashMap<String, TaskHandler> getHandlers() {
|
||||
return new LinkedHashMap<>(this.tasks);
|
||||
}
|
||||
|
||||
public TaskHandler getHandler(String taskName) {
|
||||
return this.tasks.get(taskName);
|
||||
}
|
||||
|
||||
private void scan() {
|
||||
Reflections reflector = Grasscutter.reflector;
|
||||
Set<Class<?>> classes = reflector.getTypesAnnotatedWith(Task.class);
|
||||
classes.forEach(annotated -> {
|
||||
try {
|
||||
Task taskData = annotated.getAnnotation(Task.class);
|
||||
Object object = annotated.getDeclaredConstructor().newInstance();
|
||||
if (object instanceof TaskHandler) {
|
||||
this.registerTask(taskData.taskName(), (TaskHandler) object);
|
||||
if (taskData.executeImmediatelyAfterReset()) {
|
||||
this.afterReset.put(taskData.taskName(), (TaskHandler) object);
|
||||
}
|
||||
} else {
|
||||
Grasscutter.getLogger().error("Class " + annotated.getName() + " is not a TaskHandler!");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Grasscutter.getLogger().error("Failed to register task handler for " + annotated.getSimpleName(), exception);
|
||||
}
|
||||
});
|
||||
try {
|
||||
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||
scheduler.start();
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package emu.grasscutter.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
@ -8,6 +10,7 @@ import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
|
||||
@ -36,14 +39,21 @@ public final class Crypto {
|
||||
CUR_SIGNING_KEY = KeyFactory.getInstance("RSA")
|
||||
.generatePrivate(new PKCS8EncodedKeySpec(FileUtils.readResource("/keys/SigningKey.der")));
|
||||
|
||||
var CNRelSign = KeyFactory.getInstance("RSA")
|
||||
.generatePublic(new X509EncodedKeySpec(FileUtils.readResource("/keys/CNRel_Pub.der")));
|
||||
Pattern pattern = Pattern.compile("([0-9]*)_Pub\\.der");
|
||||
for (Path path : FileUtils.getPathsFromResource("/keys/game_keys")) {
|
||||
if (path.toString().endsWith("_Pub.der")) {
|
||||
|
||||
var OSRelSign = KeyFactory.getInstance("RSA")
|
||||
.generatePublic(new X509EncodedKeySpec(FileUtils.readResource("/keys/OSRel_Pub.der")));
|
||||
var m = pattern.matcher(path.getFileName().toString());
|
||||
|
||||
EncryptionKeys.put(2, CNRelSign);
|
||||
EncryptionKeys.put(3, OSRelSign);
|
||||
if (m.matches())
|
||||
{
|
||||
var key = KeyFactory.getInstance("RSA")
|
||||
.generatePublic(new X509EncodedKeySpec(FileUtils.read(path)));
|
||||
|
||||
EncryptionKeys.put(Integer.valueOf(m.group(1)), key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Grasscutter.getLogger().error("An error occurred while loading keys.", e);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package emu.grasscutter.utils;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import lombok.val;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -87,6 +88,22 @@ public final class FileUtils {
|
||||
: Path.of(scripts);
|
||||
};
|
||||
|
||||
private static final String[] TSJ_JSON_TSV = {"tsj", "json", "tsv"};
|
||||
private static final Path[] DATA_PATHS = {DATA_USER_PATH, DATA_DEFAULT_PATH};
|
||||
public static Path getDataPathTsjJsonTsv(String filename) {
|
||||
return getDataPathTsjJsonTsv(filename, true);
|
||||
}
|
||||
public static Path getDataPathTsjJsonTsv(String filename, boolean fallback) {
|
||||
val name = getFilenameWithoutExtension(filename);
|
||||
for (val data_path : DATA_PATHS) {
|
||||
for (val ext : TSJ_JSON_TSV) {
|
||||
val path = data_path.resolve(name + "." + ext);
|
||||
if (Files.exists(path)) return path;
|
||||
}
|
||||
}
|
||||
return fallback ? DATA_USER_PATH.resolve(name + ".tsj") : null; // Maybe they want to write to a new file
|
||||
}
|
||||
|
||||
public static Path getDataPath(String path) {
|
||||
Path userPath = DATA_USER_PATH.resolve(path);
|
||||
if (Files.exists(userPath)) return userPath;
|
||||
@ -111,6 +128,22 @@ public final class FileUtils {
|
||||
return RESOURCES_PATH.resolve(path);
|
||||
}
|
||||
|
||||
public static Path getExcelPath(String filename) {
|
||||
return getTsjJsonTsv(RESOURCES_PATH.resolve("ExcelBinOutput"), filename);
|
||||
}
|
||||
|
||||
// Gets path of a resource.
|
||||
// If multiple formats of it exist, priority is TSJ > JSON > TSV
|
||||
// If none exist, return the TSJ path, in case it wants to create a file
|
||||
public static Path getTsjJsonTsv(Path root, String filename) {
|
||||
val name = getFilenameWithoutExtension(filename);
|
||||
for (val ext : TSJ_JSON_TSV) {
|
||||
val path = root.resolve(name + "." + ext);
|
||||
if (Files.exists(path)) return path;
|
||||
}
|
||||
return root.resolve(name + ".tsj");
|
||||
}
|
||||
|
||||
public static Path getScriptPath(String path) {
|
||||
return SCRIPTS_PATH.resolve(path);
|
||||
}
|
||||
@ -167,14 +200,19 @@ public final class FileUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated // No current uses of this anyway
|
||||
public static String getFilenameWithoutPath(String fileName) {
|
||||
int i = fileName.lastIndexOf(".");
|
||||
if (i > 0) {
|
||||
return fileName.substring(0, i);
|
||||
} else {
|
||||
return fileName;
|
||||
}
|
||||
@Deprecated // Misnamed legacy function
|
||||
public static String getFilenameWithoutPath(String filename) {
|
||||
return getFilenameWithoutExtension(filename);
|
||||
}
|
||||
public static String getFilenameWithoutExtension(String filename) {
|
||||
int i = filename.lastIndexOf(".");
|
||||
return (i < 0) ? filename : filename.substring(0, i);
|
||||
}
|
||||
|
||||
public static String getFileExtension(Path path) {
|
||||
val filename = path.toString();
|
||||
int i = filename.lastIndexOf(".");
|
||||
return (i < 0) ? "" : filename.substring(i+1);
|
||||
}
|
||||
|
||||
public static List<Path> getPathsFromResource(String folder) throws URISyntaxException {
|
||||
|
@ -10,6 +10,7 @@ import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
@ -17,6 +18,7 @@ import emu.grasscutter.data.common.DynamicFloat;
|
||||
import emu.grasscutter.game.quest.enums.QuestCond;
|
||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||
import emu.grasscutter.game.quest.enums.QuestExec;
|
||||
import it.unimi.dsi.fastutil.floats.FloatArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.val;
|
||||
@ -69,7 +71,54 @@ public class JsonAdapters {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter writer, IntList i) {};
|
||||
public void write(JsonWriter writer, IntList l) throws IOException {
|
||||
writer.beginArray();
|
||||
for (val i : l) // .forEach() doesn't appreciate exceptions
|
||||
writer.value(i);
|
||||
writer.endArray();
|
||||
};
|
||||
}
|
||||
|
||||
static class PositionAdapter extends TypeAdapter<Position> {
|
||||
@Override
|
||||
public Position read(JsonReader reader) throws IOException {
|
||||
switch (reader.peek()) {
|
||||
case BEGIN_ARRAY: // "pos": [x,y,z]
|
||||
reader.beginArray();
|
||||
val array = new FloatArrayList(3);
|
||||
while (reader.hasNext())
|
||||
array.add(reader.nextInt());
|
||||
reader.endArray();
|
||||
return new Position(array);
|
||||
case BEGIN_OBJECT: // "pos": {"x": x, "y": y, "z": z}
|
||||
float x = 0f;
|
||||
float y = 0f;
|
||||
float z = 0f;
|
||||
reader.beginObject();
|
||||
for (var next = reader.peek(); next != JsonToken.END_OBJECT; next = reader.peek()) {
|
||||
val name = reader.nextName();
|
||||
switch (name) {
|
||||
case "x", "X", "_x" -> x = (float) reader.nextDouble();
|
||||
case "y", "Y", "_y" -> y = (float) reader.nextDouble();
|
||||
case "z", "Z", "_z" -> z = (float) reader.nextDouble();
|
||||
default -> throw new IOException("Invalid field in Position definition - " + name);
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
return new Position(x, y, z);
|
||||
default:
|
||||
throw new IOException("Invalid Position definition - " + reader.peek().name());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter writer, Position i) throws IOException {
|
||||
writer.beginArray();
|
||||
writer.value(i.getX());
|
||||
writer.value(i.getY());
|
||||
writer.value(i.getZ());
|
||||
writer.endArray();
|
||||
};
|
||||
}
|
||||
|
||||
static class QuestAcceptConditionAdapter extends QuestEnumAdapter<QuestCond> {
|
||||
@ -120,37 +169,32 @@ public class JsonAdapters {
|
||||
static class EnumTypeAdapterFactory implements TypeAdapterFactory {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
Class<T> rawType = (Class<T>) type.getRawType();
|
||||
if (!rawType.isEnum()) return null;
|
||||
|
||||
Field id = null;
|
||||
// System.out.println("Looking for enum value field");
|
||||
for (Field f : rawType.getDeclaredFields()) {
|
||||
id = switch (f.getName()) {
|
||||
case "value", "id" -> f;
|
||||
default -> null;
|
||||
};
|
||||
if (id != null) break;
|
||||
}
|
||||
if (id == null) {
|
||||
// System.out.println("Not found");
|
||||
return null;
|
||||
}
|
||||
// System.out.println("Enum value field found - " + id.getName());
|
||||
Class<T> enumClass = (Class<T>) type.getRawType();
|
||||
if (!enumClass.isEnum()) return null;
|
||||
|
||||
// Make mappings of (string) names to enum constants
|
||||
val map = new HashMap<String, T>();
|
||||
boolean acc = id.isAccessible();
|
||||
id.setAccessible(true);
|
||||
try {
|
||||
for (T constant : rawType.getEnumConstants()) {
|
||||
map.put(constant.toString(), constant);
|
||||
map.put(String.valueOf(id.getInt(constant)), constant);
|
||||
val enumConstants = enumClass.getEnumConstants();
|
||||
for (val constant : enumConstants)
|
||||
map.put(constant.toString(), constant);
|
||||
|
||||
// If the enum also has a numeric value, map those to the constants too
|
||||
// System.out.println("Looking for enum value field");
|
||||
for (Field f : enumClass.getDeclaredFields()) {
|
||||
if (switch (f.getName()) {case "value", "id" -> true; default -> false;}) {
|
||||
// System.out.println("Enum value field found - " + f.getName());
|
||||
boolean acc = f.isAccessible();
|
||||
f.setAccessible(true);
|
||||
try {
|
||||
for (val constant : enumConstants)
|
||||
map.put(String.valueOf(f.getInt(constant)), constant);
|
||||
} catch (IllegalAccessException e) {
|
||||
// System.out.println("Failed to access enum id field.");
|
||||
}
|
||||
f.setAccessible(acc);
|
||||
break;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
// System.out.println("Failed to access enum id field.");
|
||||
return null;
|
||||
}
|
||||
id.setAccessible(acc);
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
public T read(JsonReader reader) throws IOException {
|
||||
@ -163,7 +207,9 @@ public class JsonAdapters {
|
||||
throw new IOException("Invalid Enum definition - " + reader.peek().name());
|
||||
}
|
||||
}
|
||||
public void write(JsonWriter writer, T value) {}
|
||||
public void write(JsonWriter writer, T value) throws IOException {
|
||||
writer.value(value.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@ -21,6 +22,7 @@ import emu.grasscutter.game.quest.enums.QuestCond;
|
||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||
import emu.grasscutter.game.quest.enums.QuestExec;
|
||||
import emu.grasscutter.utils.JsonAdapters.*;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
|
||||
public final class JsonUtils {
|
||||
@ -28,6 +30,7 @@ public final class JsonUtils {
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(DynamicFloat.class, new DynamicFloatAdapter())
|
||||
.registerTypeAdapter(IntList.class, new IntListAdapter())
|
||||
.registerTypeAdapter(Position.class, new PositionAdapter())
|
||||
.registerTypeAdapterFactory(new EnumTypeAdapterFactory())
|
||||
.registerTypeAdapter(QuestCond.class, new QuestAcceptConditionAdapter())
|
||||
.registerTypeAdapter(QuestContent.class, new QuestContentAdapter())
|
||||
@ -108,4 +111,12 @@ public final class JsonUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T decode(String jsonData, Type type) {
|
||||
try {
|
||||
return gson.fromJson(jsonData, type);
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user