Merge remote-tracking branch 'origin/development' into development

This commit is contained in:
KingRainbow44 2023-09-13 21:03:44 -04:00
commit ea5ee075a7
No known key found for this signature in database
GPG Key ID: FC2CB64B00D257BE
64 changed files with 1434 additions and 313 deletions

View File

@ -26,7 +26,7 @@
- Get Java 17: https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html - Get Java 17: https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html
- Get [MongoDB Community Server](https://www.mongodb.com/try/download/community) - Get [MongoDB Community Server](https://www.mongodb.com/try/download/community)
- Get game version REL3.7 (3.7 client can be found here if you don't have it): https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/3.7.0.md - Get game version REL4.0.x (4.0.x client can be found here if you don't have it): https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/4.0.0.md
- Download the [latest Cultivation version](https://github.com/Grasscutters/Cultivation/releases/latest). Use the `.msi` installer. - Download the [latest Cultivation version](https://github.com/Grasscutters/Cultivation/releases/latest). Use the `.msi` installer.
- After opening Culivation (as admin), press the download button in the upper right corner. - After opening Culivation (as admin), press the download button in the upper right corner.
@ -46,25 +46,49 @@ Grasscutter uses Gradle to handle dependencies & building.
**Requirements:** **Requirements:**
- [Java SE Development Kits - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) or higher - [Java Development Kit 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) or higher
- [Git](https://git-scm.com/downloads) - [Git](https://git-scm.com/downloads)
- [NodeJS](https://nodejs.org/en/download) (Optional, for building the handbook)
##### Windows ##### Clone
```shell ```shell
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter cd Grasscutter
.\gradlew.bat # Setting up environments
.\gradlew jar # Compile
``` ```
##### Linux (GNU) ##### Compile
**Note**: Handbook generation may fail on some systems. To disable the handbook generation, append `-PskipHandbook=1` to the `gradlew jar` command.
Windows:
```shell
.\gradlew.bat # Setting up environments
.\gradlew jar
```
Linux (GNU):
```bash ```bash
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter
chmod +x gradlew chmod +x gradlew
./gradlew jar # Compile ./gradlew jar
```
##### Compiling the Handbook (Manually)
With Gradle:
```shell
./gradlew generateHandbook
```
With NPM:
```shell
cd src/handbook
npm install
npm run build
``` ```
You can find the output jar in the root of the project folder. You can find the output jar in the root of the project folder.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**תשומת לב בבקשה:** אנחנו מקבלים עזרה בפיתוח התוכנה. לפני שאתם תורמים לפרויקט בבקשה תקראו את [תנאי השימוש](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **תשומת לב בבקשה:** אנחנו מקבלים עזרה בפיתוח התוכנה. לפני שאתם תורמים לפרויקט בבקשה תקראו את [תנאי השימוש](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).

View File

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

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**Atención:** Siempre damos la bienvenida a contribuidores del proyecto. Antes de añadir tu contribución, por favor lee cuidadosamente nuestro [Código de conducta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Atención:** Siempre damos la bienvenida a contribuidores del proyecto. Antes de añadir tu contribución, por favor lee cuidadosamente nuestro [Código de conducta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**Atensyon:** Ang mga kontributor ay laging welcome sa proyektong ito. Bago mag-bigay ng kontribusyon, basahin muna ng mabuti ang [Code of Conduct](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Atensyon:** Ang mga kontributor ay laging welcome sa proyektong ito. Bago mag-bigay ng kontribusyon, basahin muna ng mabuti ang [Code of Conduct](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**Attention:** De nouveaux contributeurs sont toujours les bienvenus. Avant d'ajouter votre contribution, veuillez lire le [code de conduite](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Attention:** De nouveaux contributeurs sont toujours les bienvenus. Avant d'ajouter votre contribution, veuillez lire le [code de conduite](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
@ -71,4 +71,4 @@ Vous pouvez trouver le jar de sortie dans la racine du dossier du projet.
### Dépanage ### Dépanage
Pour une liste des problèmes communs et leur solution et pour demander de l'aide, veuillez rejoindre [notre serveur Discord](https://discord.gg/T5vZU6UyeG) (en anglais) et dirigez vous vers le salon de support. Pour une liste des problèmes communs et leur solution et pour demander de l'aide, veuillez rejoindre [notre serveur Discord](https://discord.gg/T5vZU6UyeG) (en anglais) et dirigez vous vers le salon de support.

78
docs/README_hn-IN.md Normal file
View File

@ -0,0 +1,78 @@
![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/actions/workflow/status/Grasscutters/Grasscutter/build.yml?branch=development&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) | [简中](docs/README_zh-CN.md) | [繁中](docs/README_zh-TW.md) | [FR](docs/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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**ध्यान:** हम हमेशा परियोजना में योगदानकर्ताओं का स्वागत करते हैं।. अपना योगदान जोड़ने से पहले कृपया हमारा ध्यानपूर्वक पढ़ें [आचार संहिता](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
## वर्तमान सुविधाएँ
* लॉग इन करना
* युद्ध
* मित्रों की सूची
* टेलीपोर्टेशन
* गाचा प्रणाली
* सह-ऑप * आंशिक रूप से * काम करता है
* कंसोल के माध्यम से राक्षसों को जन्म देना
* इन्वेंट्री सुविधाएँ (आइटम / वर्ण प्राप्त करना, आइटम / वर्णों को अपग्रेड करना, आदि)
## त्वरित सेटअप गाइड
**टिप्पणी**: समर्थन के लिए कृपया हमसे जुड़ें [Discord](https://discord.gg/T5vZU6UyeG).
### त्वरित प्रारंभ (स्वचालित)
- Get Java 17: https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html
**ध्यान दें:** बस **सर्वर शुरू करने** के लिए, आपको बस **jre** की आवश्यकता है।
- Get [MongoDB Community Server](https://www.mongodb.com/try/download/community)
* प्रॉक्सी: मिटमडंप (अनुशंसित), मिटमप्रॉक्सी, फिडलर क्लासिक, आदि।
- गेम संस्करण REL3.7 प्राप्त करें (यदि आपके पास 3.7 क्लाइंट नहीं है तो उसे यहां पाया जा सकता है):: https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/3.7.0.md
- डाउनलोड करें [latest Cultivation version](https://github.com/Grasscutters/Cultivation/releases/latest). उपयोग `.msi` इंस्टालरr.
- कलिवेशन (एडमिन के रूप में) खोलने के बाद, ऊपरी दाएं कोने में डाउनलोड बटन दबाएं।
- `डाउनलोड ऑल-इन-वन` पर क्लिक करें
- ऊपरी दाएं कोने में गियर पर क्लिक करें
- गेम इंस्टॉल पथ को उस स्थान पर सेट करें जहां आपका गेम स्थित है.
- कस्टम जावा पथ को इस पर सेट करें `C:\Program Files\Java\jdk-17\bin\java.exe`
- अन्य सभी सेटिंग्स को डिफ़ॉल्ट पर छोड़ दें
- लॉन्च करने के लिए आगे छोटे बटन पर क्लिक करें.
- लॉन्च बटन पर क्लिक करें.
- आप जो भी उपयोगकर्ता नाम चाहते हैं उसके साथ लॉग इन करें। पासवर्ड कोई मायने नहीं रखता.
### इमारत
ग्रासकटर निर्भरता और निर्माण को संभालने के लिए ग्रैडल का उपयोग करता है।
**आवश्यकताएं:**
- [Java SE Development Kits - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) or higher
- [Git](https://git-scm.com/downloads)
##### विंडोज
```shell
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter
.\gradlew.bat # Setting up environments
.\gradlew jar # Compile
```
##### लिनक्स (जीएनयू)
```bash
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter
chmod +x gradlew
./gradlew jar # Compile
```
आप आउटपुट जार को प्रोजेक्ट फ़ोल्डर के रूट में पा सकते हैं।.
### समस्या निवारण
सामान्य मुद्दों और समाधानों की सूची और सहायता मांगने के लिए कृपया शामिल हों [our Discord server](https://discord.gg/T5vZU6UyeG) और सपोर्ट चैनल पर जाएं.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**Perhatian:** Kami selalu menyambut kontributor untuk proyek ini. Sebelum menambahkan kontribusi Anda, harap baca [Kode Etik](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md) kami. **Perhatian:** Kami selalu menyambut kontributor untuk proyek ini. Sebelum menambahkan kontribusi Anda, harap baca [Kode Etik](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md) kami.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**Attenzione:** Diamo sempre il benvenuto ai contributori del progetto. Prima di contribuire, leggi attentamente il nostro [Codice di condotta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Attenzione:** Diamo sempre il benvenuto ai contributori del progetto. Prima di contribuire, leggi attentamente il nostro [Codice di condotta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**:** 私たちはプロジェクトへの貢献者をいつでも歓迎します。貢献を追加する前に、我々の [行動規範](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)をよくお読みください。 **:** 私たちはプロジェクトへの貢献者をいつでも歓迎します。貢献を追加する前に、我々の [行動規範](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)をよくお読みください。

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**주의 :** 우리는 항상 프로젝트에 기여하는 사람들을 환영합니다. 기여를 하기 전, [행동 지침](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)을 주의 깊게 읽어주세요. **주의 :** 우리는 항상 프로젝트에 기여하는 사람들을 환영합니다. 기여를 하기 전, [행동 지침](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)을 주의 깊게 읽어주세요.

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**Uwaga:** Zawsze jesteśmy otwarci na wasz wkład w projekt. Przed zaproponowaniem zmian przeczytaj [zasady postępowania (ENG)](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Uwaga:** Zawsze jesteśmy otwarci na wasz wkład w projekt. Przed zaproponowaniem zmian przeczytaj [zasady postępowania (ENG)](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**Внимание:** Мы всегда рады новому вкладу в проект. Однако, перед тем, как сделать свой вклад, пожалуйста, прочтите наш [кодекс делового поведения](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Внимание:** Мы всегда рады новому вкладу в проект. Однако, перед тем, как сделать свой вклад, пожалуйста, прочтите наш [кодекс делового поведения](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**Chú ý:** Chúng tôi luôn chào đón những người đóng góp cho dự án. Trước khi đóng góp, xin vui lòng đọc kỹ ["các quy tắc" (Code of Conduct)](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md) của chúng tôi . **Chú ý:** Chúng tôi luôn chào đón những người đóng góp cho dự án. Trước khi đóng góp, xin vui lòng đọc kỹ ["các quy tắc" (Code of Conduct)](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md) của chúng tôi .

View File

@ -3,7 +3,7 @@
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.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) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
**注意:** 我们始终欢迎项目的贡献者。但在做贡献之前,请仔细阅读我们的[代码规范](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)。 **注意:** 我们始终欢迎项目的贡献者。但在做贡献之前,请仔细阅读我们的[代码规范](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)。
@ -26,7 +26,7 @@
- 获取Java 17https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html - 获取Java 17https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html
- 获取[MongoDB社区版](https://www.mongodb.com/try/download/community) - 获取[MongoDB社区版](https://www.mongodb.com/try/download/community)
- 获取游戏3.7正式版 (如果你没有3.7的客户端可以在这里找到https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/3.7.0.md) - 获取游戏4.0正式版 (如果你没有4.0的客户端可以在这里找到https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/4.0.0.md)
- 下载[最新的Cultivation版本](https://github.com/Grasscutters/Cultivation/releases/latest)(使用以“.msi”为后缀的安装包 - 下载[最新的Cultivation版本](https://github.com/Grasscutters/Cultivation/releases/latest)(使用以“.msi”为后缀的安装包
- 以管理员身份打开Culivation按右上角的下载按钮。 - 以管理员身份打开Culivation按右上角的下载按钮。

View File

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

View File

@ -36,21 +36,21 @@ public final class HomePlantSubFieldDataOuterClass {
int getEntityIdList(int index); int getEntityIdList(int index);
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @return The enum numeric value on the wire for cAKDDMKAIMD. * @return The enum numeric value on the wire for status.
*/ */
int getCAKDDMKAIMDValue(); int getStatusValue();
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @return The cAKDDMKAIMD. * @return The status.
*/ */
emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getCAKDDMKAIMD(); emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getStatus();
/** /**
* <code>uint32 JHFNDBIHLNB = 8;</code> * <code>uint32 seed_id = 8;</code>
* @return The jHFNDBIHLNB. * @return The seedId.
*/ */
int getJHFNDBIHLNB(); int getSeedId();
/** /**
* <code>fixed32 end_time = 14;</code> * <code>fixed32 end_time = 14;</code>
@ -59,10 +59,10 @@ public final class HomePlantSubFieldDataOuterClass {
int getEndTime(); int getEndTime();
/** /**
* <code>uint32 KHFGOPCOAGM = 3;</code> * <code>uint32 gather_point_type = 3;</code>
* @return The kHFGOPCOAGM. * @return The gatherPointType.
*/ */
int getKHFGOPCOAGM(); int getGatherPointType();
} }
/** /**
* <pre> * <pre>
@ -82,7 +82,7 @@ public final class HomePlantSubFieldDataOuterClass {
} }
private HomePlantSubFieldData() { private HomePlantSubFieldData() {
entityIdList_ = emptyIntList(); entityIdList_ = emptyIntList();
cAKDDMKAIMD_ = 0; status_ = 0;
} }
@java.lang.Override @java.lang.Override
@ -118,7 +118,7 @@ public final class HomePlantSubFieldDataOuterClass {
break; break;
case 24: { case 24: {
kHFGOPCOAGM_ = input.readUInt32(); gatherPointType_ = input.readUInt32();
break; break;
} }
case 48: { case 48: {
@ -145,12 +145,12 @@ public final class HomePlantSubFieldDataOuterClass {
case 56: { case 56: {
int rawValue = input.readEnum(); int rawValue = input.readEnum();
cAKDDMKAIMD_ = rawValue; status_ = rawValue;
break; break;
} }
case 64: { case 64: {
jHFNDBIHLNB_ = input.readUInt32(); seedId_ = input.readUInt32();
break; break;
} }
case 117: { case 117: {
@ -221,34 +221,34 @@ public final class HomePlantSubFieldDataOuterClass {
} }
private int entityIdListMemoizedSerializedSize = -1; private int entityIdListMemoizedSerializedSize = -1;
public static final int CAKDDMKAIMD_FIELD_NUMBER = 7; public static final int STATUS_FIELD_NUMBER = 7;
private int cAKDDMKAIMD_; private int status_;
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @return The enum numeric value on the wire for cAKDDMKAIMD. * @return The enum numeric value on the wire for status.
*/ */
@java.lang.Override public int getCAKDDMKAIMDValue() { @java.lang.Override public int getStatusValue() {
return cAKDDMKAIMD_; return status_;
} }
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @return The cAKDDMKAIMD. * @return The status.
*/ */
@java.lang.Override public emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getCAKDDMKAIMD() { @java.lang.Override public emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getStatus() {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus result = emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.valueOf(cAKDDMKAIMD_); emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus result = emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.valueOf(status_);
return result == null ? emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.UNRECOGNIZED : result; return result == null ? emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.UNRECOGNIZED : result;
} }
public static final int JHFNDBIHLNB_FIELD_NUMBER = 8; public static final int SEED_ID_FIELD_NUMBER = 8;
private int jHFNDBIHLNB_; private int seedId_;
/** /**
* <code>uint32 JHFNDBIHLNB = 8;</code> * <code>uint32 seed_id = 8;</code>
* @return The jHFNDBIHLNB. * @return The seedId.
*/ */
@java.lang.Override @java.lang.Override
public int getJHFNDBIHLNB() { public int getSeedId() {
return jHFNDBIHLNB_; return seedId_;
} }
public static final int END_TIME_FIELD_NUMBER = 14; public static final int END_TIME_FIELD_NUMBER = 14;
@ -262,15 +262,15 @@ public final class HomePlantSubFieldDataOuterClass {
return endTime_; return endTime_;
} }
public static final int KHFGOPCOAGM_FIELD_NUMBER = 3; public static final int GATHER_POINT_TYPE_FIELD_NUMBER = 3;
private int kHFGOPCOAGM_; private int gatherPointType_;
/** /**
* <code>uint32 KHFGOPCOAGM = 3;</code> * <code>uint32 gather_point_type = 3;</code>
* @return The kHFGOPCOAGM. * @return The gatherPointType.
*/ */
@java.lang.Override @java.lang.Override
public int getKHFGOPCOAGM() { public int getGatherPointType() {
return kHFGOPCOAGM_; return gatherPointType_;
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
@ -288,8 +288,8 @@ public final class HomePlantSubFieldDataOuterClass {
public void writeTo(com.google.protobuf.CodedOutputStream output) public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException { throws java.io.IOException {
getSerializedSize(); getSerializedSize();
if (kHFGOPCOAGM_ != 0) { if (gatherPointType_ != 0) {
output.writeUInt32(3, kHFGOPCOAGM_); output.writeUInt32(3, gatherPointType_);
} }
if (getEntityIdListList().size() > 0) { if (getEntityIdListList().size() > 0) {
output.writeUInt32NoTag(50); output.writeUInt32NoTag(50);
@ -298,11 +298,11 @@ public final class HomePlantSubFieldDataOuterClass {
for (int i = 0; i < entityIdList_.size(); i++) { for (int i = 0; i < entityIdList_.size(); i++) {
output.writeUInt32NoTag(entityIdList_.getInt(i)); output.writeUInt32NoTag(entityIdList_.getInt(i));
} }
if (cAKDDMKAIMD_ != emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.HOME_FIELD_STATUE_NONE.getNumber()) { if (status_ != emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.HOME_FIELD_STATUE_NONE.getNumber()) {
output.writeEnum(7, cAKDDMKAIMD_); output.writeEnum(7, status_);
} }
if (jHFNDBIHLNB_ != 0) { if (seedId_ != 0) {
output.writeUInt32(8, jHFNDBIHLNB_); output.writeUInt32(8, seedId_);
} }
if (endTime_ != 0) { if (endTime_ != 0) {
output.writeFixed32(14, endTime_); output.writeFixed32(14, endTime_);
@ -316,9 +316,9 @@ public final class HomePlantSubFieldDataOuterClass {
if (size != -1) return size; if (size != -1) return size;
size = 0; size = 0;
if (kHFGOPCOAGM_ != 0) { if (gatherPointType_ != 0) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(3, kHFGOPCOAGM_); .computeUInt32Size(3, gatherPointType_);
} }
{ {
int dataSize = 0; int dataSize = 0;
@ -334,13 +334,13 @@ public final class HomePlantSubFieldDataOuterClass {
} }
entityIdListMemoizedSerializedSize = dataSize; entityIdListMemoizedSerializedSize = dataSize;
} }
if (cAKDDMKAIMD_ != emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.HOME_FIELD_STATUE_NONE.getNumber()) { if (status_ != emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.HOME_FIELD_STATUE_NONE.getNumber()) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeEnumSize(7, cAKDDMKAIMD_); .computeEnumSize(7, status_);
} }
if (jHFNDBIHLNB_ != 0) { if (seedId_ != 0) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(8, jHFNDBIHLNB_); .computeUInt32Size(8, seedId_);
} }
if (endTime_ != 0) { if (endTime_ != 0) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
@ -363,13 +363,13 @@ public final class HomePlantSubFieldDataOuterClass {
if (!getEntityIdListList() if (!getEntityIdListList()
.equals(other.getEntityIdListList())) return false; .equals(other.getEntityIdListList())) return false;
if (cAKDDMKAIMD_ != other.cAKDDMKAIMD_) return false; if (status_ != other.status_) return false;
if (getJHFNDBIHLNB() if (getSeedId()
!= other.getJHFNDBIHLNB()) return false; != other.getSeedId()) return false;
if (getEndTime() if (getEndTime()
!= other.getEndTime()) return false; != other.getEndTime()) return false;
if (getKHFGOPCOAGM() if (getGatherPointType()
!= other.getKHFGOPCOAGM()) return false; != other.getGatherPointType()) return false;
if (!unknownFields.equals(other.unknownFields)) return false; if (!unknownFields.equals(other.unknownFields)) return false;
return true; return true;
} }
@ -385,14 +385,14 @@ public final class HomePlantSubFieldDataOuterClass {
hash = (37 * hash) + ENTITY_ID_LIST_FIELD_NUMBER; hash = (37 * hash) + ENTITY_ID_LIST_FIELD_NUMBER;
hash = (53 * hash) + getEntityIdListList().hashCode(); hash = (53 * hash) + getEntityIdListList().hashCode();
} }
hash = (37 * hash) + CAKDDMKAIMD_FIELD_NUMBER; hash = (37 * hash) + STATUS_FIELD_NUMBER;
hash = (53 * hash) + cAKDDMKAIMD_; hash = (53 * hash) + status_;
hash = (37 * hash) + JHFNDBIHLNB_FIELD_NUMBER; hash = (37 * hash) + SEED_ID_FIELD_NUMBER;
hash = (53 * hash) + getJHFNDBIHLNB(); hash = (53 * hash) + getSeedId();
hash = (37 * hash) + END_TIME_FIELD_NUMBER; hash = (37 * hash) + END_TIME_FIELD_NUMBER;
hash = (53 * hash) + getEndTime(); hash = (53 * hash) + getEndTime();
hash = (37 * hash) + KHFGOPCOAGM_FIELD_NUMBER; hash = (37 * hash) + GATHER_POINT_TYPE_FIELD_NUMBER;
hash = (53 * hash) + getKHFGOPCOAGM(); hash = (53 * hash) + getGatherPointType();
hash = (29 * hash) + unknownFields.hashCode(); hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash; memoizedHashCode = hash;
return hash; return hash;
@ -532,13 +532,13 @@ public final class HomePlantSubFieldDataOuterClass {
super.clear(); super.clear();
entityIdList_ = emptyIntList(); entityIdList_ = emptyIntList();
bitField0_ = (bitField0_ & ~0x00000001); bitField0_ = (bitField0_ & ~0x00000001);
cAKDDMKAIMD_ = 0; status_ = 0;
jHFNDBIHLNB_ = 0; seedId_ = 0;
endTime_ = 0; endTime_ = 0;
kHFGOPCOAGM_ = 0; gatherPointType_ = 0;
return this; return this;
} }
@ -572,10 +572,10 @@ public final class HomePlantSubFieldDataOuterClass {
bitField0_ = (bitField0_ & ~0x00000001); bitField0_ = (bitField0_ & ~0x00000001);
} }
result.entityIdList_ = entityIdList_; result.entityIdList_ = entityIdList_;
result.cAKDDMKAIMD_ = cAKDDMKAIMD_; result.status_ = status_;
result.jHFNDBIHLNB_ = jHFNDBIHLNB_; result.seedId_ = seedId_;
result.endTime_ = endTime_; result.endTime_ = endTime_;
result.kHFGOPCOAGM_ = kHFGOPCOAGM_; result.gatherPointType_ = gatherPointType_;
onBuilt(); onBuilt();
return result; return result;
} }
@ -634,17 +634,17 @@ public final class HomePlantSubFieldDataOuterClass {
} }
onChanged(); onChanged();
} }
if (other.cAKDDMKAIMD_ != 0) { if (other.status_ != 0) {
setCAKDDMKAIMDValue(other.getCAKDDMKAIMDValue()); setStatusValue(other.getStatusValue());
} }
if (other.getJHFNDBIHLNB() != 0) { if (other.getSeedId() != 0) {
setJHFNDBIHLNB(other.getJHFNDBIHLNB()); setSeedId(other.getSeedId());
} }
if (other.getEndTime() != 0) { if (other.getEndTime() != 0) {
setEndTime(other.getEndTime()); setEndTime(other.getEndTime());
} }
if (other.getKHFGOPCOAGM() != 0) { if (other.getGatherPointType() != 0) {
setKHFGOPCOAGM(other.getKHFGOPCOAGM()); setGatherPointType(other.getGatherPointType());
} }
this.mergeUnknownFields(other.unknownFields); this.mergeUnknownFields(other.unknownFields);
onChanged(); onChanged();
@ -755,87 +755,87 @@ public final class HomePlantSubFieldDataOuterClass {
return this; return this;
} }
private int cAKDDMKAIMD_ = 0; private int status_ = 0;
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @return The enum numeric value on the wire for cAKDDMKAIMD. * @return The enum numeric value on the wire for status.
*/ */
@java.lang.Override public int getCAKDDMKAIMDValue() { @java.lang.Override public int getStatusValue() {
return cAKDDMKAIMD_; return status_;
} }
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @param value The enum numeric value on the wire for cAKDDMKAIMD to set. * @param value The enum numeric value on the wire for status to set.
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder setCAKDDMKAIMDValue(int value) { public Builder setStatusValue(int value) {
cAKDDMKAIMD_ = value; status_ = value;
onChanged(); onChanged();
return this; return this;
} }
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @return The cAKDDMKAIMD. * @return The status.
*/ */
@java.lang.Override @java.lang.Override
public emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getCAKDDMKAIMD() { public emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getStatus() {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus result = emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.valueOf(cAKDDMKAIMD_); emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus result = emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.valueOf(status_);
return result == null ? emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.UNRECOGNIZED : result; return result == null ? emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.UNRECOGNIZED : result;
} }
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @param value The cAKDDMKAIMD to set. * @param value The status to set.
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder setCAKDDMKAIMD(emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus value) { public Builder setStatus(emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus value) {
if (value == null) { if (value == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
cAKDDMKAIMD_ = value.getNumber(); status_ = value.getNumber();
onChanged(); onChanged();
return this; return this;
} }
/** /**
* <code>.HomePlantFieldStatus CAKDDMKAIMD = 7;</code> * <code>.HomePlantFieldStatus status = 7;</code>
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder clearCAKDDMKAIMD() { public Builder clearStatus() {
cAKDDMKAIMD_ = 0; status_ = 0;
onChanged(); onChanged();
return this; return this;
} }
private int jHFNDBIHLNB_ ; private int seedId_ ;
/** /**
* <code>uint32 JHFNDBIHLNB = 8;</code> * <code>uint32 seed_id = 8;</code>
* @return The jHFNDBIHLNB. * @return The seedId.
*/ */
@java.lang.Override @java.lang.Override
public int getJHFNDBIHLNB() { public int getSeedId() {
return jHFNDBIHLNB_; return seedId_;
} }
/** /**
* <code>uint32 JHFNDBIHLNB = 8;</code> * <code>uint32 seed_id = 8;</code>
* @param value The jHFNDBIHLNB to set. * @param value The seedId to set.
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder setJHFNDBIHLNB(int value) { public Builder setSeedId(int value) {
jHFNDBIHLNB_ = value; seedId_ = value;
onChanged(); onChanged();
return this; return this;
} }
/** /**
* <code>uint32 JHFNDBIHLNB = 8;</code> * <code>uint32 seed_id = 8;</code>
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder clearJHFNDBIHLNB() { public Builder clearSeedId() {
jHFNDBIHLNB_ = 0; seedId_ = 0;
onChanged(); onChanged();
return this; return this;
} }
@ -871,33 +871,33 @@ public final class HomePlantSubFieldDataOuterClass {
return this; return this;
} }
private int kHFGOPCOAGM_ ; private int gatherPointType_ ;
/** /**
* <code>uint32 KHFGOPCOAGM = 3;</code> * <code>uint32 gather_point_type = 3;</code>
* @return The kHFGOPCOAGM. * @return The gatherPointType.
*/ */
@java.lang.Override @java.lang.Override
public int getKHFGOPCOAGM() { public int getGatherPointType() {
return kHFGOPCOAGM_; return gatherPointType_;
} }
/** /**
* <code>uint32 KHFGOPCOAGM = 3;</code> * <code>uint32 gather_point_type = 3;</code>
* @param value The kHFGOPCOAGM to set. * @param value The gatherPointType to set.
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder setKHFGOPCOAGM(int value) { public Builder setGatherPointType(int value) {
kHFGOPCOAGM_ = value; gatherPointType_ = value;
onChanged(); onChanged();
return this; return this;
} }
/** /**
* <code>uint32 KHFGOPCOAGM = 3;</code> * <code>uint32 gather_point_type = 3;</code>
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder clearKHFGOPCOAGM() { public Builder clearGatherPointType() {
kHFGOPCOAGM_ = 0; gatherPointType_ = 0;
onChanged(); onChanged();
return this; return this;
} }
@ -969,12 +969,12 @@ public final class HomePlantSubFieldDataOuterClass {
static { static {
java.lang.String[] descriptorData = { java.lang.String[] descriptorData = {
"\n\033HomePlantSubFieldData.proto\032\032HomePlant" + "\n\033HomePlantSubFieldData.proto\032\032HomePlant" +
"FieldStatus.proto\"\227\001\n\025HomePlantSubFieldD" + "FieldStatus.proto\"\224\001\n\025HomePlantSubFieldD" +
"ata\022\026\n\016entity_id_list\030\006 \003(\r\022*\n\013CAKDDMKAI" + "ata\022\026\n\016entity_id_list\030\006 \003(\r\022%\n\006status\030\007 " +
"MD\030\007 \001(\0162\025.HomePlantFieldStatus\022\023\n\013JHFND" + "\001(\0162\025.HomePlantFieldStatus\022\017\n\007seed_id\030\010 " +
"BIHLNB\030\010 \001(\r\022\020\n\010end_time\030\016 \001(\007\022\023\n\013KHFGOP" + "\001(\r\022\020\n\010end_time\030\016 \001(\007\022\031\n\021gather_point_ty" +
"COAGM\030\003 \001(\rB\033\n\031emu.grasscutter.net.proto" + "pe\030\003 \001(\rB\033\n\031emu.grasscutter.net.protob\006p" +
"b\006proto3" "roto3"
}; };
descriptor = com.google.protobuf.Descriptors.FileDescriptor descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData, .internalBuildGeneratedFileFrom(descriptorData,
@ -986,7 +986,7 @@ public final class HomePlantSubFieldDataOuterClass {
internal_static_HomePlantSubFieldData_fieldAccessorTable = new internal_static_HomePlantSubFieldData_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_HomePlantSubFieldData_descriptor, internal_static_HomePlantSubFieldData_descriptor,
new java.lang.String[] { "EntityIdList", "CAKDDMKAIMD", "JHFNDBIHLNB", "EndTime", "KHFGOPCOAGM", }); new java.lang.String[] { "EntityIdList", "Status", "SeedId", "EndTime", "GatherPointType", });
emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.getDescriptor(); emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.getDescriptor();
} }

View File

@ -286,6 +286,10 @@ public final class GameData {
private static final Int2ObjectMap<HomeWorldBgmData> homeWorldBgmDataMap = private static final Int2ObjectMap<HomeWorldBgmData> homeWorldBgmDataMap =
new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<HomeWorldEventData> homeWorldEventDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap = private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap =
new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();

View File

@ -0,0 +1,38 @@
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.home.suite.event.SuiteEventType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
@ResourceType(name = "HomeWorldEventExcelConfigData.json")
@FieldDefaults(level = AccessLevel.PRIVATE)
@Getter
public class HomeWorldEventData extends GameResource {
@SerializedName(
value = "id",
alternate = {"BBEIIPEFDPE"})
int id;
@SerializedName(
value = "eventType",
alternate = {"JOCKIMECHDP"})
SuiteEventType eventType;
int avatarID;
@SerializedName(
value = "talkId",
alternate = {"IGNJAICDFPD"})
int talkId;
int rewardID;
@SerializedName(
value = "suiteId",
alternate = {"FEHOKMJPOED"})
int suiteId;
}

View File

@ -8,6 +8,7 @@ import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.VisionTypeOuterClass; import emu.grasscutter.net.proto.VisionTypeOuterClass;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.Getter; import lombok.Getter;
public class EntityHomeAnimal extends EntityMonster implements Rebornable { public class EntityHomeAnimal extends EntityMonster implements Rebornable {
@ -15,7 +16,7 @@ public class EntityHomeAnimal extends EntityMonster implements Rebornable {
private final Position rebornPos; private final Position rebornPos;
@Getter private final int rebirth; @Getter private final int rebirth;
@Getter private final int rebirthCD; @Getter private final int rebirthCD;
private boolean disappeared; private final AtomicBoolean disappeared = new AtomicBoolean();
public EntityHomeAnimal(Scene scene, HomeWorldAnimalData data, Position pos) { public EntityHomeAnimal(Scene scene, HomeWorldAnimalData data, Position pos) {
super(scene, GameData.getMonsterDataMap().get(data.getMonsterID()), pos, 1); super(scene, GameData.getMonsterDataMap().get(data.getMonsterID()), pos, 1);
@ -60,13 +61,13 @@ public class EntityHomeAnimal extends EntityMonster implements Rebornable {
new PacketSceneEntityDisappearNotify( new PacketSceneEntityDisappearNotify(
this, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE)); this, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE));
this.rebornCDTickCount = this.getRebornCD(); this.rebornCDTickCount = this.getRebornCD();
this.disappeared = true; this.disappeared.set(true);
} }
@Override @Override
public void reborn() { public void reborn() {
if (this.disappeared) { if (this.disappeared.get()) {
this.disappeared = false; this.disappeared.set(false);
this.getPosition().set(this.getRebornPos()); this.getPosition().set(this.getRebornPos());
this.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(this)); this.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(this));
} }
@ -74,6 +75,6 @@ public class EntityHomeAnimal extends EntityMonster implements Rebornable {
@Override @Override
public boolean isInCD() { public boolean isInCD() {
return this.disappeared; return this.disappeared.get();
} }
} }

View File

@ -17,6 +17,7 @@ import java.time.temporal.ChronoUnit;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -55,6 +56,7 @@ public class GameHome {
Set<Integer> unlockedHomeBgmList; Set<Integer> unlockedHomeBgmList;
int enterHomeOption; int enterHomeOption;
Map<Integer, Set<Integer>> finishedTalkIdMap; Map<Integer, Set<Integer>> finishedTalkIdMap;
Set<Integer> finishedRewardEventIdSet;
public static GameHome getByUid(Integer uid) { public static GameHome getByUid(Integer uid) {
var home = DatabaseHelper.getHomeByUid(uid); var home = DatabaseHelper.getHomeByUid(uid);
@ -62,7 +64,9 @@ public class GameHome {
home = GameHome.create(uid); home = GameHome.create(uid);
} }
home.reassignIfNull();
home.fixMainHouseIfOld(); home.fixMainHouseIfOld();
home.syncHomeAvatarCostume();
return home; return home;
} }
@ -79,9 +83,19 @@ public class GameHome {
.mainHouseMap(new ConcurrentHashMap<>()) .mainHouseMap(new ConcurrentHashMap<>())
.unlockedHomeBgmList(new HashSet<>()) .unlockedHomeBgmList(new HashSet<>())
.finishedTalkIdMap(new HashMap<>()) .finishedTalkIdMap(new HashMap<>())
.finishedRewardEventIdSet(new HashSet<>())
.build(); .build();
} }
// avoid NPE caused by database remover.
private void reassignIfNull() {
this.getSceneMap().values().stream()
.map(HomeSceneItem::getBlockItems)
.map(Map::values)
.flatMap(Collection::stream)
.forEach(HomeBlockItem::reassignIfNull);
}
// Data fixer. // Data fixer.
private void fixMainHouseIfOld() { private void fixMainHouseIfOld() {
if (this.getMainHouseMap() == null) { if (this.getMainHouseMap() == null) {
@ -97,6 +111,18 @@ public class GameHome {
this.save(); this.save();
} }
private void syncHomeAvatarCostume() {
Stream.of(this.sceneMap, this.mainHouseMap)
.map(ConcurrentHashMap::values)
.flatMap(Collection::stream)
.map(HomeSceneItem::getBlockItems)
.map(Map::values)
.flatMap(Collection::stream)
.map(HomeBlockItem::getDeployNPCList)
.flatMap(Collection::stream)
.forEach(npc -> npc.setCostumeId(this.getPlayer().getCostumeFrom(npc.getAvatarId())));
}
public void save() { public void save() {
DatabaseHelper.saveHome(this); DatabaseHelper.saveHome(this);
} }
@ -113,12 +139,12 @@ public class GameHome {
if (defaultItem != null) { if (defaultItem != null) {
Grasscutter.getLogger() Grasscutter.getLogger()
.info("Set player {} home {} to initial setting", ownerUid, sceneId); .info("Set player {} home {} to initial setting", ownerUid, sceneId);
return HomeSceneItem.parseFrom(defaultItem, sceneId);
} else { } else {
// Realm res missing bricks account, use default realm data to allow main house // Realm res missing bricks account, use default realm data to allow main house
defaultItem = GameData.getHomeworldDefaultSaveData().get(2001); defaultItem = GameData.getHomeworldDefaultSaveData().get(2001);
return HomeSceneItem.parseFrom(defaultItem, sceneId);
} }
return HomeSceneItem.parseFrom(defaultItem, sceneId);
}); });
} }
@ -149,6 +175,8 @@ public class GameHome {
this.getMainHouseMap().remove(outdoor); // delete main house in current scene. this.getMainHouseMap().remove(outdoor); // delete main house in current scene.
this.getMainHouseItem(outdoor); // put new main house with default arrangement. this.getMainHouseItem(outdoor); // put new main house with default arrangement.
this.save(); this.save();
this.getPlayer().getCurHomeWorld().getModuleManager().refreshMainHouse();
} }
public void onOwnerLogin(Player player) { public void onOwnerLogin(Player player) {
@ -160,6 +188,8 @@ public class GameHome {
player.getSession().send(new PacketHomeMarkPointNotify(player)); player.getSession().send(new PacketHomeMarkPointNotify(player));
player.getSession().send(new PacketHomeAvatarTalkFinishInfoNotify(player)); player.getSession().send(new PacketHomeAvatarTalkFinishInfoNotify(player));
player.getSession().send(new PacketHomeAllUnlockedBgmIdListNotify(player)); player.getSession().send(new PacketHomeAllUnlockedBgmIdListNotify(player));
player.getSession().send(new PacketHomeAvatarRewardEventNotify(player));
player.getSession().send(new PacketHomeAvatarAllFinishRewardNotify(player));
checkAccumulatedResources(player); checkAccumulatedResources(player);
player.getSession().send(new PacketHomeResourceNotify(player)); player.getSession().send(new PacketHomeResourceNotify(player));
} }
@ -226,6 +256,20 @@ public class GameHome {
.toList(); .toList();
} }
public boolean onClaimAvatarRewards(int eventId) {
if (this.finishedRewardEventIdSet == null) {
this.finishedRewardEventIdSet = new HashSet<>();
}
var success = this.finishedRewardEventIdSet.add(eventId);
this.save();
return success;
}
public boolean isRewardEventFinished(int eventId) {
return this.finishedRewardEventIdSet != null && this.finishedRewardEventIdSet.contains(eventId);
}
public boolean addUnlockedHomeBgm(int homeBgmId) { public boolean addUnlockedHomeBgm(int homeBgmId) {
if (!getUnlockedHomeBgmList().add(homeBgmId)) return false; if (!getUnlockedHomeBgmList().add(homeBgmId)) return false;
@ -404,7 +448,7 @@ public class GameHome {
newCoin = storedCoin + owedCoin; newCoin = storedCoin + owedCoin;
} }
// Ensure max is not exceeded // Ensure max is not exceeded
storedCoin = (maxCoin >= newCoin) ? newCoin : maxCoin; storedCoin = Math.min(maxCoin, newCoin);
} }
// Update fetter exp // Update fetter exp
@ -416,7 +460,7 @@ public class GameHome {
newFetter = storedFetterExp + owedFetter; newFetter = storedFetterExp + owedFetter;
} }
// Ensure max is not exceeded // Ensure max is not exceeded
storedFetterExp = (maxFetter >= newFetter) ? newFetter : maxFetter; storedFetterExp = Math.min(maxFetter, newFetter);
} }
save(); save();

View File

@ -2,6 +2,8 @@ package emu.grasscutter.game.home;
import dev.morphia.annotations.*; import dev.morphia.annotations.*;
import emu.grasscutter.data.binout.HomeworldDefaultSaveData; import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
import emu.grasscutter.game.home.suite.HomeSuiteItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.HomeBlockArrangementInfoOuterClass.HomeBlockArrangementInfo; import emu.grasscutter.net.proto.HomeBlockArrangementInfoOuterClass.HomeBlockArrangementInfo;
import java.util.*; import java.util.*;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -19,6 +21,7 @@ public class HomeBlockItem {
List<HomeFurnitureItem> persistentFurnitureList; List<HomeFurnitureItem> persistentFurnitureList;
List<HomeAnimalItem> deployAnimalList; List<HomeAnimalItem> deployAnimalList;
List<HomeNPCItem> deployNPCList; List<HomeNPCItem> deployNPCList;
List<HomeSuiteItem> suiteList;
public static HomeBlockItem parseFrom(HomeworldDefaultSaveData.HomeBlock homeBlock) { public static HomeBlockItem parseFrom(HomeworldDefaultSaveData.HomeBlock homeBlock) {
// create from default setting // create from default setting
@ -37,10 +40,11 @@ public class HomeBlockItem {
.toList()) .toList())
.deployAnimalList(List.of()) .deployAnimalList(List.of())
.deployNPCList(List.of()) .deployNPCList(List.of())
.suiteList(List.of())
.build(); .build();
} }
public void update(HomeBlockArrangementInfo homeBlockArrangementInfo) { public void update(HomeBlockArrangementInfo homeBlockArrangementInfo, Player owner) {
this.blockId = homeBlockArrangementInfo.getBlockId(); this.blockId = homeBlockArrangementInfo.getBlockId();
this.deployFurnitureList = this.deployFurnitureList =
@ -60,7 +64,12 @@ public class HomeBlockItem {
this.deployNPCList = this.deployNPCList =
homeBlockArrangementInfo.getDeployNpcListList().stream() homeBlockArrangementInfo.getDeployNpcListList().stream()
.map(HomeNPCItem::parseFrom) .map(homeNpcData -> HomeNPCItem.parseFrom(homeNpcData, owner))
.toList();
this.suiteList =
homeBlockArrangementInfo.getFurnitureSuiteListList().stream()
.map(HomeSuiteItem::parseFrom)
.toList(); .toList();
} }
@ -81,15 +90,20 @@ public class HomeBlockItem {
this.persistentFurnitureList.forEach(f -> proto.addPersistentFurnitureList(f.toProto())); this.persistentFurnitureList.forEach(f -> proto.addPersistentFurnitureList(f.toProto()));
this.deployAnimalList.forEach(f -> proto.addDeployAnimalList(f.toProto())); this.deployAnimalList.forEach(f -> proto.addDeployAnimalList(f.toProto()));
this.deployNPCList.forEach(f -> proto.addDeployNpcList(f.toProto())); this.deployNPCList.forEach(f -> proto.addDeployNpcList(f.toProto()));
this.suiteList.forEach(f -> proto.addFurnitureSuiteList(f.toProto()));
return proto.build(); return proto.build();
} }
// TODO add more types (farm field and suite) // TODO implement farm field.
public List<? extends HomeMarkPointProtoFactory> getMarkPointProtoFactories() { public List<? extends HomeMarkPointProtoFactory> getMarkPointProtoFactories() {
this.reassignIfNull(); this.reassignIfNull();
return Stream.of(this.deployFurnitureList, this.persistentFurnitureList, this.deployNPCList) return Stream.of(
this.deployFurnitureList,
this.persistentFurnitureList,
this.deployNPCList,
this.suiteList)
.flatMap(Collection::stream) .flatMap(Collection::stream)
.toList(); .toList();
} }
@ -107,5 +121,8 @@ public class HomeBlockItem {
if (this.deployNPCList == null) { if (this.deployNPCList == null) {
this.deployNPCList = List.of(); this.deployNPCList = List.of();
} }
if (this.suiteList == null) {
this.suiteList = List.of();
}
} }
} }

View File

@ -0,0 +1,235 @@
package emu.grasscutter.game.home;
import com.github.davidmoten.guavamini.Lists;
import emu.grasscutter.game.home.suite.event.HomeAvatarRewardEvent;
import emu.grasscutter.game.home.suite.event.HomeAvatarSummonEvent;
import emu.grasscutter.game.home.suite.event.SuiteEventType;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.HomeAvatarRewardEventNotifyOuterClass;
import emu.grasscutter.net.proto.HomeAvatarSummonAllEventNotifyOuterClass;
import emu.grasscutter.net.proto.RetcodeOuterClass;
import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonAllEventNotify;
import emu.grasscutter.utils.Either;
import java.util.*;
import java.util.stream.Stream;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class HomeModuleManager {
final Player homeOwner;
final HomeWorld homeWorld;
final GameHome home;
final int moduleId;
final HomeScene outdoor;
HomeScene indoor;
final List<HomeAvatarRewardEvent> rewardEvents;
final List<HomeAvatarSummonEvent> summonEvents;
public HomeModuleManager(HomeWorld homeWorld) {
this.homeOwner = homeWorld.getHost();
this.homeWorld = homeWorld;
this.home = homeWorld.getHome();
this.moduleId = this.homeOwner.getCurrentRealmId();
this.outdoor = homeWorld.getSceneById(homeWorld.getActiveOutdoorSceneId());
this.refreshMainHouse();
this.rewardEvents = Lists.newArrayList();
this.summonEvents = Collections.synchronizedList(Lists.newArrayList());
}
public void tick() {
if (this.moduleId == 0) {
return;
}
this.outdoor.onTick();
this.indoor.onTick();
this.summonEvents.removeIf(HomeAvatarSummonEvent::isTimeOver);
}
public void refreshMainHouse() {
if (this.moduleId == 0) {
return;
}
this.indoor = this.homeWorld.getSceneById(this.homeWorld.getActiveIndoorSceneId());
}
public void onUpdateArrangement() {
this.fireAllAvatarRewardEvent();
this.cancelSummonEventIfAvatarLeave();
}
private void fireAllAvatarRewardEvent() {
this.rewardEvents.clear();
var allBlockItems =
Stream.of(this.getOutdoorSceneItem(), this.getIndoorSceneItem())
.map(HomeSceneItem::getBlockItems)
.map(Map::values)
.flatMap(Collection::stream)
.toList();
var suites =
allBlockItems.stream()
.map(HomeBlockItem::getSuiteList)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.distinct()
.toList();
allBlockItems.stream()
.map(HomeBlockItem::getDeployNPCList)
.flatMap(Collection::stream)
.forEach(
avatar -> {
suites.forEach(
suite -> {
var data =
SuiteEventType.HOME_AVATAR_REWARD_EVENT.getEventDataFrom(
avatar.getAvatarId(), suite.getSuiteId());
if (data == null || this.home.isRewardEventFinished(data.getId())) {
return;
}
this.rewardEvents.add(
new HomeAvatarRewardEvent(
homeOwner,
data.getId(),
data.getRewardID(),
data.getAvatarID(),
data.getSuiteId(),
suite.getGuid()));
});
});
if (this.summonEvents != null) {
var suiteIdList = this.rewardEvents.stream().map(HomeAvatarRewardEvent::getSuiteId).toList();
this.summonEvents.removeIf(event -> suiteIdList.contains(event.getSuiteId()));
}
}
private void cancelSummonEventIfAvatarLeave() {
var avatars =
Stream.of(this.getOutdoorSceneItem(), this.getIndoorSceneItem())
.map(HomeSceneItem::getBlockItems)
.map(Map::values)
.flatMap(Collection::stream)
.map(HomeBlockItem::getDeployNPCList)
.flatMap(Collection::stream)
.map(HomeNPCItem::getAvatarId)
.toList();
this.summonEvents.removeIf(event -> !avatars.contains(event.getAvatarId()));
}
public Either<List<GameItem>, Integer> claimAvatarRewards(int eventId) {
if (this.rewardEvents.isEmpty()) {
return Either.right(RetcodeOuterClass.Retcode.RET_FAIL_VALUE);
}
var event = this.rewardEvents.remove(0);
if (event.getEventId() != eventId) {
return Either.right(RetcodeOuterClass.Retcode.RET_FAIL_VALUE);
}
if (!this.homeOwner.getHome().onClaimAvatarRewards(eventId)) {
return Either.right(RetcodeOuterClass.Retcode.RET_FAIL_VALUE);
}
return Either.left(event.giveRewards());
}
public Either<HomeAvatarSummonEvent, Integer> fireAvatarSummonEvent(
Player owner, int avatarId, int guid, int suiteId) {
var targetSuite =
((HomeScene) owner.getScene())
.getSceneItem().getBlockItems().values().stream()
.map(HomeBlockItem::getSuiteList)
.flatMap(Collection::stream)
.filter(suite -> suite.getGuid() == guid)
.findFirst()
.orElse(null);
if (this.isInRewardEvent(avatarId)) {
return Either.right(RetcodeOuterClass.Retcode.RET_DUPLICATE_AVATAR_VALUE);
}
if (this.rewardEvents.stream().anyMatch(event -> event.getGuid() == guid)) {
return Either.right(RetcodeOuterClass.Retcode.RET_HOME_FURNITURE_GUID_ERROR_VALUE);
}
this.summonEvents.removeIf(event -> event.getGuid() == guid || event.getAvatarId() == avatarId);
if (targetSuite == null) {
return Either.right(RetcodeOuterClass.Retcode.RET_HOME_CLIENT_PARAM_INVALID_VALUE);
}
var eventData = SuiteEventType.HOME_AVATAR_SUMMON_EVENT.getEventDataFrom(avatarId, suiteId);
if (eventData == null) {
return Either.right(RetcodeOuterClass.Retcode.RET_HOME_CLIENT_PARAM_INVALID_VALUE);
}
var event =
new HomeAvatarSummonEvent(
owner, eventData.getId(), eventData.getRewardID(), avatarId, suiteId, guid);
this.summonEvents.add(event);
owner.sendPacket(new PacketHomeAvatarSummonAllEventNotify(owner));
return Either.left(event);
}
public void onFinishSummonEvent(int eventId) {
this.summonEvents.removeIf(event -> event.getEventId() == eventId);
}
public HomeAvatarRewardEventNotifyOuterClass.HomeAvatarRewardEventNotify toRewardEventProto() {
var notify = HomeAvatarRewardEventNotifyOuterClass.HomeAvatarRewardEventNotify.newBuilder();
if (!this.rewardEvents.isEmpty()) {
notify.setRewardEvent(this.rewardEvents.get(0).toProto()).setIsEventTrigger(true);
notify.addAllPendingList(
this.rewardEvents.subList(1, this.rewardEvents.size()).stream()
.map(HomeAvatarRewardEvent::toProto)
.toList());
}
return notify.build();
}
public HomeAvatarSummonAllEventNotifyOuterClass.HomeAvatarSummonAllEventNotify
toSummonEventProto() {
return HomeAvatarSummonAllEventNotifyOuterClass.HomeAvatarSummonAllEventNotify.newBuilder()
.addAllSummonEventList(
this.summonEvents.stream().map(HomeAvatarSummonEvent::toProto).toList())
.build();
}
public boolean isInRewardEvent(int avatarId) {
return this.rewardEvents.stream().anyMatch(e -> e.getAvatarId() == avatarId);
}
public HomeSceneItem getOutdoorSceneItem() {
return this.outdoor.getSceneItem();
}
public HomeSceneItem getIndoorSceneItem() {
return this.indoor.getSceneItem();
}
public void onSetModule() {
if (this.moduleId == 0) {
return;
}
this.outdoor.addEntities(this.getOutdoorSceneItem().getAnimals(this.outdoor));
this.indoor.addEntities(this.getIndoorSceneItem().getAnimals(this.indoor));
this.fireAllAvatarRewardEvent();
}
public void onRemovedModule() {
this.outdoor.getEntities().clear();
this.indoor.getEntities().clear();
}
}

View File

@ -2,6 +2,7 @@ package emu.grasscutter.game.home;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.Position; import emu.grasscutter.game.world.Position;
import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass; import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass;
import emu.grasscutter.net.proto.HomeMarkPointNPCDataOuterClass; import emu.grasscutter.net.proto.HomeMarkPointNPCDataOuterClass;
@ -23,11 +24,12 @@ public class HomeNPCItem implements HomeMarkPointProtoFactory {
Position spawnRot; Position spawnRot;
int costumeId; int costumeId;
public static HomeNPCItem parseFrom(HomeNpcDataOuterClass.HomeNpcData homeNpcData) { public static HomeNPCItem parseFrom(HomeNpcDataOuterClass.HomeNpcData homeNpcData, Player owner) {
return HomeNPCItem.of() return HomeNPCItem.of()
.avatarId(homeNpcData.getAvatarId()) .avatarId(homeNpcData.getAvatarId())
.spawnPos(new Position(homeNpcData.getSpawnPos())) .spawnPos(new Position(homeNpcData.getSpawnPos()))
.spawnRot(new Position(homeNpcData.getSpawnRot())) .spawnRot(new Position(homeNpcData.getSpawnRot()))
.costumeId(owner.getCostumeFrom(homeNpcData.getAvatarId()))
.build(); .build();
} }

View File

@ -1,9 +1,12 @@
package emu.grasscutter.game.home; package emu.grasscutter.game.home;
import emu.grasscutter.data.excels.scene.SceneData; import emu.grasscutter.data.excels.scene.SceneData;
import emu.grasscutter.game.entity.EntityHomeAnimal;
import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.entity.Rebornable;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.VisionTypeOuterClass;
import emu.grasscutter.server.packet.send.PacketSceneTimeNotify; import emu.grasscutter.server.packet.send.PacketSceneTimeNotify;
public class HomeScene extends Scene { public class HomeScene extends Scene {
@ -40,10 +43,31 @@ public class HomeScene extends Scene {
.forEach(gameEntity -> gameEntity.onTick(this.getSceneTimeSeconds())); .forEach(gameEntity -> gameEntity.onTick(this.getSceneTimeSeconds()));
this.finishLoading(); this.finishLoading();
this.checkPlayerRespawn();
if (this.tickCount++ % 10 == 0) this.broadcastPacket(new PacketSceneTimeNotify(this)); if (this.tickCount++ % 10 == 0) this.broadcastPacket(new PacketSceneTimeNotify(this));
} }
public void onEnterEditModeFinish() {
this.removeEntities(
this.getEntities().values().stream()
.filter(gameEntity -> gameEntity instanceof EntityHomeAnimal)
.toList(),
VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE);
}
public void onLeaveEditMode() {
this.addEntities(this.getSceneItem().getAnimals(this));
}
@Override
public void killEntity(GameEntity target, int attackerId) {
if (target instanceof Rebornable rebornable) {
rebornable.onAiKillSelf(); // Teapot animals will not die. They will revive!
return;
}
super.killEntity(target, attackerId);
}
@Override @Override
public void checkNpcGroup() {} public void checkNpcGroup() {}

View File

@ -6,16 +6,18 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.HomeworldDefaultSaveData; import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
import emu.grasscutter.game.entity.EntityHomeAnimal; import emu.grasscutter.game.entity.EntityHomeAnimal;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.Position; import emu.grasscutter.game.world.Position;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo; import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import lombok.*; import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
@Entity @Entity
@ -49,14 +51,14 @@ public class HomeSceneItem {
.build(); .build();
} }
public void update(HomeSceneArrangementInfo arrangementInfo) { public void update(HomeSceneArrangementInfo arrangementInfo, Player owner) {
for (var blockItem : arrangementInfo.getBlockArrangementInfoListList()) { for (var blockItem : arrangementInfo.getBlockArrangementInfoListList()) {
var block = this.blockItems.get(blockItem.getBlockId()); var block = this.blockItems.get(blockItem.getBlockId());
if (block == null) { if (block == null) {
Grasscutter.getLogger().warn("Could not found the Home Block {}", blockItem.getBlockId()); Grasscutter.getLogger().warn("Could not found the Home Block {}", blockItem.getBlockId());
continue; continue;
} }
block.update(blockItem); block.update(blockItem, owner);
this.blockItems.put(blockItem.getBlockId(), block); this.blockItems.put(blockItem.getBlockId(), block);
} }
@ -84,17 +86,13 @@ public class HomeSceneItem {
} }
@Nullable public Position getTeleportPointPos(int guid) { @Nullable public Position getTeleportPointPos(int guid) {
var pos = new AtomicReference<Position>(); return this.getBlockItems().values().stream()
this.getBlockItems().values().stream()
.map(HomeBlockItem::getDeployFurnitureList) .map(HomeBlockItem::getDeployFurnitureList)
.flatMap(Collection::stream) .flatMap(Collection::stream)
.filter(homeFurnitureItem -> homeFurnitureItem.getGuid() == guid) .filter(homeFurnitureItem -> homeFurnitureItem.getGuid() == guid)
.map(HomeFurnitureItem::getSpawnPos) .map(HomeFurnitureItem::getSpawnPos)
.findFirst() .findFirst()
.ifPresent(pos::set); .orElse(null);
return pos.get();
} }
public List<EntityHomeAnimal> getAnimals(Scene scene) { public List<EntityHomeAnimal> getAnimals(Scene scene) {

View File

@ -8,33 +8,59 @@ import emu.grasscutter.game.world.World;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.ChatInfoOuterClass; import emu.grasscutter.net.proto.ChatInfoOuterClass;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
import emu.grasscutter.server.packet.send.PacketPlayerChatNotify;
import emu.grasscutter.server.packet.send.PacketPlayerGameTimeNotify;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import lombok.Getter; import lombok.Getter;
public class HomeWorld extends World { public class HomeWorld extends World {
@Getter private final GameHome home; @Getter private final GameHome home;
@Getter private HomeModuleManager moduleManager;
public HomeWorld(GameServer server, Player owner) { public HomeWorld(GameServer server, Player owner) {
super(server, owner); super(server, owner);
this.home = owner.isOnline() ? owner.getHome() : GameHome.getByUid(owner.getUid()); this.home = owner.isOnline() ? owner.getHome() : GameHome.getByUid(owner.getUid());
server.registerHomeWorld(this); server.registerHomeWorld(this);
this.refreshModuleManager();
} }
@Override @Override
public void registerScene(Scene scene) { public boolean onTick() {
this.addAnimalsToScene((HomeScene) scene); if (this.moduleManager == null) {
super.registerScene(scene); return false;
}
this.moduleManager.tick();
if (this.getTickCount() % 10 == 0) {
this.getPlayers().forEach(p -> p.sendPacket(new PacketPlayerGameTimeNotify(p)));
}
if (this.isInHome(this.getHost()) && this.getTickCount() % 60 == 0) {
this.getHost().updatePlayerGameTime(this.getCurrentWorldTime());
}
this.tickCount++;
return false;
} }
@Override public void refreshModuleManager() {
public void deregisterScene(Scene scene) { if (this.moduleManager != null) {
super.deregisterScene(scene); this.moduleManager.onRemovedModule();
}
this.moduleManager = new HomeModuleManager(this);
this.moduleManager.onSetModule();
} }
private void addAnimalsToScene(HomeScene scene) { public int getActiveOutdoorSceneId() {
scene.getSceneItem().getAnimals(scene).forEach(scene::addEntity); return this.getHost().getCurrentRealmId() + 2000;
}
public int getActiveIndoorSceneId() {
return this.getSceneById(this.getActiveOutdoorSceneId()).getSceneItem().getRoomSceneId();
} }
@Override @Override
@ -188,6 +214,12 @@ public class HomeWorld extends World {
return this.getPlayers().contains(player); return this.getPlayers().contains(player);
} }
public void ifHost(Player hostOrGuest, Consumer<Player> ifHost) {
if (this.getHost().equals(hostOrGuest)) {
ifHost.accept(hostOrGuest);
}
}
public void sendPacketToHostIfOnline(BasePacket basePacket) { public void sendPacketToHostIfOnline(BasePacket basePacket) {
if (this.getHost().isOnline()) { if (this.getHost().isOnline()) {
this.getHost().sendPacket(basePacket); this.getHost().sendPacket(basePacket);

View File

@ -5,10 +5,7 @@ import emu.grasscutter.game.props.EnterReason;
import emu.grasscutter.game.world.Position; import emu.grasscutter.game.world.Position;
import emu.grasscutter.game.world.World; import emu.grasscutter.game.world.World;
import emu.grasscutter.game.world.data.TeleportProperties; import emu.grasscutter.game.world.data.TeleportProperties;
import emu.grasscutter.net.proto.EnterTypeOuterClass; import emu.grasscutter.net.proto.*;
import emu.grasscutter.net.proto.OtherPlayerEnterHomeNotifyOuterClass;
import emu.grasscutter.net.proto.PlayerApplyEnterHomeResultNotifyOuterClass;
import emu.grasscutter.net.proto.RetcodeOuterClass;
import emu.grasscutter.server.event.player.PlayerEnterHomeEvent; import emu.grasscutter.server.event.player.PlayerEnterHomeEvent;
import emu.grasscutter.server.event.player.PlayerLeaveHomeEvent; import emu.grasscutter.server.event.player.PlayerLeaveHomeEvent;
import emu.grasscutter.server.event.player.PlayerTeleportEvent; import emu.grasscutter.server.event.player.PlayerTeleportEvent;
@ -215,6 +212,10 @@ public class HomeWorldMPSystem extends BaseGameSystem {
player.setCurHomeWorld(myHome); player.setCurHomeWorld(myHome);
myHome.getHome().onOwnerLogin(player); myHome.getHome().onOwnerLogin(player);
player.sendPacket(
new PacketPlayerQuitFromHomeNotify(
PlayerQuitFromHomeNotifyOuterClass.PlayerQuitFromHomeNotify.QuitReason
.BACK_TO_MY_WORLD));
player.sendPacket( player.sendPacket(
new PacketPlayerEnterSceneNotify( new PacketPlayerEnterSceneNotify(
player, player,
@ -263,6 +264,9 @@ public class HomeWorldMPSystem extends BaseGameSystem {
victim.setCurHomeWorld(myHome); victim.setCurHomeWorld(myHome);
myHome.getHome().onOwnerLogin(victim); myHome.getHome().onOwnerLogin(victim);
victim.sendPacket(
new PacketPlayerQuitFromHomeNotify(
PlayerQuitFromHomeNotifyOuterClass.PlayerQuitFromHomeNotify.QuitReason.KICK_BY_HOST));
victim.sendPacket( victim.sendPacket(
new PacketPlayerEnterSceneNotify( new PacketPlayerEnterSceneNotify(
victim, victim,

View File

@ -0,0 +1,82 @@
package emu.grasscutter.game.home.suite;
import dev.morphia.annotations.Entity;
import emu.grasscutter.game.home.HomeMarkPointProtoFactory;
import emu.grasscutter.game.home.SpecialFurnitureType;
import emu.grasscutter.game.world.Position;
import emu.grasscutter.net.proto.HomeFurnitureSuiteDataOuterClass;
import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass;
import emu.grasscutter.net.proto.HomeMarkPointSuiteDataOuterClass;
import java.util.List;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import org.jetbrains.annotations.Nullable;
@Entity
@Builder(builderMethodName = "of")
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class HomeSuiteItem implements HomeMarkPointProtoFactory {
public static final int SUITE_FURNITURE_ID = 377101;
int guid;
int suiteId;
Position pos;
List<Integer> includedFurnitureIndexList;
boolean isAllowSummon;
public static HomeSuiteItem parseFrom(
HomeFurnitureSuiteDataOuterClass.HomeFurnitureSuiteData data) {
return HomeSuiteItem.of()
.guid(data.getGuid())
.suiteId(data.getSuiteId())
.pos(new Position(data.getSpawnPos()))
.includedFurnitureIndexList(data.getIncludedFurnitureIndexListList())
.isAllowSummon(data.getIsAllowSummon())
.build();
}
public HomeFurnitureSuiteDataOuterClass.HomeFurnitureSuiteData toProto() {
return HomeFurnitureSuiteDataOuterClass.HomeFurnitureSuiteData.newBuilder()
.setSuiteId(this.suiteId)
.setGuid(this.guid)
.setIsAllowSummon(this.isAllowSummon)
.addAllIncludedFurnitureIndexList(this.includedFurnitureIndexList)
.setSpawnPos(this.pos.toProto())
.build();
}
@Nullable @Override
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto() {
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
.setFurnitureId(SUITE_FURNITURE_ID)
.setPos(this.pos.toProto())
.setFurnitureType(this.getType().getValue())
.setGuid(this.guid)
.setSuiteData(
HomeMarkPointSuiteDataOuterClass.HomeMarkPointSuiteData.newBuilder()
.setSuiteId(this.suiteId)
.build())
.build();
}
@Override
public SpecialFurnitureType getType() {
return SpecialFurnitureType.FurnitureSuite;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HomeSuiteItem that = (HomeSuiteItem) o;
return suiteId == that.suiteId;
}
@Override
public int hashCode() {
return Objects.hash(suiteId);
}
}

View File

@ -0,0 +1,54 @@
package emu.grasscutter.game.home.suite.event;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Utils;
import java.util.List;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public abstract class HomeAvatarEvent {
final Player homeOwner;
final int eventId;
final int rewardId;
final int avatarId;
final int suiteId;
final int guid;
final int randomPos;
public HomeAvatarEvent(
Player homeOwner, int eventId, int rewardId, int avatarId, int suiteId, int guid) {
this.homeOwner = homeOwner;
this.eventId = eventId;
this.rewardId = rewardId;
this.avatarId = avatarId;
this.suiteId = suiteId;
this.guid = guid;
this.randomPos = this.generateRandomPos();
}
public int generateRandomPos() {
return Utils.randomRange(1, 97);
}
public List<GameItem> giveRewards() {
return List.of();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HomeAvatarEvent that = (HomeAvatarEvent) o;
return eventId == that.eventId;
}
@Override
public int hashCode() {
return Objects.hash(eventId);
}
}

View File

@ -0,0 +1,37 @@
package emu.grasscutter.game.home.suite.event;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.net.proto.HomeAvatarRewardEventInfoOuterClass;
import java.util.List;
public class HomeAvatarRewardEvent extends HomeAvatarEvent {
public HomeAvatarRewardEvent(
Player homeOwner, int eventId, int rewardId, int avatarId, int suiteId, int guid) {
super(homeOwner, eventId, rewardId, avatarId, suiteId, guid);
}
public HomeAvatarRewardEventInfoOuterClass.HomeAvatarRewardEventInfo toProto() {
return HomeAvatarRewardEventInfoOuterClass.HomeAvatarRewardEventInfo.newBuilder()
.setAvatarId(this.getAvatarId())
.setEventId(this.getEventId())
.setGuid(this.getGuid())
.setSuiteId(this.getSuiteId())
.setRandomPosition(this.getRandomPos())
.build();
}
@Override
public List<GameItem> giveRewards() {
var data = GameData.getRewardDataMap().get(this.getRewardId());
if (data == null) {
return List.of();
}
var rewards = data.getRewardItemList().stream().map(GameItem::new).toList();
this.getHomeOwner().getInventory().addItems(rewards, ActionReason.HomeAvatarEventReward);
return rewards;
}
}

View File

@ -0,0 +1,37 @@
package emu.grasscutter.game.home.suite.event;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.HomeAvatarSummonEventInfoOuterClass;
import emu.grasscutter.utils.Utils;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class HomeAvatarSummonEvent extends HomeAvatarEvent {
public static final int TIME_LIMIT_SECS = 240;
final int eventOverTime;
public HomeAvatarSummonEvent(
Player homeOwner, int eventId, int rewardId, int avatarId, int suiteId, int guid) {
super(homeOwner, eventId, rewardId, avatarId, suiteId, guid);
this.eventOverTime = Utils.getCurrentSeconds() + TIME_LIMIT_SECS;
}
public HomeAvatarSummonEventInfoOuterClass.HomeAvatarSummonEventInfo toProto() {
return HomeAvatarSummonEventInfoOuterClass.HomeAvatarSummonEventInfo.newBuilder()
.setAvatarId(this.getAvatarId())
.setEventId(this.getEventId())
.setGuid(this.getGuid())
.setSuitId(this.getSuiteId())
.setRandomPosition(this.getRandomPos())
.setEventOverTime(this.eventOverTime)
.build();
}
public boolean isTimeOver() {
return Utils.getCurrentSeconds() > this.eventOverTime;
}
}

View File

@ -0,0 +1,21 @@
package emu.grasscutter.game.home.suite.event;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.HomeWorldEventData;
import javax.annotation.Nullable;
public enum SuiteEventType {
HOME_AVATAR_REWARD_EVENT,
HOME_AVATAR_SUMMON_EVENT;
@Nullable public HomeWorldEventData getEventDataFrom(int avatarId, int suiteId) {
return GameData.getHomeWorldEventDataMap().values().stream()
.filter(
data ->
data.getEventType() == this
&& data.getAvatarID() == avatarId
&& data.getSuiteId() == suiteId)
.findFirst()
.orElse(null);
}
}

View File

@ -950,6 +950,13 @@ public class Player implements PlayerHook, FieldFetch {
this.sendPacket(new PacketAvatarGainCostumeNotify(costumeId)); this.sendPacket(new PacketAvatarGainCostumeNotify(costumeId));
} }
public int getCostumeFrom(int avatarId) {
var avatars = this.getAvatars();
avatars.loadFromDatabase();
var avatar = avatars.getAvatarById(avatarId);
return avatar == null ? 0 : avatar.getCostume();
}
public void addPersonalLine(int personalLineId) { public void addPersonalLine(int personalLineId) {
this.getPersonalLineList().add(personalLineId); this.getPersonalLineList().add(personalLineId);
session.getPlayer().getQuestManager().queueEvent(QuestCond.QUEST_COND_PERSONAL_LINE_UNLOCK, personalLineId); session.getPlayer().getQuestManager().queueEvent(QuestCond.QUEST_COND_PERSONAL_LINE_UNLOCK, personalLineId);

View File

@ -177,7 +177,8 @@ public enum ActionReason {
ChannellerSlabLoopDungeonFirstPassReward(1090), ChannellerSlabLoopDungeonFirstPassReward(1090),
ChannellerSlabLoopDungeonScoreReward(1091), ChannellerSlabLoopDungeonScoreReward(1091),
HomeLimitedShopBuy(1092), HomeLimitedShopBuy(1092),
HomeCoinCollect(1093); HomeCoinCollect(1093),
HomeAvatarEventReward(1100);
private static final Int2ObjectMap<ActionReason> map = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ActionReason> map = new Int2ObjectOpenHashMap<>();
private static final Map<String, ActionReason> stringMap = new HashMap<>(); private static final Map<String, ActionReason> stringMap = new HashMap<>();

View File

@ -169,23 +169,6 @@ public class GameMainQuest {
this.state = ParentQuestState.PARENT_QUEST_STATE_FINISHED; this.state = ParentQuestState.PARENT_QUEST_STATE_FINISHED;
} }
/*
* We also need to check for unfinished childQuests in this MainQuest
* force them to complete and send a packet about this to the user,
* because at some points there are special "invisible" child quests that control
* some situations.
*
* For example, subQuest 35312 is responsible for the event of leaving the territory
* of the island with a statue and automatically returns the character back,
* quest 35311 completes the main quest line 353 and starts 35501 from
* new MainQuest 355 but if 35312 is not completed after the completion
* of the main quest 353 - the character will not be able to leave place
* (return again and again)
*/
// this.getChildQuests().values().stream()
// .filter(p -> p.state != QuestState.QUEST_STATE_FINISHED)
// .forEach(GameQuest::finish);
this.getOwner().getSession().send(new PacketFinishedParentQuestUpdateNotify(this)); this.getOwner().getSession().send(new PacketFinishedParentQuestUpdateNotify(this));
this.getOwner().getSession().send(new PacketCodexDataUpdateNotify(this)); this.getOwner().getSession().send(new PacketCodexDataUpdateNotify(this));
@ -383,46 +366,6 @@ public class GameMainQuest {
} }
} }
public void tryAcceptSubQuests(QuestCond condType, String paramStr, int... params) {
try {
List<GameQuest> subQuestsWithCond =
getChildQuests().values().stream()
.filter(
p ->
p.getState() == QuestState.QUEST_STATE_UNSTARTED
|| p.getState() == QuestState.UNFINISHED)
.filter(
p ->
p.getQuestData().getAcceptCond().stream()
.anyMatch(
q ->
condType == QuestCond.QUEST_COND_NONE || q.getType() == condType))
.toList();
var questSystem = owner.getServer().getQuestSystem();
for (GameQuest subQuestWithCond : subQuestsWithCond) {
var acceptCond = subQuestWithCond.getQuestData().getAcceptCond();
int[] accept = new int[acceptCond.size()];
for (int i = 0; i < subQuestWithCond.getQuestData().getAcceptCond().size(); i++) {
var condition = acceptCond.get(i);
boolean result =
questSystem.triggerCondition(
getOwner(), subQuestWithCond.getQuestData(), condition, paramStr, params);
accept[i] = result ? 1 : 0;
}
boolean shouldAccept =
LogicType.calculate(subQuestWithCond.getQuestData().getAcceptCondComb(), accept);
if (shouldAccept) subQuestWithCond.start();
}
this.save();
} catch (Exception e) {
Grasscutter.getLogger().error("An error occurred while trying to accept quest.", e);
}
}
public void tryFailSubQuests(QuestContent condType, String paramStr, int... params) { public void tryFailSubQuests(QuestContent condType, String paramStr, int... params) {
try { try {
List<GameQuest> subQuestsWithCond = List<GameQuest> subQuestsWithCond =
@ -437,7 +380,7 @@ public class GameMainQuest {
for (GameQuest subQuestWithCond : subQuestsWithCond) { for (GameQuest subQuestWithCond : subQuestsWithCond) {
val failCond = subQuestWithCond.getQuestData().getFailCond(); val failCond = subQuestWithCond.getQuestData().getFailCond();
for (int i = 0; i < subQuestWithCond.getQuestData().getFailCond().size(); i++) { for (int i = 0; i < failCond.size(); i++) {
val condition = failCond.get(i); val condition = failCond.get(i);
if (condition.getType() == condType) { if (condition.getType() == condType) {
boolean result = boolean result =
@ -445,7 +388,7 @@ public class GameMainQuest {
.getServer() .getServer()
.getQuestSystem() .getQuestSystem()
.triggerContent(subQuestWithCond, condition, paramStr, params); .triggerContent(subQuestWithCond, condition, paramStr, params);
subQuestWithCond.getFailProgressList()[i] = result ? 1 : 0; subQuestWithCond.setFailProgress(i, result ? 1 : 0);
if (result) { if (result) {
getOwner().getSession().send(new PacketQuestProgressUpdateNotify(subQuestWithCond)); getOwner().getSession().send(new PacketQuestProgressUpdateNotify(subQuestWithCond));
} }

View File

@ -158,6 +158,13 @@ public class GameQuest {
public boolean clearProgress(boolean notifyDelete) { public boolean clearProgress(boolean notifyDelete) {
// TODO improve // TODO improve
var oldState = state; var oldState = state;
if (questData.getAcceptCond() != null && questData.getAcceptCond().size() != 0) {
this.getMainQuest()
.getQuestManager()
.getAcceptProgressLists()
.put(this.getSubQuestId(), new int[questData.getAcceptCond().size()]);
}
if (questData.getFinishCond() != null && questData.getFinishCond().size() != 0) { if (questData.getFinishCond() != null && questData.getFinishCond().size() != 0) {
for (var condition : questData.getFinishCond()) { for (var condition : questData.getFinishCond()) {
if (condition.getType() == QuestContent.QUEST_CONTENT_LUA_NOTIFY) { if (condition.getType() == QuestContent.QUEST_CONTENT_LUA_NOTIFY) {

View File

@ -26,6 +26,7 @@ public final class QuestManager extends BasePlayerManager {
@Getter private final Player player; @Getter private final Player player;
@Getter private final Int2ObjectMap<GameMainQuest> mainQuests; @Getter private final Int2ObjectMap<GameMainQuest> mainQuests;
@Getter private Int2ObjectMap<int[]> acceptProgressLists;
@Getter private final List<Integer> loggedQuests; @Getter private final List<Integer> loggedQuests;
private long lastHourCheck = 0; private long lastHourCheck = 0;
@ -52,6 +53,7 @@ public final class QuestManager extends BasePlayerManager {
this.player = player; this.player = player;
this.mainQuests = new Int2ObjectOpenHashMap<>(); this.mainQuests = new Int2ObjectOpenHashMap<>();
this.loggedQuests = new ArrayList<>(); this.loggedQuests = new ArrayList<>();
this.acceptProgressLists = new Int2ObjectOpenHashMap<>();
if (DEBUG) { if (DEBUG) {
this.loggedQuests.addAll( this.loggedQuests.addAll(
@ -484,8 +486,6 @@ public final class QuestManager extends BasePlayerManager {
eventExecutor.submit(() -> triggerEvent(condType, paramStr, params)); eventExecutor.submit(() -> triggerEvent(condType, paramStr, params));
} }
// QUEST_EXEC are handled directly by each subQuest
public void triggerEvent(QuestCond condType, String paramStr, int... params) { public void triggerEvent(QuestCond condType, String paramStr, int... params) {
Grasscutter.getLogger().trace("Trigger Event {}, {}, {}", condType, paramStr, params); Grasscutter.getLogger().trace("Trigger Event {}, {}, {}", condType, paramStr, params);
var potentialQuests = GameData.getQuestDataByConditions(condType, params[0], paramStr); var potentialQuests = GameData.getQuestDataByConditions(condType, params[0], paramStr);
@ -502,15 +502,19 @@ public final class QuestManager extends BasePlayerManager {
return; return;
} }
val acceptCond = questData.getAcceptCond(); val acceptCond = questData.getAcceptCond();
int[] accept = new int[acceptCond.size()]; acceptProgressLists.putIfAbsent(questData.getId(), new int[acceptCond.size()]);
for (int i = 0; i < acceptCond.size(); i++) { for (int i = 0; i < acceptCond.size(); i++) {
val condition = acceptCond.get(i); val condition = acceptCond.get(i);
boolean result = if (condition.getType() == condType) {
questSystem.triggerCondition(owner, questData, condition, paramStr, params); boolean result =
accept[i] = result ? 1 : 0; questSystem.triggerCondition(owner, questData, condition, paramStr, params);
acceptProgressLists.get(questData.getId())[i] = result ? 1 : 0;
}
} }
boolean shouldAccept = LogicType.calculate(questData.getAcceptCondComb(), accept); boolean shouldAccept =
LogicType.calculate(
questData.getAcceptCondComb(), acceptProgressLists.get(questData.getId()));
if (this.loggedQuests.contains(questData.getId())) { if (this.loggedQuests.contains(questData.getId())) {
Grasscutter.getLogger() Grasscutter.getLogger()
.debug( .debug(
@ -522,7 +526,7 @@ public final class QuestManager extends BasePlayerManager {
Arrays.stream(params) Arrays.stream(params)
.mapToObj(String::valueOf) .mapToObj(String::valueOf)
.collect(Collectors.joining(", "))); .collect(Collectors.joining(", ")));
for (var i = 0; i < accept.length; i++) { for (var i = 0; i < acceptCond.size(); i++) {
var condition = acceptCond.get(i); var condition = acceptCond.get(i);
Grasscutter.getLogger() Grasscutter.getLogger()
.debug( .debug(
@ -532,14 +536,13 @@ public final class QuestManager extends BasePlayerManager {
.filter(value -> value > 0) .filter(value -> value > 0)
.mapToObj(String::valueOf) .mapToObj(String::valueOf)
.collect(Collectors.joining(", ")), .collect(Collectors.joining(", ")),
accept[i] == 1 ? "success" : "failure"); acceptProgressLists.get(questData.getId())[i] == 1 ? "success" : "failure");
} }
} }
if (shouldAccept) { if (shouldAccept) {
GameQuest quest = owner.getQuestManager().addQuest(questData); GameQuest quest = owner.getQuestManager().addQuest(questData);
Grasscutter.getLogger() Grasscutter.getLogger().debug("Added quest {}", questData.getSubId());
.debug("Added quest {} result {}", questData.getSubId(), quest != null);
} }
}); });
} }

View File

@ -0,0 +1,21 @@
package emu.grasscutter.game.quest.conditions;
import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.QuestValueCond;
import emu.grasscutter.game.quest.enums.QuestCond;
@QuestValueCond(QuestCond.QUEST_COND_ITEM_GIVING_FINISHED)
public class ConditionItemGivingFinished extends BaseCondition {
@Override
public boolean execute(
Player owner,
QuestData questData,
QuestData.QuestAcceptCondition condition,
String paramStr,
int... params) {
return condition.getParam()[0] == params[0]
&& (condition.getParam()[1] == 0 || condition.getParam()[1] == params[1]);
}
}

View File

@ -5,10 +5,11 @@ import emu.grasscutter.game.quest.*;
import emu.grasscutter.game.quest.enums.QuestContent; import emu.grasscutter.game.quest.enums.QuestContent;
@QuestValueContent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING) @QuestValueContent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING)
public final class ContentFinishGivingItem extends BaseContent { public final class ContentFinishItemGiving extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
return condition.getParam()[0] == params[0] && condition.getParam()[1] == params[1]; return condition.getParam()[0] == params[0]
&& (condition.getParam()[1] == 0 || condition.getParam()[1] == params[1]);
} }
} }

View File

@ -25,7 +25,7 @@ public enum QuestCond implements QuestTrigger {
QUEST_COND_PLAYER_LEVEL_EQUAL_GREATER(17), QUEST_COND_PLAYER_LEVEL_EQUAL_GREATER(17),
QUEST_COND_SCENE_AREA_UNLOCKED(18), // missing, only NPC groups/talks QUEST_COND_SCENE_AREA_UNLOCKED(18), // missing, only NPC groups/talks
QUEST_COND_ITEM_GIVING_ACTIVED(19), // missing QUEST_COND_ITEM_GIVING_ACTIVED(19), // missing
QUEST_COND_ITEM_GIVING_FINISHED(20), // missing QUEST_COND_ITEM_GIVING_FINISHED(20),
QUEST_COND_IS_DAYTIME(21), // only NPC groups QUEST_COND_IS_DAYTIME(21), // only NPC groups
QUEST_COND_CURRENT_AVATAR(22), // missing QUEST_COND_CURRENT_AVATAR(22), // missing
QUEST_COND_CURRENT_AREA(23), // missing QUEST_COND_CURRENT_AREA(23), // missing

View File

@ -535,7 +535,17 @@ public class Scene {
"Can not solve monster drop: drop_id = {}, drop_tag = {}. Falling back to legacy drop system.", "Can not solve monster drop: drop_id = {}, drop_tag = {}. Falling back to legacy drop system.",
monster.getMetaMonster().drop_id, monster.getMetaMonster().drop_id,
monster.getMetaMonster().drop_tag); monster.getMetaMonster().drop_tag);
getWorld().getServer().getDropSystemLegacy().callDrop(monster); world.getServer().getDropSystemLegacy().callDrop(monster);
}
}
if (target instanceof EntityGadget gadget) {
if (gadget.getMetaGadget() != null) {
world
.getServer()
.getDropSystem()
.handleChestDrop(
gadget.getMetaGadget().drop_id, gadget.getMetaGadget().drop_count, gadget);
} }
} }

View File

@ -39,7 +39,7 @@ public class World implements Iterable<Player> {
@Getter private boolean timeLocked; @Getter private boolean timeLocked;
private long lastUpdateTime; private long lastUpdateTime;
@Getter private int tickCount = 0; @Getter protected int tickCount = 0;
@Getter private boolean isPaused = false; @Getter private boolean isPaused = false;
@Getter private long currentWorldTime; @Getter private long currentWorldTime;

View File

@ -1105,6 +1105,12 @@ public class ScriptLib {
return 0; return 0;
} }
public int MoveAvatarByPointArrayWithTemplate(int uid, int pointarray_id, int[] routelist, int var4, LuaTable var5){
logger.warn("[LUA] Call unimplemented MoveAvatarByPointArrayWithTemplate with {} {} {} {} {}", uid, pointarray_id, routelist, var4, printTable(var5));
//TODO implement var5 contains int speed
return 0;
}
public int MovePlayerToPos(LuaTable var1){ public int MovePlayerToPos(LuaTable var1){
logger.warn("[LUA] Call unchecked MovePlayerToPos with {}", printTable(var1)); logger.warn("[LUA] Call unchecked MovePlayerToPos with {}", printTable(var1));
//TODO implement var1 contains int[] uid_list, Position pos, int radius, Position rot //TODO implement var1 contains int[] uid_list, Position pos, int radius, Position rot
@ -1262,6 +1268,7 @@ public class ScriptLib {
} }
public int SetWeatherAreaState(int var1, int var2) { public int SetWeatherAreaState(int var1, int var2) {
logger.debug("[LUA] Call SetWeatherAreaState with {} {}", var1, var2);
this.getSceneScriptManager().getScene().getPlayers() this.getSceneScriptManager().getScene().getPlayers()
.forEach(p -> p.setWeather(var1, ClimateType.getTypeByValue(var2))); .forEach(p -> p.setWeather(var1, ClimateType.getTypeByValue(var2)));
return 0; return 0;
@ -1405,6 +1412,11 @@ public class ScriptLib {
return 0; return 0;
} }
public int SetPlayerInteractOption(String var1){
logger.warn("[LUA] Call unimplemented SetPlayerInteractOption {}", var1);
return 0;
}
public int UnlockForce(int force){ public int UnlockForce(int force){
logger.debug("[LUA] Call UnlockForce {}", force); logger.debug("[LUA] Call UnlockForce {}", force);
getSceneScriptManager().getScene().unlockForce(force); getSceneScriptManager().getScene().unlockForce(force);
@ -1552,7 +1564,7 @@ public class ScriptLib {
} }
public int GetRegionConfigId(LuaTable var1){ public int GetRegionConfigId(LuaTable var1){
logger.warn("[LUA] Call untested GetRegionConfigId with {}", printTable(var1)); logger.debug("[LUA] Call GetRegionConfigId with {}", printTable(var1));
var EntityId = var1.get("region_eid").toint(); var EntityId = var1.get("region_eid").toint();
var entity = getSceneScriptManager().getScene().getScriptManager().getRegionById(EntityId); var entity = getSceneScriptManager().getScene().getScriptManager().getRegionById(EntityId);
if (entity == null){ if (entity == null){
@ -1657,9 +1669,11 @@ public class ScriptLib {
} }
public int SetGadgetEnableInteract(int groupId, int configId, boolean enable) { public int SetGadgetEnableInteract(int groupId, int configId, boolean enable) {
EntityGadget gadget = getCurrentEntityGadget(); logger.debug("[LUA] Call SetGadgetEnableInteract with {} {} {}", groupId, configId, enable);
if(gadget.getGroupId() != groupId || gadget.getConfigId() != configId) return -1; var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId);
if (!(entity instanceof EntityGadget gadget)) {
return -1;
}
gadget.setInteractEnabled(enable); gadget.setInteractEnabled(enable);
return 0; return 0;

View File

@ -7,6 +7,7 @@ import lombok.*;
public class SceneGadget extends SceneObject { public class SceneGadget extends SceneObject {
public int gadget_id; public int gadget_id;
public int chest_drop_id; public int chest_drop_id;
public int drop_id;
public int drop_count; public int drop_count;
public String drop_tag; public String drop_tag;
boolean showcutscene; boolean showcutscene;

View File

@ -30,16 +30,47 @@ public class SceneRegion {
public boolean contains(Position position) { public boolean contains(Position position) {
switch (shape) { switch (shape) {
case ScriptRegionShape.CUBIC: case ScriptRegionShape.SPHERE -> {
val x = pos.getX() - position.getX();
val y = pos.getY() - position.getY();
val z = pos.getZ() - position.getZ();
// x^2 + y^2 + z^2 = radius^2
return x * x + y * y + z * z <= radius * radius;
}
case ScriptRegionShape.CUBIC -> {
return (Math.abs(pos.getX() - position.getX()) <= size.getX() / 2f) return (Math.abs(pos.getX() - position.getX()) <= size.getX() / 2f)
&& (Math.abs(pos.getY() - position.getY()) <= size.getY() / 2f) && (Math.abs(pos.getY() - position.getY()) <= size.getY() / 2f)
&& (Math.abs(pos.getZ() - position.getZ()) <= size.getZ() / 2f); && (Math.abs(pos.getZ() - position.getZ()) <= size.getZ() / 2f);
case ScriptRegionShape.SPHERE: }
var x = Math.pow(pos.getX() - position.getX(), 2); case ScriptRegionShape.POLYGON -> {
var y = Math.pow(pos.getY() - position.getY(), 2); // algorithm is "ray casting": https://www.youtube.com/watch?v=RSXM9bgqxJM
var z = Math.pow(pos.getZ() - position.getZ(), 2); if (Math.abs(pos.getY() - position.getY()) > height / 2f) return false;
// ^ means XOR in java! var count = 0;
return x + y + z <= (radius * radius); for (var i = 0; i < point_array.size(); ++i) {
val j = (i + 1) % point_array.size();
val yp = position.getZ();
val y1 = point_array.get(i).getY();
val y2 = point_array.get(j).getY();
val xp = position.getX();
val x1 = point_array.get(i).getX();
val x2 = point_array.get(j).getX();
if ((yp < y1) != (yp < y2) && xp < x1 + ((yp - y1) / (y2 - y1)) * (x2 - x1)) {
++count;
}
}
return count % 2 == 1;
}
case ScriptRegionShape.CYLINDER -> {
if (Math.abs(pos.getY() - position.getY()) > height / 2f) return false;
val x = pos.getX() - position.getX();
val z = pos.getZ() - position.getZ();
// x^2 + z^2 = radius^2
return x * x + z * z <= radius * radius;
}
} }
return false; return false;
} }

View File

@ -0,0 +1,29 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeAvatarRewardEventGetReqOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeAvatarAllFinishRewardNotify;
import emu.grasscutter.server.packet.send.PacketHomeAvatarRewardEventGetRsp;
import emu.grasscutter.server.packet.send.PacketHomeAvatarRewardEventNotify;
@Opcodes(PacketOpcodes.HomeAvatarRewardEventGetReq)
public class HandlerHomeAvatarRewardEventGetReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = HomeAvatarRewardEventGetReqOuterClass.HomeAvatarRewardEventGetReq.parseFrom(payload);
var player = session.getPlayer();
var rewardsOrError =
player.getCurHomeWorld().getModuleManager().claimAvatarRewards(req.getEventId());
session.send(new PacketHomeAvatarRewardEventNotify(player));
session.send(new PacketHomeAvatarAllFinishRewardNotify(player));
session.send(
rewardsOrError.map(
gameItems -> new PacketHomeAvatarRewardEventGetRsp(req.getEventId(), gameItems),
integer -> new PacketHomeAvatarRewardEventGetRsp(req.getEventId(), integer)));
}
}

View File

@ -0,0 +1,22 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeAvatarSummonEventReqOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonEventRsp;
@Opcodes(PacketOpcodes.HomeAvatarSummonEventReq)
public class HandlerHomeAvatarSummonEventReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = HomeAvatarSummonEventReqOuterClass.HomeAvatarSummonEventReq.parseFrom(payload);
var moduleManager = session.getPlayer().getCurHomeWorld().getModuleManager();
var eventOrError =
moduleManager.fireAvatarSummonEvent(
session.getPlayer(), req.getAvatarId(), req.getGuid(), req.getSuitId());
session.send(
eventOrError.map(PacketHomeAvatarSummonEventRsp::new, PacketHomeAvatarSummonEventRsp::new));
}
}

View File

@ -0,0 +1,21 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeAvatarSummonFinishReqOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonAllEventNotify;
import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonFinishRsp;
@Opcodes(PacketOpcodes.HomeAvatarSummonFinishReq)
public class HandlerHomeAvatarSummonFinishReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = HomeAvatarSummonFinishReqOuterClass.HomeAvatarSummonFinishReq.parseFrom(payload);
var player = session.getPlayer();
player.getCurHomeWorld().getModuleManager().onFinishSummonEvent(req.getEventId());
session.send(new PacketHomeAvatarSummonAllEventNotify(session.getPlayer()));
session.send(new PacketHomeAvatarSummonFinishRsp(req.getEventId()));
}
}

View File

@ -1,5 +1,6 @@
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.home.HomeScene;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
@ -31,14 +32,8 @@ public class HandlerHomeChangeEditModeReq extends PacketHandler {
session.send(new PacketHomeComfortInfoNotify(session.getPlayer())); session.send(new PacketHomeComfortInfoNotify(session.getPlayer()));
if (!req.getIsEnterEditMode()) { if (!req.getIsEnterEditMode()) {
var scene = session.getPlayer().getScene(); var scene = (HomeScene) session.getPlayer().getScene();
scene.addEntities( scene.onLeaveEditMode();
session
.getPlayer()
.getCurHomeWorld()
.getHome()
.getHomeSceneItem(scene.getId())
.getAnimals(scene));
} }
session.send(new PacketHomeChangeEditModeRsp(req.getIsEnterEditMode())); session.send(new PacketHomeChangeEditModeRsp(req.getIsEnterEditMode()));

View File

@ -1,7 +1,5 @@
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.world.Position;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
@ -21,7 +19,8 @@ public class HandlerHomeChangeModuleReq extends PacketHandler {
HomeChangeModuleReqOuterClass.HomeChangeModuleReq req = HomeChangeModuleReqOuterClass.HomeChangeModuleReq req =
HomeChangeModuleReqOuterClass.HomeChangeModuleReq.parseFrom(payload); HomeChangeModuleReqOuterClass.HomeChangeModuleReq.parseFrom(payload);
if (!session.getPlayer().getCurHomeWorld().getGuests().isEmpty()) { var homeWorld = session.getPlayer().getCurHomeWorld();
if (!homeWorld.getGuests().isEmpty()) {
session.send(new PacketHomeChangeModuleRsp()); session.send(new PacketHomeChangeModuleRsp());
return; return;
} }
@ -33,13 +32,10 @@ public class HandlerHomeChangeModuleReq extends PacketHandler {
session.send(new PacketHomeComfortInfoNotify(session.getPlayer())); session.send(new PacketHomeComfortInfoNotify(session.getPlayer()));
int realmId = 2000 + req.getTargetModuleId(); int realmId = 2000 + req.getTargetModuleId();
var scene = homeWorld.getSceneById(realmId);
var pos = scene.getScriptManager().getConfig().born_pos;
Scene scene = session.getPlayer().getWorld().getSceneById(realmId); homeWorld.transferPlayerToScene(session.getPlayer(), realmId, TeleportType.WAYPOINT, pos);
Position pos = scene.getScriptManager().getConfig().born_pos; homeWorld.refreshModuleManager();
session
.getPlayer()
.getWorld()
.transferPlayerToScene(session.getPlayer(), realmId, TeleportType.WAYPOINT, pos);
} }
} }

View File

@ -1,10 +1,9 @@
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.entity.EntityHomeAnimal; import emu.grasscutter.game.home.HomeScene;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.VisionTypeOuterClass;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeEnterEditModeFinishRsp; import emu.grasscutter.server.packet.send.PacketHomeEnterEditModeFinishRsp;
@ -17,12 +16,8 @@ public class HandlerHomeEnterEditModeFinishReq extends PacketHandler {
* This packet is about the edit mode * This packet is about the edit mode
*/ */
var scene = session.getPlayer().getScene(); var scene = (HomeScene) session.getPlayer().getScene();
scene.removeEntities( scene.onEnterEditModeFinish();
scene.getEntities().values().stream()
.filter(gameEntity -> gameEntity instanceof EntityHomeAnimal)
.toList(),
VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE);
session.send(new PacketHomeEnterEditModeFinishRsp()); session.send(new PacketHomeEnterEditModeFinishRsp());
} }

View File

@ -1,6 +1,8 @@
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.*; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.OtherPlayerEnterHomeNotifyOuterClass; import emu.grasscutter.net.proto.OtherPlayerEnterHomeNotifyOuterClass;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
@ -26,6 +28,12 @@ public class HandlerHomeSceneInitFinishReq extends PacketHandler {
} }
} }
curHomeWorld.ifHost(
session.getPlayer(),
player -> {
player.sendPacket(new PacketHomeAvatarRewardEventNotify(player));
player.sendPacket(new PacketHomeAvatarSummonAllEventNotify(player));
});
session.send(new PacketHomeMarkPointNotify(session.getPlayer())); session.send(new PacketHomeMarkPointNotify(session.getPlayer()));
session.send(new PacketHomeSceneInitFinishRsp()); session.send(new PacketHomeSceneInitFinishRsp());

View File

@ -5,10 +5,7 @@ import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeUpdateArrangementInfoReqOuterClass; import emu.grasscutter.net.proto.HomeUpdateArrangementInfoReqOuterClass;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeAvatarTalkFinishInfoNotify; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.server.packet.send.PacketHomeBasicInfoNotify;
import emu.grasscutter.server.packet.send.PacketHomeMarkPointNotify;
import emu.grasscutter.server.packet.send.PacketHomeUpdateArrangementInfoRsp;
@Opcodes(PacketOpcodes.HomeUpdateArrangementInfoReq) @Opcodes(PacketOpcodes.HomeUpdateArrangementInfoReq)
public class HandlerHomeUpdateArrangementInfoReq extends PacketHandler { public class HandlerHomeUpdateArrangementInfoReq extends PacketHandler {
@ -22,14 +19,17 @@ public class HandlerHomeUpdateArrangementInfoReq extends PacketHandler {
session.getPlayer().getHome().getHomeSceneItem(session.getPlayer().getSceneId()); session.getPlayer().getHome().getHomeSceneItem(session.getPlayer().getSceneId());
var roomSceneId = homeScene.getRoomSceneId(); var roomSceneId = homeScene.getRoomSceneId();
homeScene.update(req.getSceneArrangementInfo()); homeScene.update(req.getSceneArrangementInfo(), session.getPlayer());
if (roomSceneId != homeScene.getRoomSceneId()) { if (roomSceneId != homeScene.getRoomSceneId()) {
session.getPlayer().getHome().onMainHouseChanged(); session.getPlayer().getHome().onMainHouseChanged();
} }
session.getPlayer().getCurHomeWorld().getModuleManager().onUpdateArrangement();
session.send(new PacketHomeAvatarRewardEventNotify(session.getPlayer()));
session.send( session.send(
new PacketHomeBasicInfoNotify(session.getPlayer(), session.getPlayer().isInEditMode())); new PacketHomeBasicInfoNotify(session.getPlayer(), session.getPlayer().isInEditMode()));
session.send(new PacketHomeAvatarTalkFinishInfoNotify(session.getPlayer())); session.send(new PacketHomeAvatarTalkFinishInfoNotify(session.getPlayer()));
session.send(new PacketHomeAvatarSummonAllEventNotify(session.getPlayer()));
session.send(new PacketHomeMarkPointNotify(session.getPlayer())); session.send(new PacketHomeMarkPointNotify(session.getPlayer()));
session.getPlayer().getHome().save(); session.getPlayer().getHome().save();

View File

@ -2,6 +2,7 @@ package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.game.quest.enums.QuestCond;
import emu.grasscutter.game.quest.enums.QuestContent; import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.net.packet.*; import emu.grasscutter.net.packet.*;
import emu.grasscutter.net.proto.ItemGivingReqOuterClass.ItemGivingReq; import emu.grasscutter.net.proto.ItemGivingReqOuterClass.ItemGivingReq;
@ -50,8 +51,9 @@ public final class HandlerItemGivingReq extends PacketHandler {
player.sendPacket(new PacketItemGivingRsp(giveId, Mode.EXACT_SUCCESS)); player.sendPacket(new PacketItemGivingRsp(giveId, Mode.EXACT_SUCCESS));
// Remove the action from the active givings. // Remove the action from the active givings.
questManager.removeGivingItemAction(giveId); questManager.removeGivingItemAction(giveId);
// Queue the content action. // Queue the content and condition actions.
questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, 0); questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, 0);
questManager.queueEvent(QuestCond.QUEST_COND_ITEM_GIVING_FINISHED, giveId, 0);
} }
case GIVING_METHOD_VAGUE_GROUP -> { case GIVING_METHOD_VAGUE_GROUP -> {
var matchedGroups = new ArrayList<Integer>(); var matchedGroups = new ArrayList<Integer>();
@ -96,8 +98,11 @@ public final class HandlerItemGivingReq extends PacketHandler {
player.sendPacket(new PacketItemGivingRsp(matchedGroups.get(0), Mode.GROUP_SUCCESS)); player.sendPacket(new PacketItemGivingRsp(matchedGroups.get(0), Mode.GROUP_SUCCESS));
// Mark the giving action as completed. // Mark the giving action as completed.
questManager.markCompleted(giveId); questManager.markCompleted(giveId);
// Queue the content action. // Queue the content and condition actions.
questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, 0); questManager.queueEvent(
QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, matchedGroups.get(0));
questManager.queueEvent(
QuestCond.QUEST_COND_ITEM_GIVING_FINISHED, giveId, matchedGroups.get(0));
} }
} }
} }

View File

@ -0,0 +1,19 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeAvatarAllFinishRewardNotifyOuterClass;
public class PacketHomeAvatarAllFinishRewardNotify extends BasePacket {
public PacketHomeAvatarAllFinishRewardNotify(Player player) {
super(PacketOpcodes.HomeAvatarAllFinishRewardNotify);
var list = player.getHome().getFinishedRewardEventIdSet();
if (list != null) {
this.setData(
HomeAvatarAllFinishRewardNotifyOuterClass.HomeAvatarAllFinishRewardNotify.newBuilder()
.addAllEventIdList(player.getHome().getFinishedRewardEventIdSet()));
}
}
}

View File

@ -0,0 +1,27 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeAvatarRewardEventGetRspOuterClass;
import java.util.List;
public class PacketHomeAvatarRewardEventGetRsp extends BasePacket {
public PacketHomeAvatarRewardEventGetRsp(int eventId, List<GameItem> rewards) {
super(PacketOpcodes.HomeAvatarRewardEventGetRsp);
this.setData(
HomeAvatarRewardEventGetRspOuterClass.HomeAvatarRewardEventGetRsp.newBuilder()
.setEventId(eventId)
.addAllItemList(rewards.stream().map(GameItem::toItemParam).toList()));
}
public PacketHomeAvatarRewardEventGetRsp(int eventId, int retcode) {
super(PacketOpcodes.HomeAvatarRewardEventGetRsp);
this.setData(
HomeAvatarRewardEventGetRspOuterClass.HomeAvatarRewardEventGetRsp.newBuilder()
.setEventId(eventId)
.setRetcode(retcode));
}
}

View File

@ -0,0 +1,12 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
public class PacketHomeAvatarRewardEventNotify extends BasePacket {
public PacketHomeAvatarRewardEventNotify(Player homeOwner) {
super(PacketOpcodes.HomeAvatarRewardEventNotify);
this.setData(homeOwner.getCurHomeWorld().getModuleManager().toRewardEventProto());
}
}

View File

@ -0,0 +1,12 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
public class PacketHomeAvatarSummonAllEventNotify extends BasePacket {
public PacketHomeAvatarSummonAllEventNotify(Player homeOwner) {
super(PacketOpcodes.HomeAvatarSummonAllEventNotify);
this.setData(homeOwner.getCurHomeWorld().getModuleManager().toSummonEventProto());
}
}

View File

@ -0,0 +1,24 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.home.suite.event.HomeAvatarSummonEvent;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeAvatarSummonEventRspOuterClass;
public class PacketHomeAvatarSummonEventRsp extends BasePacket {
public PacketHomeAvatarSummonEventRsp(HomeAvatarSummonEvent event) {
super(PacketOpcodes.HomeAvatarSummonEventRsp);
this.setData(
HomeAvatarSummonEventRspOuterClass.HomeAvatarSummonEventRsp.newBuilder()
.setEventId(event.getEventId()));
}
public PacketHomeAvatarSummonEventRsp(int retcode) {
super(PacketOpcodes.HomeAvatarSummonEventRsp);
this.setData(
HomeAvatarSummonEventRspOuterClass.HomeAvatarSummonEventRsp.newBuilder()
.setRetcode(retcode));
}
}

View File

@ -0,0 +1,15 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeAvatarSummonFinishRspOuterClass;
public class PacketHomeAvatarSummonFinishRsp extends BasePacket {
public PacketHomeAvatarSummonFinishRsp(int eventId) {
super(PacketOpcodes.HomeAvatarSummonFinishRsp);
this.setData(
HomeAvatarSummonFinishRspOuterClass.HomeAvatarSummonFinishRsp.newBuilder()
.setEventId(eventId));
}
}

View File

@ -0,0 +1,15 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlayerQuitFromHomeNotifyOuterClass;
public class PacketPlayerQuitFromHomeNotify extends BasePacket {
public PacketPlayerQuitFromHomeNotify(
PlayerQuitFromHomeNotifyOuterClass.PlayerQuitFromHomeNotify.QuitReason reason) {
super(PacketOpcodes.PlayerQuitFromHomeNotify);
this.setData(
PlayerQuitFromHomeNotifyOuterClass.PlayerQuitFromHomeNotify.newBuilder().setReason(reason));
}
}

View File

@ -0,0 +1,155 @@
package emu.grasscutter.utils;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
public abstract class Either<L, R> {
private static final class Left<L, R> extends Either<L, R> {
private final L value;
public Left(L value) {
this.value = value;
}
@Override
public <U, V> Either<U, V> mapBoth(
Function<? super L, ? extends U> f1, Function<? super R, ? extends V> f2) {
return new Left<>(f1.apply(this.value));
}
@Override
public <T> T map(Function<? super L, ? extends T> l, Function<? super R, ? extends T> r) {
return l.apply(this.value);
}
@Override
public Either<L, R> ifLeft(Consumer<? super L> consumer) {
consumer.accept(this.value);
return this;
}
@Override
public Either<L, R> ifRight(Consumer<? super R> consumer) {
return this;
}
@Override
public Optional<L> left() {
return Optional.of(this.value);
}
@Override
public Optional<R> right() {
return Optional.empty();
}
@Override
public String toString() {
return "Left[" + this.value + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Left<?, ?> left = (Left<?, ?>) o;
return Objects.equals(value, left.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}
private static final class Right<L, R> extends Either<L, R> {
private final R value;
public Right(R value) {
this.value = value;
}
@Override
public <U, V> Either<U, V> mapBoth(
Function<? super L, ? extends U> f1, Function<? super R, ? extends V> f2) {
return new Right<>(f2.apply(this.value));
}
@Override
public <T> T map(Function<? super L, ? extends T> l, Function<? super R, ? extends T> r) {
return r.apply(this.value);
}
@Override
public Either<L, R> ifLeft(Consumer<? super L> consumer) {
return this;
}
@Override
public Either<L, R> ifRight(Consumer<? super R> consumer) {
consumer.accept(this.value);
return this;
}
@Override
public Optional<L> left() {
return Optional.empty();
}
@Override
public Optional<R> right() {
return Optional.of(this.value);
}
@Override
public String toString() {
return "Right[" + this.value + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Right<?, ?> right = (Right<?, ?>) o;
return Objects.equals(value, right.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}
private Either() {}
public abstract <U, V> Either<U, V> mapBoth(
Function<? super L, ? extends U> f1, Function<? super R, ? extends V> f2);
public abstract <T> T map(Function<? super L, ? extends T> l, Function<? super R, ? extends T> r);
public abstract Either<L, R> ifLeft(Consumer<? super L> consumer);
public abstract Either<L, R> ifRight(Consumer<? super R> consumer);
public abstract Optional<L> left();
public abstract Optional<R> right();
public <T> Either<T, R> mapLeft(Function<? super L, ? extends T> l) {
return map(t -> left(l.apply(t)), Either::right);
}
public <T> Either<L, T> mapRight(Function<? super R, ? extends T> l) {
return map(Either::left, t -> right(l.apply(t)));
}
public static <L, R> Either<L, R> left(L value) {
return new Left<>(value);
}
public static <L, R> Either<L, R> right(R value) {
return new Right<>(value);
}
}

View File

@ -260,7 +260,7 @@
"refreshed": "Группа %s обновлена." "refreshed": "Группа %s обновлена."
}, },
"cutscene": { "cutscene": {
"description": "Odtwarza przerywnik filmowy" "description": "Проигрывает кат-сцену"
}, },
"sound": { "sound": {
"description": "Проигрывает звук" "description": "Проигрывает звук"
@ -411,7 +411,7 @@
"description": "Генерирует отладочную информацию для решения проблем." "description": "Генерирует отладочную информацию для решения проблем."
}, },
"debug": { "debug": {
"description": "🇺🇸Useful debugging commands for developers." "description": "Полезные отладочные команды для разработкиков."
} }
}, },
"gacha": { "gacha": {
@ -451,9 +451,9 @@
}, },
"plugin": { "plugin": {
"directory_failed": "Ошибка создания директории плагинов: ", "directory_failed": "Ошибка создания директории плагинов: ",
"unable_to_load": "Невозможно загрудить плагин.", "unable_to_load": "Невозможно загрузить плагин.",
"invalid_config": "Плагин %s имеет недопустимый файл конфигурации.", "invalid_config": "Плагин %s имеет недопустимый файл конфигурации.",
"invalid_main_class": "Плагин %s имеет неверный главный класс.", "invalid_main_class": "Плагин %s имеет некорректный главный класс.",
"missing_config": "Плагин %s не имеет корректного файла конфигурации.", "missing_config": "Плагин %s не имеет корректного файла конфигурации.",
"failed_to_load_plugin": "Ошибка загрузки плагина: %s", "failed_to_load_plugin": "Ошибка загрузки плагина: %s",
"failed_to_load": "Не удалось загрузить Плагин.", "failed_to_load": "Не удалось загрузить Плагин.",