96 Commits

Author SHA1 Message Date
8c2d00fcd3 fix README.md build badge (#2243)
* fix README.md build badge

* fix README_XXX.md build badge
2023-07-01 01:17:03 -04:00
308686d9e7 Format code [skip actions] 2023-06-27 05:51:09 +00:00
83d447cfc2 Update region logic (#2240) 2023-06-27 01:49:24 -04:00
4ec274f5c5 Set event source for group variable changes to the variable name (#2231) 2023-06-25 10:45:37 -04:00
30d093f348 Update ScriptLib.java (#2227) 2023-06-24 00:37:13 -04:00
9fd5f7665c Fix unlogging quests (#2226) 2023-06-23 23:03:14 -04:00
55840bcdb6 Synchronize the Chinese README with the English version (#2224)
* Synchronize the Chinese README with the English version

* Update Chinese README translation

Better formatting and fixing several words that were not translated.
2023-06-22 16:42:35 -04:00
e706cce802 Format code [skip actions] 2023-06-20 20:38:14 +00:00
b58caf0632 Fix Librarian Story Quest (#2218)
* Fix Librarian Story Quest

* People die if they are killed

You want to die people instead of remove them so they play their sweet death animations.

* Nope. I take it back. Scriptlib is the wierd one to think removeEntity removes the entity.

* One must stop editing the code directly.

* Update EntityType.java

* Add warnings per Hartie

* Per Hartie, change getEntityType to EntityType
2023-06-20 16:37:00 -04:00
97b28b13fe Format code [skip actions] 2023-06-17 19:58:14 +00:00
4ebe6fbf63 dungeon drop implementation (#2215)
* dungeon drop implementation

* Update src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

---------

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
2023-06-17 15:56:47 -04:00
06d5bf7098 Temporary fix to scene reference 2023-06-17 11:24:46 -04:00
9d94888da3 Fix race condition with worktops (#2216)
* Fix race condition with worktops

* Update ScriptLib.java

* Update ScriptLib.java

---------

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
2023-06-17 11:00:10 -04:00
86036682d7 Format code [skip actions] 2023-06-17 03:00:10 +00:00
762e7ae301 Fix ContentNotFinishPlot 2023-06-16 22:58:49 -04:00
31cef88ef7 Format code [skip actions] 2023-06-16 18:28:59 +00:00
c3339de184 Resume the app token exchanger (#2209) 2023-06-16 14:27:14 -04:00
e382c6d691 Format code [skip actions] 2023-06-16 18:06:43 +00:00
6b3f19e588 fix giveall doesn't give everything (#2210)
* fix giveall doesn't give everything

* avoid unnecessary failure to add items by catching exception earlier

* switch to use grasscutter logger

* use debug()
2023-06-16 14:05:33 -04:00
47172c995f Format code [skip actions] 2023-06-16 18:05:28 +00:00
6da5343df0 Do not unload groups asked for by quests (#2212) 2023-06-16 14:04:58 -04:00
89376d58bf Change method of not ticking empty scenes (#2211) 2023-06-16 14:04:16 -04:00
248af4abfb Update VisionLevelType.java (#2207) 2023-06-13 11:27:24 -04:00
a7f78c7759 Skip invalid plugins (#2206) 2023-06-13 11:24:02 -04:00
baac48c4a0 Format code [skip actions] 2023-06-11 20:26:35 +00:00
6c89998759 Fix KillSelf 2023-06-11 16:24:42 -04:00
3cc5e6b4e8 Disclaimer 2023-06-11 16:15:15 -04:00
0f43e18d70 Fix some affixes not working 2023-06-11 16:14:38 -04:00
1c9f32cbef Fix a bit of un-researched action handling 2023-06-11 16:12:57 -04:00
d933ca6d02 Format code [skip actions] 2023-06-11 03:33:37 +00:00
3d62e72aa0 Format code [skip actions] 2023-06-11 03:32:55 +00:00
15699e562a Fix lock clock (#2201)
* Fix lock clock

* Update src/main/java/emu/grasscutter/game/world/World.java

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update src/main/java/emu/grasscutter/server/packet/recv/HandlerClientLockGameTimeNotify.java

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update src/main/java/emu/grasscutter/server/packet/recv/HandlerClientLockGameTimeNotify.java

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

---------

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
2023-06-10 23:32:23 -04:00
2788206934 Almost fully fix Chasing Shadows (#2202) 2023-06-10 23:31:57 -04:00
9dbeb2172d fix description of command quest and list (#2203)
* fix description of command `quest` and `list`

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

Co-authored-by: Der Chien <b03902015@ntu.edu.tw>

* Update QuestCommand.java

---------

Co-authored-by: Der Chien <b03902015@ntu.edu.tw>
2023-06-10 23:31:39 -04:00
55cb7ab967 Repair README.md 2023-06-10 23:31:12 -04:00
944db42762 Update quick start guide (#2198)
* Update quick start guide

Co-Authored-By: Nazrin <1877986+scooterboo@users.noreply.github.com>

* Update README.md

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update README.md

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update README.md

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update README.md

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update README.md

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update README.md

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update README.md

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

---------

Co-authored-by: Nazrin <1877986+scooterboo@users.noreply.github.com>
Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
2023-06-10 23:30:28 -04:00
1ed89598ff Add option "all" for UnlockMap and change the default behavior for "/prop unlockmap on" (#2196)
* Do not unlock unnecessary scene points during '/prop unlockmap on'

* Format code [skip actions]

* Backup scenePoints since we might modify it

* Format code [skip actions]

* Add 'all' for UnlockMap

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-06-09 13:31:11 -04:00
4093420c90 Format code [skip actions] 2023-06-09 17:29:36 +00:00
a1f75e1537 Format code [skip actions] 2023-06-09 17:29:26 +00:00
e6d32f5599 Make ice dude show up (#2200)
* Make ice dude show up

* replace contains with equals

Might as well fix this while I'm here.
"leave" and "enter" have the same number of letters, so it works.

* empty strings suck

* Update SceneTrigger.java

---------

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
2023-06-09 13:28:28 -04:00
b412a24657 Smarter NPC loading (#2199) 2023-06-09 13:27:34 -04:00
b4b0b8d2a8 Fix cutscene and sound permissions (#2197) 2023-06-07 11:57:59 -04:00
d8d31f3afe Update AvatarUpgradeRspOuterClass.java (#2193) 2023-06-06 16:39:46 -04:00
7fb9913c4f Format code [skip actions] 2023-06-06 03:28:38 +00:00
8472c36490 Implement SET_KILLED_STATE 2023-06-05 23:27:14 -04:00
ddb76a0c2a Format code [skip actions] 2023-06-04 21:57:29 +00:00
c40213affc Action id mapping fix 2023-06-04 17:55:19 -04:00
f389d2fb28 Handle SetRandomOverrideMapValue 2023-06-04 17:53:48 -04:00
b5595c3fab Fix dropType de-serialization
enum edition
2023-06-04 17:53:30 -04:00
ecb6145e54 Revert "Fix dropType de-serialization" 2023-06-04 17:52:12 -04:00
eb17d65330 Revert "Format code [skip actions]"
This reverts commit 22e953b636.
2023-06-04 17:50:55 -04:00
22e953b636 Format code [skip actions] 2023-06-04 19:56:38 +00:00
6080297be9 Fix dropType de-serialization 2023-06-04 15:55:06 -04:00
6d6e6a041d Format code [skip actions] 2023-06-04 05:01:54 +00:00
b09c0d48bf Fix ActionGenerateElemBall 2023-06-04 01:00:27 -04:00
b050337216 Format code [skip actions] 2023-06-04 04:29:25 +00:00
ac3ccf93f3 Little fix 2023-06-04 00:27:15 -04:00
0167709070 Implement GenerateElemBall action 2023-06-04 00:27:01 -04:00
63ccff8755 Shut down the game server when Grasscutter is about to shut down 2023-06-04 00:26:06 -04:00
494cd3b28c Format code [skip actions] 2023-06-03 19:37:54 +00:00
f9dffba27a Merge remote-tracking branch 'origin/development' into development 2023-06-03 15:36:05 -04:00
f85070abdc Make subfield & drop classes final 2023-06-03 15:36:00 -04:00
4de21d4a40 Remove redundant script event calling when changing the time 2023-06-03 15:35:04 -04:00
56f09e87a1 Fix ore dropping and implement subfields 2023-06-03 15:29:45 -04:00
9dae3cbcc7 Added localid missing actions (needs testing) 2023-06-03 15:27:02 -04:00
d18a8c31a6 Add SystemHintType enum 2023-06-03 15:23:27 -04:00
f977679c1c Fix handbook generation being performed when all conditions weren't met 2023-06-03 15:23:05 -04:00
8fc17ede99 Format code [skip actions] 2023-06-03 16:43:21 +00:00
73e181df9b Merge remote-tracking branch 'origin/development' into development 2023-06-03 12:41:51 -04:00
5441094e47 Fix NullPointerException when trying to find gadgets in a group suite 2023-06-03 12:41:20 -04:00
7fc7b5087c Format code [skip actions] 2023-06-03 14:55:55 +00:00
e28575c80f Fix battle in front of glowy stag god (#2188)
* Fix battle in front of glowy stag god

* Don't do a rollback when starting a quest. We're better than that.
2023-06-03 10:54:46 -04:00
853a67d48e Format code [skip actions] 2023-06-03 01:43:44 +00:00
e8bfdc3c01 Send system hint when a player joins/leaves a world in multiplayer 2023-06-02 21:41:47 -04:00
8870675dcd Remove dead entities on scene tick 2023-06-02 21:41:10 -04:00
43fa6efec9 Format code [skip actions] 2023-06-02 18:26:45 +00:00
d9e8810a5c Fix invalid JSON exception when querying gacha records 2023-06-02 14:15:39 -04:00
82189e03ed Add debug command for checking triggers on a group 2023-06-01 21:28:46 -04:00
cef8b53dd6 Fix quest chests not having drop data 2023-06-01 21:28:12 -04:00
43f3494073 Check for an invalid avatar in a team 2023-06-01 20:00:17 -04:00
20f0cda3e0 Fix chasing shadows (mostly) 2023-06-01 19:59:36 -04:00
8692405363 Wait for thread executors to shut down 2023-06-01 18:17:48 -04:00
9dd514a73b Catch exception when unable to write to KCP client 2023-06-01 18:17:15 -04:00
1940b22dc5 Fix statue unlocks, and probably other quests involving talks 2023-06-01 18:13:41 -04:00
bb1729c227 Bump version to 1.6.1 2023-06-01 14:35:01 -04:00
4870871b2c Move rewind data logger call to debug 2023-06-01 14:27:38 -04:00
2c7c8bf4fd Add option for enabling costumes on trial avatars 2023-06-01 14:23:12 -04:00
deaa13c2af Add check for legacy API method calls on plugins 2023-06-01 14:19:05 -04:00
fd40575cb4 Fix issue with time when a player reconnects without a world 2023-06-01 14:18:34 -04:00
3c0e834348 Fix FieldFetch not getting fields from superclasses 2023-06-01 14:18:12 -04:00
27be6c31e6 Fix a typo I left in Player.java (#2180)
ENTER_REGION_ ->LEAVE_REGION_
Took the opportunity to refactor it so that we only calculate the string once.
2023-06-01 12:30:19 -04:00
87269e9ded README.md (#2181)
Remove mention of unstable branch in README.md
2023-06-01 12:29:42 -04:00
46fee38217 Fix ability modifiers NullPointerException 2023-06-01 03:30:00 -04:00
6e5971df62 Fix stamina casting exception 2023-06-01 03:27:48 -04:00
98375deac9 Downgrade development version to 1.6.0 2023-06-01 02:37:01 -04:00
97c70f7877 Fix issues with regions (#2179)
Luckily, SceneRegion and TriggerExcelConfigData both have group numbers, so we can use those to differentiate regions!
2023-06-01 02:04:18 -04:00
107 changed files with 2405 additions and 601 deletions

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>
@ -22,51 +22,23 @@
**Note**: For support please join our [Discord](https://discord.gg/T5vZU6UyeG).
### Requirements
### Quick Start (automatic)
* [Java SE - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) or higher
- 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 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)
**Note:** If you just want to **run it**, then **jre** only is fine.
- 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.
- Click `Download All-in-One`
- Click the gear in the upper right corner
- Set the game Install path to where your game is located.
- Set the Custom Java Path to `C:\Program Files\Java\jdk-17\bin\java.exe`
- Leave all other settings on default
* [MongoDB](https://www.mongodb.com/try/download/community) (recommended 4.0+)
* Proxy Daemon: [mitmproxy](https://mitmproxy.org/) (mitmdump, recommended), [Fiddler Classic](https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe), etc.
### Running
**Note:** If you updated from an older version, delete `config.json` to regenerate it.
1. Get `grasscutter.jar`
- Download from [releases](https://github.com/Grasscutters/Grasscutter/releases/latest) or [actions](https://github.com/Grasscutters/Grasscutter/actions/workflows/build.yml) or [build the server by yourself](#building).
2. Create a `resources` folder in the directory where grasscutter.jar is located and move your `BinOutput, ExcelBinOutput, Readables, Scripts, Subtitle, TextMap` folders there *(Check the [wiki](https://github.com/Grasscutters/Grasscutter/wiki) for more details how to get those.)*
3. Run Grasscutter with `java -jar grasscutter.jar`. **Make sure mongodb service is running as well.**
### Connecting with the client
½. Create an account in the server console using this [command](https://github.com/Grasscutters/Grasscutter/wiki/Commands#:~:text=account%20%3Ccreate|delete%3E%20%3Cusername%3E%20[UID]).
1. Redirect traffic: (choose one only)
- mitmdump: `mitmdump -s proxy.py -k`
- Trust CA certificate:
- The CA certificate is usually stored in `%USERPROFILE%\.mitmproxy`, double click `mitmproxy-ca-cert.cer` to [install](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) or...
- Via command line *(needs administration privileges)*
```shell
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
```
- Fiddler Classic: Run Fiddler Classic, turn on `Decrypt HTTPS traffic` in (Tools -> Options -> HTTPS) and change the default port in (Tools -> Options -> Connections) to anything other than `8888`, load [this script](https://github.com/Grasscutters/Grasscutter/wiki/Resources#fiddler-classic-jscript) (copy and paste the script in the `FiddlerScript` tab) and click the `Save Script` button.
- [Hosts file](https://github.com/Grasscutters/Grasscutter/wiki/Resources#hosts-file)
2. Set network proxy to `127.0.0.1:8080` or the proxy port you specified.
- For mitmproxy: After setting up the network proxy and installing the certificate, check http://mitm.it/ if traffic is passing through mitmproxy.
**You can also use `start.cmd` to start servers and proxy daemons automatically, but you have to set up `JAVA_HOME` environment and configure the `start_config.cmd` file.**
- Click the small button next to launch.
- Click the launch button.
- Log in with whatever username you want. Password doesn't matter.
### Building
@ -80,7 +52,7 @@ Grasscutter uses Gradle to handle dependencies & building.
##### Windows
```shell
git clone --recurse-submodules -b unstable https://github.com/Grasscutters/Grasscutter.git
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter
.\gradlew.bat # Setting up environments
.\gradlew jar # Compile
@ -89,7 +61,7 @@ cd Grasscutter
##### Linux (GNU)
```bash
git clone --recurse-submodules -b unstable https://github.com/Grasscutters/Grasscutter.git
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter
chmod +x gradlew
./gradlew jar # Compile

View File

@ -57,7 +57,7 @@ sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
group = 'io.grasscutter'
version = '2.0.0-unstable'
version = '1.6.1'
java {
withJavadocJar()
@ -335,18 +335,48 @@ tasks.register('generateHandbook') {
return
}
def nodeVersion = {
def npmVersion = {
try {
return 'node --version'.execute().text.trim()
return 'npm --version'.execute().text.trim()
} catch (ignored) {
return 'NODE_NOT_FOUND'
return 'NPM_NOT_FOUND'
}
}
// Check if Node is installed.
if (nodeVersion() == 'NODE_NOT_FOUND') {
println('Node is not installed. Skipping handbook generation.')
if (npmVersion() == 'NPM_NOT_FOUND') {
println('NPM is not installed. Skipping handbook generation.')
} else {
// Check if the handbook resources are present.
if (!file('src/handbook/data/commands.json')) {
println('Command data was not found. Skipping handbook generation.')
return
}
if (!file('src/handbook/data/avatars.csv')) {
println('Avatar data was not found. Skipping handbook generation.')
return
}
if (!file('src/handbook/data/entities.csv')) {
println('Entity data was not found. Skipping handbook generation.')
return
}
if (!file('src/handbook/data/items.csv')) {
println('Item data was not found. Skipping handbook generation.')
return
}
if (!file('src/handbook/data/mainquests.csv')) {
println('Main quest data was not found. Skipping handbook generation.')
return
}
if (!file('src/handbook/data/quests.csv')) {
println('Quest data was not found. Skipping handbook generation.')
return
}
if (!file('src/handbook/data/scenes.csv')) {
println('Scene data was not found. Skipping handbook generation.')
return
}
// Build the handbook.
var npm = 'npm'
if (Os.isFamily(Os.FAMILY_WINDOWS))

View File

@ -1,5 +1,5 @@
![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="Documention" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><img alt="Documention" 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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,5 +1,5 @@
![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="Documention" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><img alt="Documention" 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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,5 +1,5 @@
![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="Documention" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><img alt="Documention" 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>

View File

@ -1,5 +1,5 @@
![Grasscutter](https://socialify.git.ci/Grasscutters/Grasscutter/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fs2.loli.net%2F2022%2F04%2F25%2FxOiJn7lCdcT5Mw1.png&name=1&owner=1&pulls=1&stargazers=1&theme=Light)
<div align="center"><img alt="Documentation" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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>

View File

@ -1,11 +1,11 @@
![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="Documention" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><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) | [简中](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)
**注意:** 欢迎成为本项目的贡献者。但在提交 PR 之前, 请仔细阅读 [代码规范](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)。
**注意:** 我们始终欢迎项目的贡献者。但在做贡献之前,请仔细阅读我们的[代码规范](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)。
## 当前功能
@ -16,92 +16,59 @@
* 祈愿
* 多人游戏 *部分* 可用
* 从控制台生成魔物
* 物品 (接收或升级角色、武器等)
* 背包功能(接收或升级物品、角色等)。
## 快速设置指南
## 快速安装指南
**注意:** 如需帮助请加入 [Discord](https://discord.gg/T5vZU6UyeG)
**注意:** 如需帮助请加入我们的[Discord](https://discord.gg/T5vZU6UyeG)
### 环境需求
### 快速开始(全自动)
* [Java SE - 17](https://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)
- 获取游戏3.7正式版 (如果你没有3.7的客户端可以在这里找到https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/3.7.0.md)
**注意:** 如果想仅**运行服务端**, 只下载 **jre** 即可
- 下载[最新的Cultivation版本](https://github.com/Grasscutters/Cultivation/releases/latest)(使用以“.msi”为后缀的安装包
- 以管理员身份打开Culivation按右上角的下载按钮。
- 点击“下载 Grasscutter 一体化”
- 点击右上角的齿轮
- 将游戏安装路径设置为你游戏所在的位置。
- 将自定义Java路径设置为`C:\Program Files\Java\jdk-17\bin\java.exe`
- 保持所有其它设置为默认值
* [MongoDB](https://www.mongodb.com/try/download/community) (推荐 4.0+)
* 代理程序: [mitmproxy](https://mitmproxy.org/) (仅需 mitmdump推荐使用), [Fiddler Classic](https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe) 等
### 运行服务端
**注意:** 从旧版本升级到新版本, 需要删除 `config.json` 使其重新生成
1. 获取 `grasscutter.jar`
- 从 [actions](https://github.com/Grasscutters/Grasscutter/actions) 下载,或 [自行编译](#构建)
2. 在 JAR 文件根目录中创建 `resources` 文件夹并复制 `BinOutput``ExcelBinOutput` *(查看 [Wiki](https://github.com/Grasscutters/Grasscutter/wiki) 了解更多)*
3. **确认 MongoDB 服务运行正常后**,使用命令行 `java -jar grasscutter.jar` 运行 Grasscutter。
### 客户端连接
½. 在服务器控制台 [创建账户](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting)
1. 重定向流量: (选择其中一个)
- mitmdump: `mitmdump -s proxy.py -k`
信任 CA 证书:
**注意:** mitmproxy 的 CA 证书通常存放在 `%USERPROFILE%\ .mitmproxy`, 或者从 `http://mitm.it` 下载证书
双击 [安装根证书](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate)或者...
- 使用命令行
```shell
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
```
- Fiddler Classic: 运行 Fiddler Classic, 在设置中开启 `解密 https 通信` 并将端口设为除 `8888` 以外的任意端口 (工具 -> 选项 -> 连接) 并加载 [此脚本](https://github.lunatic.moe/fiddlerscript)
- [Hosts 文件](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. 设置代理为 `127.0.0.1:8080` 或你设置的端口
**也可直接运行 `start.cmd` 一键启动服务端并设置代理, 但设置 `JAVA_HOME` 环境变量并配置 `start_config.cmd`**
- 点击“启动”按钮旁边的小按钮。
- 点击“启动”按钮。
- 随便想一个用户名登录,不需要密码。
### 构建
Grasscutter 使用 Gradle 来处理依赖及编译
Grasscutter使用Gradle来处理依赖和构建
**前置依赖:**
**前置**
- [Java SE Development Kits - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
- [Java SE Development Kits - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)或更高版本
- [Git](https://git-scm.com/downloads)
##### Windows
```shell
git clone https://github.com/Grasscutters/Grasscutter.git
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter
.\gradlew.bat # 建立开发环境
.\gradlew.bat # 设置开发环境
.\gradlew jar # 编译
```
##### Linux
##### LinuxGNU
```bash
git clone https://github.com/Grasscutters/Grasscutter.git
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter
chmod +x gradlew
./gradlew jar # 编译
```
* 编译后的 JAR 文件会在源码根目录生成
你可以在项目的根目录找到输出的jar。
### 命令列表请到 [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands) 查看
### 故障排除
# 快速问题排除
* 如果编译失败, 请检查 JDK 安装是否正确 (需要 JDK 17 并确认 JDK 的 bin 文件夹处于环境变量 `PATH` 中)
* 客户端无法登录、连接、错误 4206 等其他问题... - 大部分情况是因为代理设置出现了*问题*。
如果使用 Fiddler请确认 Fiddler 监听端口不是 `8888`
* 启动顺序: MongoDB > Grasscutter > 代理程序 (mitmdump, Fiddler 等) > 客户端
获取常见问题的解决方案或寻求帮助,请加入[我们的Discord服务器](https://discord.gg/T5vZU6UyeG)并进入“support”频道。

View File

@ -1,5 +1,5 @@
![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="Documention" src="https://img.shields.io/badge/Wiki-Grasscutter-blue?style=for-the-badge&link=https://github.com/Grasscutters/Grasscutter/wiki&link=https://github.com/Grasscutters/Grasscutter/wiki"> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Grasscutters/Grasscutter?logo=java&style=for-the-badge"> <img alt="GitHub" src="https://img.shields.io/github/license/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/Grasscutters/Grasscutter?style=for-the-badge"> <img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/Grasscutters/Grasscutter/Build?logo=github&style=for-the-badge"></div>
<div align="center"><img alt="Documention" 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>

View File

@ -0,0 +1,539 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: AbilityActionSetRandomOverrideMapValue.proto
package emu.grasscutter.net.proto;
public final class AbilityActionSetRandomOverrideMapValueOuterClass {
private AbilityActionSetRandomOverrideMapValueOuterClass() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
public interface AbilityActionSetRandomOverrideMapValueOrBuilder extends
// @@protoc_insertion_point(interface_extends:AbilityActionSetRandomOverrideMapValue)
com.google.protobuf.MessageOrBuilder {
/**
* <code>float random_value = 1;</code>
* @return The randomValue.
*/
float getRandomValue();
}
/**
* Protobuf type {@code AbilityActionSetRandomOverrideMapValue}
*/
public static final class AbilityActionSetRandomOverrideMapValue extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:AbilityActionSetRandomOverrideMapValue)
AbilityActionSetRandomOverrideMapValueOrBuilder {
private static final long serialVersionUID = 0L;
// Use AbilityActionSetRandomOverrideMapValue.newBuilder() to construct.
private AbilityActionSetRandomOverrideMapValue(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private AbilityActionSetRandomOverrideMapValue() {
}
@java.lang.Override
@SuppressWarnings({"unused"})
protected java.lang.Object newInstance(
UnusedPrivateParameter unused) {
return new AbilityActionSetRandomOverrideMapValue();
}
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private AbilityActionSetRandomOverrideMapValue(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
if (extensionRegistry == null) {
throw new java.lang.NullPointerException();
}
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
case 13: {
randomValue_ = input.readFloat();
break;
}
default: {
if (!parseUnknownField(
input, unknownFields, extensionRegistry, tag)) {
done = true;
}
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.internal_static_AbilityActionSetRandomOverrideMapValue_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.internal_static_AbilityActionSetRandomOverrideMapValue_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue.class, emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue.Builder.class);
}
public static final int RANDOM_VALUE_FIELD_NUMBER = 1;
private float randomValue_;
/**
* <code>float random_value = 1;</code>
* @return The randomValue.
*/
@java.lang.Override
public float getRandomValue() {
return randomValue_;
}
private byte memoizedIsInitialized = -1;
@java.lang.Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
@java.lang.Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (randomValue_ != 0F) {
output.writeFloat(1, randomValue_);
}
unknownFields.writeTo(output);
}
@java.lang.Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (randomValue_ != 0F) {
size += com.google.protobuf.CodedOutputStream
.computeFloatSize(1, randomValue_);
}
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
}
@java.lang.Override
public boolean equals(final java.lang.Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue)) {
return super.equals(obj);
}
emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue other = (emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue) obj;
if (java.lang.Float.floatToIntBits(getRandomValue())
!= java.lang.Float.floatToIntBits(
other.getRandomValue())) return false;
if (!unknownFields.equals(other.unknownFields)) return false;
return true;
}
@java.lang.Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + RANDOM_VALUE_FIELD_NUMBER;
hash = (53 * hash) + java.lang.Float.floatToIntBits(
getRandomValue());
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
@java.lang.Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@java.lang.Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* Protobuf type {@code AbilityActionSetRandomOverrideMapValue}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:AbilityActionSetRandomOverrideMapValue)
emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValueOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.internal_static_AbilityActionSetRandomOverrideMapValue_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.internal_static_AbilityActionSetRandomOverrideMapValue_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue.class, emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue.Builder.class);
}
// Construct using emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessageV3
.alwaysUseFieldBuilders) {
}
}
@java.lang.Override
public Builder clear() {
super.clear();
randomValue_ = 0F;
return this;
}
@java.lang.Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.internal_static_AbilityActionSetRandomOverrideMapValue_descriptor;
}
@java.lang.Override
public emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue getDefaultInstanceForType() {
return emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue.getDefaultInstance();
}
@java.lang.Override
public emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue build() {
emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@java.lang.Override
public emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue buildPartial() {
emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue result = new emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue(this);
result.randomValue_ = randomValue_;
onBuilt();
return result;
}
@java.lang.Override
public Builder clone() {
return super.clone();
}
@java.lang.Override
public Builder setField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.setField(field, value);
}
@java.lang.Override
public Builder clearField(
com.google.protobuf.Descriptors.FieldDescriptor field) {
return super.clearField(field);
}
@java.lang.Override
public Builder clearOneof(
com.google.protobuf.Descriptors.OneofDescriptor oneof) {
return super.clearOneof(oneof);
}
@java.lang.Override
public Builder setRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
int index, java.lang.Object value) {
return super.setRepeatedField(field, index, value);
}
@java.lang.Override
public Builder addRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.addRepeatedField(field, value);
}
@java.lang.Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue) {
return mergeFrom((emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue other) {
if (other == emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue.getDefaultInstance()) return this;
if (other.getRandomValue() != 0F) {
setRandomValue(other.getRandomValue());
}
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
}
@java.lang.Override
public final boolean isInitialized() {
return true;
}
@java.lang.Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private float randomValue_ ;
/**
* <code>float random_value = 1;</code>
* @return The randomValue.
*/
@java.lang.Override
public float getRandomValue() {
return randomValue_;
}
/**
* <code>float random_value = 1;</code>
* @param value The randomValue to set.
* @return This builder for chaining.
*/
public Builder setRandomValue(float value) {
randomValue_ = value;
onChanged();
return this;
}
/**
* <code>float random_value = 1;</code>
* @return This builder for chaining.
*/
public Builder clearRandomValue() {
randomValue_ = 0F;
onChanged();
return this;
}
@java.lang.Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.setUnknownFields(unknownFields);
}
@java.lang.Override
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.mergeUnknownFields(unknownFields);
}
// @@protoc_insertion_point(builder_scope:AbilityActionSetRandomOverrideMapValue)
}
// @@protoc_insertion_point(class_scope:AbilityActionSetRandomOverrideMapValue)
private static final emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue();
}
public static emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<AbilityActionSetRandomOverrideMapValue>
PARSER = new com.google.protobuf.AbstractParser<AbilityActionSetRandomOverrideMapValue>() {
@java.lang.Override
public AbilityActionSetRandomOverrideMapValue parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new AbilityActionSetRandomOverrideMapValue(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<AbilityActionSetRandomOverrideMapValue> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<AbilityActionSetRandomOverrideMapValue> getParserForType() {
return PARSER;
}
@java.lang.Override
public emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_AbilityActionSetRandomOverrideMapValue_descriptor;
private static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_AbilityActionSetRandomOverrideMapValue_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n,AbilityActionSetRandomOverrideMapValue" +
".proto\">\n&AbilityActionSetRandomOverride" +
"MapValue\022\024\n\014random_value\030\001 \001(\002B\033\n\031emu.gr" +
"asscutter.net.protob\006proto3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
});
internal_static_AbilityActionSetRandomOverrideMapValue_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_AbilityActionSetRandomOverrideMapValue_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_AbilityActionSetRandomOverrideMapValue_descriptor,
new java.lang.String[] { "RandomValue", });
}
// @@protoc_insertion_point(outer_class_scope)
}

View File

@ -0,0 +1,545 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: AbilityMetaSetKilledState.proto
package emu.grasscutter.net.proto;
public final class AbilityMetaSetKilledStateOuterClass {
private AbilityMetaSetKilledStateOuterClass() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
public interface AbilityMetaSetKilledStateOrBuilder extends
// @@protoc_insertion_point(interface_extends:AbilityMetaSetKilledState)
com.google.protobuf.MessageOrBuilder {
/**
* <code>bool killed = 6;</code>
* @return The killed.
*/
boolean getKilled();
}
/**
* <pre>
* Handcrafted by Magix!
* </pre>
*
* Protobuf type {@code AbilityMetaSetKilledState}
*/
public static final class AbilityMetaSetKilledState extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:AbilityMetaSetKilledState)
AbilityMetaSetKilledStateOrBuilder {
private static final long serialVersionUID = 0L;
// Use AbilityMetaSetKilledState.newBuilder() to construct.
private AbilityMetaSetKilledState(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private AbilityMetaSetKilledState() {
}
@java.lang.Override
@SuppressWarnings({"unused"})
protected java.lang.Object newInstance(
UnusedPrivateParameter unused) {
return new AbilityMetaSetKilledState();
}
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private AbilityMetaSetKilledState(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
if (extensionRegistry == null) {
throw new java.lang.NullPointerException();
}
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
case 48: {
killed_ = input.readBool();
break;
}
default: {
if (!parseUnknownField(
input, unknownFields, extensionRegistry, tag)) {
done = true;
}
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.internal_static_AbilityMetaSetKilledState_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.internal_static_AbilityMetaSetKilledState_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState.class, emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState.Builder.class);
}
public static final int KILLED_FIELD_NUMBER = 6;
private boolean killed_;
/**
* <code>bool killed = 6;</code>
* @return The killed.
*/
@java.lang.Override
public boolean getKilled() {
return killed_;
}
private byte memoizedIsInitialized = -1;
@java.lang.Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
@java.lang.Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (killed_ != false) {
output.writeBool(6, killed_);
}
unknownFields.writeTo(output);
}
@java.lang.Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (killed_ != false) {
size += com.google.protobuf.CodedOutputStream
.computeBoolSize(6, killed_);
}
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
}
@java.lang.Override
public boolean equals(final java.lang.Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState)) {
return super.equals(obj);
}
emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState other = (emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState) obj;
if (getKilled()
!= other.getKilled()) return false;
if (!unknownFields.equals(other.unknownFields)) return false;
return true;
}
@java.lang.Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + KILLED_FIELD_NUMBER;
hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(
getKilled());
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
@java.lang.Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@java.lang.Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* <pre>
* Handcrafted by Magix!
* </pre>
*
* Protobuf type {@code AbilityMetaSetKilledState}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:AbilityMetaSetKilledState)
emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledStateOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.internal_static_AbilityMetaSetKilledState_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.internal_static_AbilityMetaSetKilledState_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState.class, emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState.Builder.class);
}
// Construct using emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessageV3
.alwaysUseFieldBuilders) {
}
}
@java.lang.Override
public Builder clear() {
super.clear();
killed_ = false;
return this;
}
@java.lang.Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.internal_static_AbilityMetaSetKilledState_descriptor;
}
@java.lang.Override
public emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState getDefaultInstanceForType() {
return emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState.getDefaultInstance();
}
@java.lang.Override
public emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState build() {
emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@java.lang.Override
public emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState buildPartial() {
emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState result = new emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState(this);
result.killed_ = killed_;
onBuilt();
return result;
}
@java.lang.Override
public Builder clone() {
return super.clone();
}
@java.lang.Override
public Builder setField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.setField(field, value);
}
@java.lang.Override
public Builder clearField(
com.google.protobuf.Descriptors.FieldDescriptor field) {
return super.clearField(field);
}
@java.lang.Override
public Builder clearOneof(
com.google.protobuf.Descriptors.OneofDescriptor oneof) {
return super.clearOneof(oneof);
}
@java.lang.Override
public Builder setRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
int index, java.lang.Object value) {
return super.setRepeatedField(field, index, value);
}
@java.lang.Override
public Builder addRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.addRepeatedField(field, value);
}
@java.lang.Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState) {
return mergeFrom((emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState other) {
if (other == emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState.getDefaultInstance()) return this;
if (other.getKilled() != false) {
setKilled(other.getKilled());
}
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
}
@java.lang.Override
public final boolean isInitialized() {
return true;
}
@java.lang.Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private boolean killed_ ;
/**
* <code>bool killed = 6;</code>
* @return The killed.
*/
@java.lang.Override
public boolean getKilled() {
return killed_;
}
/**
* <code>bool killed = 6;</code>
* @param value The killed to set.
* @return This builder for chaining.
*/
public Builder setKilled(boolean value) {
killed_ = value;
onChanged();
return this;
}
/**
* <code>bool killed = 6;</code>
* @return This builder for chaining.
*/
public Builder clearKilled() {
killed_ = false;
onChanged();
return this;
}
@java.lang.Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.setUnknownFields(unknownFields);
}
@java.lang.Override
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.mergeUnknownFields(unknownFields);
}
// @@protoc_insertion_point(builder_scope:AbilityMetaSetKilledState)
}
// @@protoc_insertion_point(class_scope:AbilityMetaSetKilledState)
private static final emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState();
}
public static emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<AbilityMetaSetKilledState>
PARSER = new com.google.protobuf.AbstractParser<AbilityMetaSetKilledState>() {
@java.lang.Override
public AbilityMetaSetKilledState parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new AbilityMetaSetKilledState(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<AbilityMetaSetKilledState> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<AbilityMetaSetKilledState> getParserForType() {
return PARSER;
}
@java.lang.Override
public emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_AbilityMetaSetKilledState_descriptor;
private static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_AbilityMetaSetKilledState_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\037AbilityMetaSetKilledState.proto\"+\n\031Abi" +
"lityMetaSetKilledState\022\016\n\006killed\030\006 \001(\010B\033" +
"\n\031emu.grasscutter.net.protob\006proto3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
});
internal_static_AbilityMetaSetKilledState_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_AbilityMetaSetKilledState_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_AbilityMetaSetKilledState_descriptor,
new java.lang.String[] { "Killed", });
}
// @@protoc_insertion_point(outer_class_scope)
}

View File

@ -19,11 +19,11 @@ public final class AvatarUpgradeRspOuterClass {
com.google.protobuf.MessageOrBuilder {
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
int getOldFightPropMapCount();
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
boolean containsOldFightPropMap(
int key);
@ -34,19 +34,19 @@ public final class AvatarUpgradeRspOuterClass {
java.util.Map<java.lang.Integer, java.lang.Float>
getOldFightPropMap();
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
java.util.Map<java.lang.Integer, java.lang.Float>
getOldFightPropMapMap();
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
float getOldFightPropMapOrDefault(
int key,
float defaultValue);
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
float getOldFightPropMapOrThrow(
@ -65,11 +65,11 @@ public final class AvatarUpgradeRspOuterClass {
int getCurLevel();
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
int getCurFightPropMapCount();
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
boolean containsCurFightPropMap(
int key);
@ -80,19 +80,19 @@ public final class AvatarUpgradeRspOuterClass {
java.util.Map<java.lang.Integer, java.lang.Float>
getCurFightPropMap();
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
java.util.Map<java.lang.Integer, java.lang.Float>
getCurFightPropMapMap();
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
float getCurFightPropMapOrDefault(
int key,
float defaultValue);
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
float getCurFightPropMapOrThrow(
@ -177,19 +177,6 @@ public final class AvatarUpgradeRspOuterClass {
break;
}
case 98: {
if (!((mutable_bitField0_ & 0x00000001) != 0)) {
oldFightPropMap_ = com.google.protobuf.MapField.newMapField(
OldFightPropMapDefaultEntryHolder.defaultEntry);
mutable_bitField0_ |= 0x00000001;
}
com.google.protobuf.MapEntry<java.lang.Integer, java.lang.Float>
oldFightPropMap__ = input.readMessage(
OldFightPropMapDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry);
oldFightPropMap_.getMutableMap().put(
oldFightPropMap__.getKey(), oldFightPropMap__.getValue());
break;
}
case 106: {
if (!((mutable_bitField0_ & 0x00000002) != 0)) {
curFightPropMap_ = com.google.protobuf.MapField.newMapField(
CurFightPropMapDefaultEntryHolder.defaultEntry);
@ -202,6 +189,19 @@ public final class AvatarUpgradeRspOuterClass {
curFightPropMap__.getKey(), curFightPropMap__.getValue());
break;
}
case 106: {
if (!((mutable_bitField0_ & 0x00000001) != 0)) {
oldFightPropMap_ = com.google.protobuf.MapField.newMapField(
OldFightPropMapDefaultEntryHolder.defaultEntry);
mutable_bitField0_ |= 0x00000001;
}
com.google.protobuf.MapEntry<java.lang.Integer, java.lang.Float>
oldFightPropMap__ = input.readMessage(
OldFightPropMapDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry);
oldFightPropMap_.getMutableMap().put(
oldFightPropMap__.getKey(), oldFightPropMap__.getValue());
break;
}
case 112: {
curLevel_ = input.readUInt32();
@ -236,9 +236,9 @@ public final class AvatarUpgradeRspOuterClass {
protected com.google.protobuf.MapField internalGetMapField(
int number) {
switch (number) {
case 12:
return internalGetOldFightPropMap();
case 13:
return internalGetOldFightPropMap();
case 12:
return internalGetCurFightPropMap();
default:
throw new RuntimeException(
@ -253,7 +253,7 @@ public final class AvatarUpgradeRspOuterClass {
emu.grasscutter.net.proto.AvatarUpgradeRspOuterClass.AvatarUpgradeRsp.class, emu.grasscutter.net.proto.AvatarUpgradeRspOuterClass.AvatarUpgradeRsp.Builder.class);
}
public static final int OLD_FIGHT_PROP_MAP_FIELD_NUMBER = 12;
public static final int OLD_FIGHT_PROP_MAP_FIELD_NUMBER = 13;
private static final class OldFightPropMapDefaultEntryHolder {
static final com.google.protobuf.MapEntry<
java.lang.Integer, java.lang.Float> defaultEntry =
@ -280,7 +280,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetOldFightPropMap().getMap().size();
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
@java.lang.Override
@ -298,7 +298,7 @@ public final class AvatarUpgradeRspOuterClass {
return getOldFightPropMapMap();
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
@java.lang.Override
@ -306,7 +306,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetOldFightPropMap().getMap();
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
@java.lang.Override
@ -319,7 +319,7 @@ public final class AvatarUpgradeRspOuterClass {
return map.containsKey(key) ? map.get(key) : defaultValue;
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
@java.lang.Override
@ -356,7 +356,7 @@ public final class AvatarUpgradeRspOuterClass {
return curLevel_;
}
public static final int CUR_FIGHT_PROP_MAP_FIELD_NUMBER = 13;
public static final int CUR_FIGHT_PROP_MAP_FIELD_NUMBER = 12;
private static final class CurFightPropMapDefaultEntryHolder {
static final com.google.protobuf.MapEntry<
java.lang.Integer, java.lang.Float> defaultEntry =
@ -383,7 +383,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetCurFightPropMap().getMap().size();
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
@java.lang.Override
@ -401,7 +401,7 @@ public final class AvatarUpgradeRspOuterClass {
return getCurFightPropMapMap();
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
@java.lang.Override
@ -409,7 +409,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetCurFightPropMap().getMap();
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
@java.lang.Override
@ -422,7 +422,7 @@ public final class AvatarUpgradeRspOuterClass {
return map.containsKey(key) ? map.get(key) : defaultValue;
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
@java.lang.Override
@ -485,14 +485,14 @@ public final class AvatarUpgradeRspOuterClass {
com.google.protobuf.GeneratedMessageV3
.serializeIntegerMapTo(
output,
internalGetOldFightPropMap(),
OldFightPropMapDefaultEntryHolder.defaultEntry,
internalGetCurFightPropMap(),
CurFightPropMapDefaultEntryHolder.defaultEntry,
12);
com.google.protobuf.GeneratedMessageV3
.serializeIntegerMapTo(
output,
internalGetCurFightPropMap(),
CurFightPropMapDefaultEntryHolder.defaultEntry,
internalGetOldFightPropMap(),
OldFightPropMapDefaultEntryHolder.defaultEntry,
13);
if (curLevel_ != 0) {
output.writeUInt32(14, curLevel_);
@ -518,16 +518,6 @@ public final class AvatarUpgradeRspOuterClass {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(10, retcode_);
}
for (java.util.Map.Entry<java.lang.Integer, java.lang.Float> entry
: internalGetOldFightPropMap().getMap().entrySet()) {
com.google.protobuf.MapEntry<java.lang.Integer, java.lang.Float>
oldFightPropMap__ = OldFightPropMapDefaultEntryHolder.defaultEntry.newBuilderForType()
.setKey(entry.getKey())
.setValue(entry.getValue())
.build();
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(12, oldFightPropMap__);
}
for (java.util.Map.Entry<java.lang.Integer, java.lang.Float> entry
: internalGetCurFightPropMap().getMap().entrySet()) {
com.google.protobuf.MapEntry<java.lang.Integer, java.lang.Float>
@ -536,7 +526,17 @@ public final class AvatarUpgradeRspOuterClass {
.setValue(entry.getValue())
.build();
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(13, curFightPropMap__);
.computeMessageSize(12, curFightPropMap__);
}
for (java.util.Map.Entry<java.lang.Integer, java.lang.Float> entry
: internalGetOldFightPropMap().getMap().entrySet()) {
com.google.protobuf.MapEntry<java.lang.Integer, java.lang.Float>
oldFightPropMap__ = OldFightPropMapDefaultEntryHolder.defaultEntry.newBuilderForType()
.setKey(entry.getKey())
.setValue(entry.getValue())
.build();
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(13, oldFightPropMap__);
}
if (curLevel_ != 0) {
size += com.google.protobuf.CodedOutputStream
@ -713,9 +713,9 @@ public final class AvatarUpgradeRspOuterClass {
protected com.google.protobuf.MapField internalGetMapField(
int number) {
switch (number) {
case 12:
return internalGetOldFightPropMap();
case 13:
return internalGetOldFightPropMap();
case 12:
return internalGetCurFightPropMap();
default:
throw new RuntimeException(
@ -726,9 +726,9 @@ public final class AvatarUpgradeRspOuterClass {
protected com.google.protobuf.MapField internalGetMutableMapField(
int number) {
switch (number) {
case 12:
return internalGetMutableOldFightPropMap();
case 13:
return internalGetMutableOldFightPropMap();
case 12:
return internalGetMutableCurFightPropMap();
default:
throw new RuntimeException(
@ -927,7 +927,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetOldFightPropMap().getMap().size();
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
@java.lang.Override
@ -945,7 +945,7 @@ public final class AvatarUpgradeRspOuterClass {
return getOldFightPropMapMap();
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
@java.lang.Override
@ -953,7 +953,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetOldFightPropMap().getMap();
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
@java.lang.Override
@ -966,7 +966,7 @@ public final class AvatarUpgradeRspOuterClass {
return map.containsKey(key) ? map.get(key) : defaultValue;
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
@java.lang.Override
@ -987,7 +987,7 @@ public final class AvatarUpgradeRspOuterClass {
return this;
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
public Builder removeOldFightPropMap(
@ -1006,7 +1006,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetMutableOldFightPropMap().getMutableMap();
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
public Builder putOldFightPropMap(
int key,
@ -1018,7 +1018,7 @@ public final class AvatarUpgradeRspOuterClass {
return this;
}
/**
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 12;</code>
* <code>map&lt;uint32, float&gt; old_fight_prop_map = 13;</code>
*/
public Builder putAllOldFightPropMap(
@ -1117,7 +1117,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetCurFightPropMap().getMap().size();
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
@java.lang.Override
@ -1135,7 +1135,7 @@ public final class AvatarUpgradeRspOuterClass {
return getCurFightPropMapMap();
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
@java.lang.Override
@ -1143,7 +1143,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetCurFightPropMap().getMap();
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
@java.lang.Override
@ -1156,7 +1156,7 @@ public final class AvatarUpgradeRspOuterClass {
return map.containsKey(key) ? map.get(key) : defaultValue;
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
@java.lang.Override
@ -1177,7 +1177,7 @@ public final class AvatarUpgradeRspOuterClass {
return this;
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
public Builder removeCurFightPropMap(
@ -1196,7 +1196,7 @@ public final class AvatarUpgradeRspOuterClass {
return internalGetMutableCurFightPropMap().getMutableMap();
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
public Builder putCurFightPropMap(
int key,
@ -1208,7 +1208,7 @@ public final class AvatarUpgradeRspOuterClass {
return this;
}
/**
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 13;</code>
* <code>map&lt;uint32, float&gt; cur_fight_prop_map = 12;</code>
*/
public Builder putAllCurFightPropMap(
@ -1357,10 +1357,10 @@ public final class AvatarUpgradeRspOuterClass {
static {
java.lang.String[] descriptorData = {
"\n\026AvatarUpgradeRsp.proto\"\326\002\n\020AvatarUpgra" +
"deRsp\022B\n\022old_fight_prop_map\030\014 \003(\0132&.Avat" +
"deRsp\022B\n\022old_fight_prop_map\030\r \003(\0132&.Avat" +
"arUpgradeRsp.OldFightPropMapEntry\022\023\n\013ava" +
"tar_guid\030\010 \001(\004\022\021\n\tcur_level\030\016 \001(\r\022B\n\022cur" +
"_fight_prop_map\030\r \003(\0132&.AvatarUpgradeRsp" +
"_fight_prop_map\030\014 \003(\0132&.AvatarUpgradeRsp" +
".CurFightPropMapEntry\022\017\n\007retcode\030\n \001(\005\022\021" +
"\n\told_level\030\004 \001(\r\0326\n\024OldFightPropMapEntr" +
"y\022\013\n\003key\030\001 \001(\r\022\r\n\005value\030\002 \001(\002:\0028\001\0326\n\024Cur" +

View File

@ -224,6 +224,123 @@ public final class ChatInfoOuterClass {
emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.class, emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.Builder.class);
}
/**
* Protobuf enum {@code ChatInfo.SystemHintType}
*/
public enum SystemHintType
implements com.google.protobuf.ProtocolMessageEnum {
/**
* <code>SYSTEM_HINT_TYPE_CHAT_NONE = 0;</code>
*/
SYSTEM_HINT_TYPE_CHAT_NONE(0),
/**
* <code>SYSTEM_HINT_TYPE_CHAT_ENTER_WORLD = 1;</code>
*/
SYSTEM_HINT_TYPE_CHAT_ENTER_WORLD(1),
/**
* <code>SYSTEM_HINT_TYPE_CHAT_LEAVE_WORLD = 2;</code>
*/
SYSTEM_HINT_TYPE_CHAT_LEAVE_WORLD(2),
UNRECOGNIZED(-1),
;
/**
* <code>SYSTEM_HINT_TYPE_CHAT_NONE = 0;</code>
*/
public static final int SYSTEM_HINT_TYPE_CHAT_NONE_VALUE = 0;
/**
* <code>SYSTEM_HINT_TYPE_CHAT_ENTER_WORLD = 1;</code>
*/
public static final int SYSTEM_HINT_TYPE_CHAT_ENTER_WORLD_VALUE = 1;
/**
* <code>SYSTEM_HINT_TYPE_CHAT_LEAVE_WORLD = 2;</code>
*/
public static final int SYSTEM_HINT_TYPE_CHAT_LEAVE_WORLD_VALUE = 2;
public final int getNumber() {
if (this == UNRECOGNIZED) {
throw new java.lang.IllegalArgumentException(
"Can't get the number of an unknown enum value.");
}
return value;
}
/**
* @param value The numeric wire value of the corresponding enum entry.
* @return The enum associated with the given numeric wire value.
* @deprecated Use {@link #forNumber(int)} instead.
*/
@java.lang.Deprecated
public static SystemHintType valueOf(int value) {
return forNumber(value);
}
/**
* @param value The numeric wire value of the corresponding enum entry.
* @return The enum associated with the given numeric wire value.
*/
public static SystemHintType forNumber(int value) {
switch (value) {
case 0: return SYSTEM_HINT_TYPE_CHAT_NONE;
case 1: return SYSTEM_HINT_TYPE_CHAT_ENTER_WORLD;
case 2: return SYSTEM_HINT_TYPE_CHAT_LEAVE_WORLD;
default: return null;
}
}
public static com.google.protobuf.Internal.EnumLiteMap<SystemHintType>
internalGetValueMap() {
return internalValueMap;
}
private static final com.google.protobuf.Internal.EnumLiteMap<
SystemHintType> internalValueMap =
new com.google.protobuf.Internal.EnumLiteMap<SystemHintType>() {
public SystemHintType findValueByNumber(int number) {
return SystemHintType.forNumber(number);
}
};
public final com.google.protobuf.Descriptors.EnumValueDescriptor
getValueDescriptor() {
if (this == UNRECOGNIZED) {
throw new java.lang.IllegalStateException(
"Can't get the descriptor of an unrecognized enum value.");
}
return getDescriptor().getValues().get(ordinal());
}
public final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptorForType() {
return getDescriptor();
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
return emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.getDescriptor().getEnumTypes().get(0);
}
private static final SystemHintType[] VALUES = values();
public static SystemHintType valueOf(
com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
if (desc.getType() != getDescriptor()) {
throw new java.lang.IllegalArgumentException(
"EnumValueDescriptor is not for this type.");
}
if (desc.getIndex() == -1) {
return UNRECOGNIZED;
}
return VALUES[desc.getIndex()];
}
private final int value;
private SystemHintType(int value) {
this.value = value;
}
// @@protoc_insertion_point(enum_scope:ChatInfo.SystemHintType)
}
public interface SystemHintOrBuilder extends
// @@protoc_insertion_point(interface_extends:ChatInfo.SystemHint)
com.google.protobuf.MessageOrBuilder {
@ -1907,13 +2024,16 @@ public final class ChatInfoOuterClass {
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\016ChatInfo.proto\"\317\001\n\010ChatInfo\022\014\n\004time\030\007 " +
"\n\016ChatInfo.proto\"\317\002\n\010ChatInfo\022\014\n\004time\030\007 " +
"\001(\r\022\016\n\006to_uid\030\006 \001(\r\022\017\n\007is_read\030\004 \001(\010\022\013\n\003" +
"uid\030\005 \001(\r\022\020\n\010sequence\030\014 \001(\r\022\017\n\004text\030\230\003 \001" +
"(\tH\000\022\017\n\004icon\030\234\n \001(\rH\000\022,\n\013system_hint\030\246\001 " +
"\001(\0132\024.ChatInfo.SystemHintH\000\032\032\n\nSystemHin" +
"t\022\014\n\004type\030\r \001(\rB\t\n\007contentB\033\n\031emu.grassc" +
"utter.net.protob\006proto3"
"t\022\014\n\004type\030\r \001(\r\"~\n\016SystemHintType\022\036\n\032SYS" +
"TEM_HINT_TYPE_CHAT_NONE\020\000\022%\n!SYSTEM_HINT" +
"_TYPE_CHAT_ENTER_WORLD\020\001\022%\n!SYSTEM_HINT_" +
"TYPE_CHAT_LEAVE_WORLD\020\002B\t\n\007contentB\033\n\031em" +
"u.grasscutter.net.protob\006proto3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,

View File

@ -8,7 +8,7 @@ import emu.grasscutter.auth.*;
import emu.grasscutter.command.*;
import emu.grasscutter.config.ConfigContainer;
import emu.grasscutter.data.ResourceLoader;
import emu.grasscutter.database.DatabaseManager;
import emu.grasscutter.database.*;
import emu.grasscutter.plugin.PluginManager;
import emu.grasscutter.plugin.api.ServerHelper;
import emu.grasscutter.server.dispatch.DispatchServer;
@ -183,6 +183,25 @@ public final class Grasscutter {
private static void onShutdown() {
// Disable all plugins.
if (pluginManager != null) pluginManager.disablePlugins();
// Shutdown the game server.
if (gameServer != null) gameServer.onServerShutdown();
try {
// Wait for Grasscutter's thread pool to finish.
var executor = Grasscutter.getThreadPool();
executor.shutdown();
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
// Wait for database operations to finish.
var dbExecutor = DatabaseHelper.getEventExecutor();
dbExecutor.shutdown();
if (!dbExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
dbExecutor.shutdownNow();
}
} catch (InterruptedException ignored) {
}
}
/*

View File

@ -5,8 +5,7 @@ import static emu.grasscutter.config.Configuration.SERVER;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.*;
import java.util.*;
import org.reflections.Reflections;

View File

@ -11,8 +11,8 @@ import lombok.val;
label = "cutscene",
aliases = {"c"},
usage = {"[<cutsceneId>]"},
permission = "player.group",
permissionTargeted = "player.group.others")
permission = "player.cutscene",
permissionTargeted = "player.cutscene.others")
public final class CutsceneCommand implements CommandHandler {
@Override

View File

@ -12,7 +12,7 @@ import java.util.Map;
@Command(
label = "list",
aliases = {"players"},
usage = {"[<UID>]"},
usage = {"[uid]"},
targetRequirement = Command.TargetRequirement.NONE)
public final class ListCommand implements CommandHandler {

View File

@ -2,23 +2,23 @@ package emu.grasscutter.command.commands;
import static emu.grasscutter.utils.lang.Language.translate;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.*;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.GameQuest;
import java.util.List;
import java.util.stream.Collectors;
@Command(
label = "quest",
aliases = {"q"},
usage = {"(add|finish) [<questId>]"},
usage = {"(add|finish|running|talking|debug|triggers|grouptriggers) [<questId>]", "dungeons"},
permission = "player.quest",
permissionTargeted = "player.quest.others")
public final class QuestCommand implements CommandHandler {
@Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
if (args.size() != 2) {
if (args.size() != 2 || (args.size() == 1 && !args.get(0).toLowerCase().equals("dungeons"))) {
sendUsageMessage(sender);
return;
}
@ -112,7 +112,7 @@ public final class QuestCommand implements CommandHandler {
var shouldAdd = !loggedQuests.contains(questId);
if (shouldAdd) loggedQuests.add(questId);
else loggedQuests.remove(questId);
else loggedQuests.remove(loggedQuests.indexOf(questId));
CommandHandler.sendMessage(
sender,
@ -131,6 +131,22 @@ public final class QuestCommand implements CommandHandler {
"Triggers registered for %s: %s."
.formatted(questId, String.join(", ", quest.getTriggers().keySet())));
}
case "grouptriggers" -> {
var scene = targetPlayer.getScene();
var scriptManager = scene.getScriptManager();
var group = scriptManager.getGroupById(questId);
if (group == null) {
CommandHandler.sendMessage(sender, "The group does not exist.");
return;
}
CommandHandler.sendMessage(
sender,
group.triggers.entrySet().stream()
.map(entry -> "%s: %s".formatted(entry.getKey(), entry.getValue()))
.collect(Collectors.joining(", ")));
}
default -> this.sendUsageMessage(sender);
}
}

View File

@ -12,6 +12,7 @@ import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.IntStream;
@Command(
@ -107,6 +108,7 @@ public final class SetPropCommand implements CommandHandler {
case "on", "true" -> 1;
case "off", "false" -> 0;
case "toggle" -> -1;
case "all" -> -2;
default -> Integer.parseInt(valueStr);
};
} catch (NumberFormatException ignored) {
@ -126,7 +128,7 @@ public final class SetPropCommand implements CommandHandler {
sender, targetPlayer, prop.pseudoProp, value);
case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0);
case UNLOCK_MAP -> unlockMap(targetPlayer);
case UNLOCK_MAP -> unlockMap(targetPlayer, value);
default -> targetPlayer.setProperty(prop.prop, value);
};
@ -217,13 +219,30 @@ public final class SetPropCommand implements CommandHandler {
return true;
}
private boolean unlockMap(Player targetPlayer) {
private boolean unlockMap(Player targetPlayer, int value) {
// Unlock.
GameData.getScenePointsPerScene()
.forEach(
(sceneId, scenePoints) -> {
if (value == -2) {
// Unlock trans points.
targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints);
} else {
var scenePointsBackup = new CopyOnWriteArrayList<>(scenePoints);
for (var p : scenePointsBackup) {
var scenePointEentry = GameData.getScenePointEntryById(sceneId, p);
var pointData = scenePointEentry.getPointData();
boolean forbidSimpleUnlock = pointData.isForbidSimpleUnlock();
boolean sceneBuildingPointLocked =
pointData.getType().equals("SceneBuildingPoint") && !pointData.isUnlocked();
if (forbidSimpleUnlock || sceneBuildingPointLocked) scenePointsBackup.remove(p);
}
// Unlock trans points.
targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePointsBackup);
}
// Unlock map areas.
targetPlayer.getUnlockedSceneAreas(sceneId).addAll(sceneAreas);

View File

@ -14,8 +14,8 @@ import lombok.val;
label = "sound",
aliases = {"s", "audio"},
usage = {"[<audioname>] [<x><y><z>]"},
permission = "player.group",
permissionTargeted = "player.group.others")
permission = "player.sound",
permissionTargeted = "player.sound.others")
public final class SoundCommand implements CommandHandler {
@Override

View File

@ -27,9 +27,11 @@ public class ConfigContainer {
* Version 8 - 'server' is being added for enforcing handbook server
* addresses.
* Version 9 - 'limits' was added for handbook requests.
* Version 10 - 'trialCostumes' was added for enabling costumes
* on trial avatars.
*/
private static int version() {
return 9;
return 10;
}
/**
@ -255,6 +257,8 @@ public class ConfigContainer {
public boolean staminaUsage = true;
public boolean energyUsage = true;
public boolean fishhookTeleport = true;
public boolean trialCostumes = false;
@SerializedName(value = "questing", alternate = "questOptions")
public Questing questing = new Questing();
public ResinOptions resinOptions = new ResinOptions();

View File

@ -37,8 +37,11 @@ import emu.grasscutter.data.excels.world.WeatherData;
import emu.grasscutter.data.excels.world.WorldAreaData;
import emu.grasscutter.data.excels.world.WorldLevelData;
import emu.grasscutter.data.server.ActivityCondGroup;
import emu.grasscutter.data.server.DropSubfieldMapping;
import emu.grasscutter.data.server.DropTableExcelConfigData;
import emu.grasscutter.data.server.GadgetMapping;
import emu.grasscutter.data.server.MonsterMapping;
import emu.grasscutter.data.server.SubfieldMapping;
import emu.grasscutter.game.dungeons.DungeonDropEntry;
import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.game.quest.RewindData;
@ -451,6 +454,18 @@ public final class GameData {
private static final Int2ObjectMap<GadgetMapping> gadgetMappingMap =
new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<SubfieldMapping> subfieldMappingMap =
new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<DropSubfieldMapping> dropSubfieldMappingMap =
new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<DropTableExcelConfigData> dropTableExcelConfigDataMap =
new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<MonsterMapping> monsterMappingMap =
new Int2ObjectOpenHashMap<>();

View File

@ -116,6 +116,7 @@ public final class ResourceLoader {
loadConfigLevelEntityData();
loadQuestShareConfig();
loadGadgetMappings();
loadSubfieldMappings();
loadMonsterMappings();
loadActivityCondGroups();
loadGroupReplacements();
@ -805,6 +806,51 @@ public final class ResourceLoader {
}
}
private static void loadSubfieldMappings() {
try {
val subfieldMap = GameData.getSubfieldMappingMap();
try {
JsonUtils.loadToList(getResourcePath("Server/SubfieldMapping.json"), SubfieldMapping.class)
.forEach(entry -> subfieldMap.put(entry.getEntityId(), entry));
;
} catch (IOException | NullPointerException ignored) {
}
Grasscutter.getLogger().debug("Loaded {} subfield mappings.", subfieldMap.size());
} catch (Exception e) {
Grasscutter.getLogger().error("Unable to load subfield mappings.", e);
}
try {
val dropSubfieldMap = GameData.getDropSubfieldMappingMap();
try {
JsonUtils.loadToList(
getResourcePath("Server/DropSubfieldMapping.json"), DropSubfieldMapping.class)
.forEach(entry -> dropSubfieldMap.put(entry.getDropId(), entry));
;
} catch (IOException | NullPointerException ignored) {
}
Grasscutter.getLogger().debug("Loaded {} drop subfield mappings.", dropSubfieldMap.size());
} catch (Exception e) {
Grasscutter.getLogger().error("Unable to load drop subfield mappings.", e);
}
try {
val dropTableExcelConfigDataMap = GameData.getDropTableExcelConfigDataMap();
try {
JsonUtils.loadToList(
getResourcePath("Server/DropTableExcelConfigData.json"),
DropTableExcelConfigData.class)
.forEach(entry -> dropTableExcelConfigDataMap.put(entry.getId(), entry));
;
} catch (IOException | NullPointerException ignored) {
}
Grasscutter.getLogger()
.debug("Loaded {} drop table configs.", dropTableExcelConfigDataMap.size());
} catch (Exception e) {
Grasscutter.getLogger().error("Unable to load drop table config data.", e);
}
}
private static void loadMonsterMappings() {
try {
var monsterMap = GameData.getMonsterMappingMap();

View File

@ -87,7 +87,10 @@ public class AbilityData {
}
private void initializeModifiers() {
if (modifiers == null) return;
if (modifiers == null) {
this.modifiers = new HashMap<>();
return;
}
var _modifiers =
modifiers.entrySet().stream()

View File

@ -323,9 +323,28 @@ public class AbilityModifier implements Serializable {
public int skillID;
public AbilityModifierAction[] actions;
public AbilityModifierAction[] successActions;
public AbilityModifierAction[] failActions;
public DropType dropType = DropType.LevelControl;
public DynamicFloat baseEnergy;
public DynamicFloat ratio = DynamicFloat.ONE;
public int configID;
public DynamicFloat valueRangeMin;
public DynamicFloat valueRangeMax;
public String overrideMapKey;
public int param1;
public int param2;
public int param3;
public enum DropType {
LevelControl,
BigWorldOnly,
ForceDrop
}
}
// The following should be implemented into DynamicFloat if older resource formats need to be

View File

@ -11,4 +11,6 @@ public class ConfigLevelEntity {
@Getter private List<ConfigAbilityData> avatarAbilities;
@Getter private List<ConfigAbilityData> teamAbilities;
@Getter private List<Integer> preloadMonsterEntityIDs;
@Getter private String dropElemControlType;
}

View File

@ -19,6 +19,8 @@ public final class PointData {
@Getter private Position pos;
@Getter private Position rot;
@Getter private Position size;
@Getter private boolean forbidSimpleUnlock;
@Getter private boolean unlocked;
@SerializedName(
value = "dungeonIds",

View File

@ -1,12 +1,10 @@
package emu.grasscutter.data.excels;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.*;
import emu.grasscutter.game.talk.TalkExec;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.*;
@ResourceType(name = "TalkExcelConfigData.json")
@EqualsAndHashCode(callSuper = false)
@ -38,6 +36,11 @@ public final class TalkConfigData extends GameResource {
this.finishExec == null
? List.of()
: this.finishExec.stream().filter(x -> x.getType() != null).toList();
if (this.questId <= 0) {
var id = String.valueOf(this.getId());
this.questId = Integer.parseInt(id.length() < 5 ? "0" : id.substring(0, 3));
}
}
@Data

View File

@ -32,6 +32,7 @@ public class DungeonData extends GameResource {
@Getter private int passRewardPreviewID;
@Getter private int statueCostID;
@Getter private int statueCostCount;
@Getter private int statueDrop;
// not part of DungeonExcelConfigData
@Getter private RewardPreviewData rewardPreviewData;

View File

@ -0,0 +1,10 @@
package emu.grasscutter.data.server;
import lombok.Data;
@Data
public final class DropSubfieldMapping {
private int dropId;
private int levelLimit;
private int itemId;
}

View File

@ -0,0 +1,24 @@
package emu.grasscutter.data.server;
import lombok.Data;
@Data
public final class DropTableExcelConfigData {
private int id;
private int randomType;
private int dropLevel;
private DropVectorEntry[] dropVec;
private int nodeType;
private boolean fallToGround;
private int sourceType;
private int everydayLimit;
private int historyLimit;
private int activityLimit;
@Data
public static class DropVectorEntry {
private int itemId;
private String countRange;
private int weight;
}
}

View File

@ -0,0 +1,15 @@
package emu.grasscutter.data.server;
import lombok.Data;
@Data
public final class SubfieldMapping {
private int entityId;
private SubfieldMappingEntry[] subfields;
@Data
public static class SubfieldMappingEntry {
private String subfieldName;
private int drop_id;
}
}

View File

@ -2,11 +2,9 @@ package emu.grasscutter.database;
import static com.mongodb.client.model.Filters.eq;
import dev.morphia.query.FindOptions;
import dev.morphia.query.Sort;
import dev.morphia.query.*;
import dev.morphia.query.experimental.filters.Filters;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.*;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.achievement.Achievements;
import emu.grasscutter.game.activity.PlayerActivityData;
@ -26,8 +24,10 @@ import io.netty.util.concurrent.FastThreadLocalThread;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Stream;
import lombok.Getter;
public final class DatabaseHelper {
@Getter
private static final ExecutorService eventExecutor =
new ThreadPoolExecutor(
6,

View File

@ -30,30 +30,50 @@ public class AbilityLocalIdGenerator {
}
public void initializeActionLocalIds(
AbilityModifierAction[] actions, Map<Integer, AbilityModifierAction> localIdToAction) {
if (actions == null) return;
actionIndex = 0;
for (AbilityModifierAction action : actions) {
actionIndex++;
long id = GetLocalId();
localIdToAction.put((int) id, action);
AbilityModifierAction actions[], Map<Integer, AbilityModifierAction> localIdToAction) {
this.initializeActionLocalIds(actions, localIdToAction, false);
}
actionIndex = 0;
public void initializeActionLocalIds(
AbilityModifierAction[] actions,
Map<Integer, AbilityModifierAction> localIdToAction,
boolean preserveActionIndex) {
if (actions == null) return;
if (!preserveActionIndex) this.actionIndex = 0;
for (int i = 0; i < actions.length; i++) {
this.actionIndex++;
var id = GetLocalId();
localIdToAction.put((int) id, actions[i]);
if (actions[i].actions != null)
this.initializeActionLocalIds(actions[i].actions, localIdToAction, true);
else {
if (actions[i].successActions != null)
this.initializeActionLocalIds(
actions[i].successActions,
localIdToAction,
true); // Need to check this specific order
if (actions[i].failActions != null)
this.initializeActionLocalIds(actions[i].failActions, localIdToAction, true);
}
}
if (!preserveActionIndex) actionIndex = 0;
}
public void initializeMixinsLocalIds(
AbilityMixinData[] mixins, Map<Integer, AbilityMixinData> localIdToAction) {
if (mixins == null) return;
mixinIndex = 0;
for (AbilityMixinData mixin : mixins) {
long id = GetLocalId();
this.mixinIndex = 0;
for (var mixin : mixins) {
var id = GetLocalId();
localIdToAction.put((int) id, mixin);
mixinIndex++;
this.mixinIndex++;
}
mixinIndex = 0;
this.mixinIndex = 0;
}
public long GetLocalId() {

View File

@ -9,10 +9,12 @@ import emu.grasscutter.game.ability.actions.*;
import emu.grasscutter.game.ability.mixins.*;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.*;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
import emu.grasscutter.net.proto.AbilityMetaAddAbilityOuterClass.AbilityMetaAddAbility;
import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange;
import emu.grasscutter.net.proto.AbilityMetaReInitOverrideMapOuterClass.AbilityMetaReInitOverrideMap;
import emu.grasscutter.net.proto.AbilityMetaSetKilledStateOuterClass.AbilityMetaSetKilledState;
import emu.grasscutter.net.proto.AbilityScalarTypeOuterClass.AbilityScalarType;
import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry;
import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction;
@ -174,6 +176,7 @@ public final class AbilityManager extends BasePlayerManager {
case ABILITY_INVOKE_ARGUMENT_META_MODIFIER_DURABILITY_CHANGE -> this
.handleModifierDurabilityChange(invoke);
case ABILITY_INVOKE_ARGUMENT_META_ADD_NEW_ABILITY -> this.handleAddNewAbility(invoke);
case ABILITY_INVOKE_ARGUMENT_META_SET_KILLED_SETATE -> this.handleKillState(invoke);
default -> {}
}
}
@ -535,6 +538,25 @@ public final class AbilityManager extends BasePlayerManager {
entity.getInstancedAbilities().size());
}
private void handleKillState(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
var scene = this.getPlayer().getScene();
var entity = scene.getEntityById(invoke.getEntityId());
if (entity == null) {
Grasscutter.getLogger()
.trace("Entity of ID {} was not found in the scene.", invoke.getEntityId());
return;
}
var killState = AbilityMetaSetKilledState.parseFrom(invoke.getAbilityData());
if (killState.getKilled()) {
scene.killEntity(entity);
} else if (!entity.isAlive()) {
entity.setFightProperty(
FightProperty.FIGHT_PROP_CUR_HP,
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP));
}
}
public void addAbilityToEntity(GameEntity entity, String name) {
AbilityData data = GameData.getAbilityData(name);
if (data != null) addAbilityToEntity(entity, data);

View File

@ -3,7 +3,7 @@ package emu.grasscutter.game.ability.actions;
import com.google.protobuf.ByteString;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.game.ability.Ability;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.entity.*;
@AbilityAction(AbilityModifierAction.Type.ExecuteGadgetLua)
public class ActionExecuteGadgetLua extends AbilityActionHandler {

View File

@ -0,0 +1,100 @@
package emu.grasscutter.game.ability.actions;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction.DropType;
import emu.grasscutter.data.binout.config.ConfigLevelEntity;
import emu.grasscutter.game.ability.Ability;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.world.Position;
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
@AbilityAction(AbilityModifierAction.Type.GenerateElemBall)
public final class ActionGenerateElemBall extends AbilityActionHandler {
@Override
public boolean execute(
Ability ability, AbilityModifierAction action, ByteString abilityData, GameEntity target) {
GameEntity owner = ability.getOwner();
AbilityActionGenerateElemBall generateElemBall;
try {
generateElemBall = AbilityActionGenerateElemBall.parseFrom(abilityData);
} catch (InvalidProtocolBufferException e) {
return false;
}
// Check if we should allow elem ball generation
if (action.dropType == DropType.LevelControl) {
String levelEntityConfig = owner.getScene().getSceneData().getLevelEntityConfig();
ConfigLevelEntity config = GameData.getConfigLevelEntityDataMap().get(levelEntityConfig);
if (config != null
&& config.getDropElemControlType() != null
&& config.getDropElemControlType().compareTo("None") == 0) {
Grasscutter.getLogger().warn("This level config don't allow element balls");
return true;
}
} else if (action.dropType == DropType.BigWorldOnly) {
if (owner.getScene().getSceneData().getSceneType() != SceneType.SCENE_WORLD) {
Grasscutter.getLogger().warn("This level config only allows element balls on big world");
return true;
}
} // Else the drop is forced
var energy = action.baseEnergy.get(ability) * action.ratio.get(ability);
if (energy <= 0.0) return true;
var itemData = GameData.getItemDataMap().get(action.configID);
if (itemData == null) {
Grasscutter.getLogger().warn("configID {} not found", action.configID);
return false;
}
if (itemData.getItemUse() == null || itemData.getItemUse().isEmpty()) {
Grasscutter.getLogger().warn("Item {} has no item use array", action.configID);
return true;
}
var itemUse = itemData.getItemUse().get(0);
double requiredEnergy;
switch (itemUse.getUseOp()) {
case ITEM_USE_ADD_ELEM_ENERGY:
requiredEnergy = Integer.parseInt(itemUse.getUseParam()[1]);
break;
case ITEM_USE_ADD_ALL_ENERGY:
requiredEnergy = Integer.parseInt(itemUse.getUseParam()[0]);
break;
default:
Grasscutter.getLogger().warn("UseOp not implemented", itemUse.getUseOp());
return false;
}
var amountGenerated = (int) Math.ceil(energy / requiredEnergy);
if (amountGenerated >= 21) {
Grasscutter.getLogger()
.warn("Attempt to generate more than 20 element balls {}", amountGenerated);
return false;
}
Grasscutter.getLogger()
.debug("Generating {} of {} element balls", amountGenerated, action.configID);
for (int i = 0; i < amountGenerated; i++) {
EntityItem energyBall =
new EntityItem(
owner.getScene(),
(owner instanceof EntityAvatar avatar) ? avatar.getPlayer() : null,
itemData,
new Position(generateElemBall.getPos()),
new Position(generateElemBall.getRot()),
1);
owner.getScene().addEntity(energyBall);
}
return true;
}
}

View File

@ -1,6 +1,7 @@
package emu.grasscutter.game.ability.actions;
import com.google.protobuf.ByteString;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.game.ability.Ability;
import emu.grasscutter.game.entity.GameEntity;
@ -10,9 +11,14 @@ public final class ActionKillSelf extends AbilityActionHandler {
@Override
public boolean execute(
Ability ability, AbilityModifierAction action, ByteString abilityData, GameEntity target) {
GameEntity owner = ability.getOwner();
owner.getScene().killEntity(owner);
// KillSelf should not have a target field, so target it's the actual entity to be applied.
// TODO: Check if this is always true.
if (target == null) {
Grasscutter.getLogger().warn("Tried killing null target");
return false;
}
target.getScene().killEntity(target);
return true;
}
}

View File

@ -1,11 +1,10 @@
package emu.grasscutter.game.ability.actions;
import com.google.protobuf.ByteString;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.game.ability.Ability;
import emu.grasscutter.game.entity.EntityClientGadget;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.entity.*;
@AbilityAction(AbilityModifierAction.Type.SetGlobalValueToOverrideMap)
public class ActionSetGlobalValueToOverrideMap extends AbilityActionHandler {
@ -23,15 +22,20 @@ public class ActionSetGlobalValueToOverrideMap extends AbilityActionHandler {
var globalValueKey = action.globalValueKey;
var abilityFormula = action.abilityFormula;
if (!entity.getGlobalAbilityValues().containsKey(globalValueKey)) return false;
if (!entity.getGlobalAbilityValues().containsKey(globalValueKey)) {
Grasscutter.getLogger().debug("Action does not contains {} global key", globalValueKey);
return true;
}
var globalValue = entity.getGlobalAbilityValues().getOrDefault(globalValueKey, 0.0f);
if (abilityFormula.compareTo("DummyThrowSpeed") == 0) {
globalValue = ((globalValue * 30.0f) / ((float) Math.sin(0.9424778) * 100.0f)) - 1.0f;
}
entity.getGlobalAbilityValues().put(globalValueKey, globalValue);
entity.onAbilityValueUpdate();
entity.getGlobalAbilityValues().put(globalValueKey, globalValue); // Research if this is needed.
ability
.getAbilitySpecials()
.put(action.overrideMapKey, globalValue.floatValue()); // Override our own.
// TODO: ChangeServerGlobalValueNotify

View File

@ -0,0 +1,41 @@
package emu.grasscutter.game.ability.actions;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.game.ability.Ability;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.net.proto.AbilityActionSetRandomOverrideMapValueOuterClass.AbilityActionSetRandomOverrideMapValue;
@AbilityAction(AbilityModifierAction.Type.SetRandomOverrideMapValue)
public class ActionSetRandomOverrideMapValue extends AbilityActionHandler {
@Override
public boolean execute(
Ability ability, AbilityModifierAction action, ByteString abilityData, GameEntity target) {
AbilityActionSetRandomOverrideMapValue valueProto;
try {
valueProto = AbilityActionSetRandomOverrideMapValue.parseFrom(abilityData);
} catch (InvalidProtocolBufferException e) {
return false;
}
float value = valueProto.getRandomValue();
float valueRangeMin = action.valueRangeMin.get(ability);
float valueRangeMax = action.valueRangeMax.get(ability);
if (value < valueRangeMin || value > valueRangeMax) {
Grasscutter.getLogger()
.warn(
"Tried setting value out of range: {} inside [{}, {}]",
value,
valueRangeMin,
valueRangeMax);
return true;
}
ability.getAbilitySpecials().put(action.overrideMapKey, value);
return true;
}
}

View File

@ -1243,6 +1243,7 @@ public class Avatar {
});
// Add costume if avatar has a costume.
if (GAME_OPTIONS.trialCostumes) {
GameData.getAvatarCostumeDataItemIdMap()
.values()
.forEach(
@ -1251,6 +1252,7 @@ public class Avatar {
this.setCostume(costumeData.getId());
});
}
}
/** Equips the items applied from {@link Avatar#applyTrialItems()}. */
public void equipTrialItems() {

View File

@ -80,6 +80,14 @@ public final class DropSystem extends BaseGameSystem {
return dropData.getDropId();
}
public List<GameItem> handleDungeonRewardDrop(int dropId, boolean doubleReward) {
if (!dropTable.containsKey(dropId)) return List.of();
var dropData = dropTable.get(dropId);
List<GameItem> items = new ArrayList<>();
processDrop(dropData, doubleReward ? 2 : 1, items);
return items;
}
public boolean handleMonsterDrop(EntityMonster monster) {
int dropId;
int level = monster.getLevel();

View File

@ -134,7 +134,16 @@ public final class DungeonManager {
}
// Get and roll rewards.
List<GameItem> rewards = new ArrayList<>(this.rollRewards(useCondensed));
List<GameItem> rewards =
player
.getServer()
.getDropSystem()
.handleDungeonRewardDrop(dungeonData.getStatueDrop(), useCondensed);
if (rewards.isEmpty()) {
// fallback to legacy drop system
Grasscutter.getLogger().debug("dungeon drop failed for {}", dungeonData.getId());
rewards = new ArrayList<>(this.rollRewards(useCondensed));
}
// Add rewards to player and send notification.
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
@ -187,7 +196,7 @@ public final class DungeonManager {
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
}
// Double rewards in multiplay mode, if specified.
// Double rewards in multiply mode, if specified.
if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
amount *= 2;
}

View File

@ -8,11 +8,9 @@ import emu.grasscutter.data.excels.GadgetData;
import emu.grasscutter.game.entity.gadget.*;
import emu.grasscutter.game.entity.gadget.platform.BaseRoute;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.world.Position;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.SceneGroupInstance;
import emu.grasscutter.game.props.*;
import emu.grasscutter.game.world.*;
import emu.grasscutter.net.proto.*;
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
@ -20,31 +18,21 @@ import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import emu.grasscutter.net.proto.PlatformInfoOuterClass;
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
import emu.grasscutter.net.proto.VisionTypeOuterClass;
import emu.grasscutter.scripts.EntityControllerScriptManager;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneGadget;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
import emu.grasscutter.server.packet.send.PacketPlatformStartRouteNotify;
import emu.grasscutter.server.packet.send.PacketPlatformStopRouteNotify;
import emu.grasscutter.server.packet.send.PacketSceneTimeNotify;
import emu.grasscutter.scripts.data.*;
import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.helpers.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import java.util.ArrayList;
import java.util.List;
import it.unimi.dsi.fastutil.ints.*;
import java.util.*;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.*;
@ToString(callSuper = true)
public class EntityGadget extends EntityBaseGadget {

View File

@ -37,14 +37,30 @@ public class EntityItem extends EntityBaseGadget {
this(scene, player, itemData, pos, count, true);
}
public EntityItem(
Scene scene, Player player, ItemData itemData, Position pos, Position rotation, int count) {
this(scene, player, itemData, pos, rotation, count, true);
}
public EntityItem(
Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) {
this(scene, player, itemData, pos, null, count, share);
}
// In official game, some drop items are shared to all players, and some other items are
// independent to all players
// For example, if you killed a monster in MP mode, all players could get drops but rarity and
// number of them are different
// but if you broke regional mine, when someone picked up the drop then it disappeared
public EntityItem(
Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) {
super(scene, pos, null);
Scene scene,
Player player,
ItemData itemData,
Position pos,
Position rotation,
int count,
boolean share) {
super(scene, pos, rotation);
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
this.guid =
player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid();

View File

@ -113,7 +113,13 @@ public class EntityMonster extends GameEntity {
if(monster != null) affixes = monster.affix;
}
if (affixes != null) {
if (monsterData != null) {
// TODO: Research if group affixes goes first
if (affixes == null) affixes = monsterData.getAffix();
else affixes.addAll(monsterData.getAffix());
}
if(affixes != null) {
for(var affixId : affixes) {
var affix = GameData.getMonsterAffixDataMap().get(affixId.intValue());
if (!affix.isPreAdd()) continue;

View File

@ -1,5 +1,6 @@
package emu.grasscutter.game.entity;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.ability.*;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.*;
@ -51,8 +52,8 @@ public abstract class GameEntity {
public abstract void initAbilities();
public int getEntityType() {
return this.getId() >> 24;
public EntityType getEntityType() {
return EntityIdType.toEntityType(this.getId() >> 24);
}
public abstract int getEntityTypeId();
@ -226,6 +227,82 @@ public abstract class GameEntity {
public void onRemoved() {}
private int[] parseCountRange(String range) {
var split = range.split(";");
if (split.length == 1)
return new int[] {Integer.parseInt(split[0]), Integer.parseInt(split[0])};
return new int[] {Integer.parseInt(split[0]), Integer.parseInt(split[1])};
}
public boolean dropSubfieldItem(int dropId) {
var drop = GameData.getDropSubfieldMappingMap().get(dropId);
if (drop == null) return false;
var dropTableEntry = GameData.getDropTableExcelConfigDataMap().get(drop.getItemId());
if (dropTableEntry == null) return false;
Int2ObjectMap<Integer> itemsToDrop = new Int2ObjectOpenHashMap<>();
switch (dropTableEntry.getRandomType()) {
case 0: // select one
{
int weightCount = 0;
for (var entry : dropTableEntry.getDropVec()) weightCount += entry.getWeight();
int randomValue = new Random().nextInt(weightCount);
weightCount = 0;
for (var entry : dropTableEntry.getDropVec()) {
if (randomValue >= weightCount && randomValue < (weightCount + entry.getWeight())) {
var countRange = parseCountRange(entry.getCountRange());
itemsToDrop.put(
entry.getItemId(),
Integer.valueOf((new Random().nextBoolean() ? countRange[0] : countRange[1])));
}
}
}
break;
case 1: // Select various
{
for (var entry : dropTableEntry.getDropVec()) {
if (entry.getWeight() < new Random().nextInt(10000)) {
var countRange = parseCountRange(entry.getCountRange());
itemsToDrop.put(
entry.getItemId(),
Integer.valueOf((new Random().nextBoolean() ? countRange[0] : countRange[1])));
}
}
}
break;
}
for (var entry : itemsToDrop.int2ObjectEntrySet()) {
var item =
new EntityItem(
scene,
null,
GameData.getItemDataMap().get(entry.getIntKey()),
getPosition().nearby2d(1f).addY(0.5f),
entry.getValue(),
true);
scene.addEntity(item);
}
return true;
}
public boolean dropSubfield(String subfieldName) {
var subfieldMapping = GameData.getSubfieldMappingMap().get(getEntityTypeId());
if (subfieldMapping == null || subfieldMapping.getSubfields() == null) return false;
for (var entry : subfieldMapping.getSubfields()) {
if (entry.getSubfieldName().compareTo(subfieldName) == 0) {
return dropSubfieldItem(entry.getDrop_id());
}
}
return false;
}
public void onTick(int sceneTime) {
if (entityController != null) {
entityController.onTimer(this, sceneTime);

View File

@ -75,6 +75,7 @@ public class GadgetChest extends GadgetContent {
} else if (chest.chest_drop_id != 0) {
status = dropSystem.handleChestDrop(chest.chest_drop_id, chest.drop_count, getGadget());
}
if (status) {
getGadget().updateState(ScriptGadgetState.ChestOpened);
player.sendPacket(

View File

@ -14,6 +14,8 @@ import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.GatherGadgetInfoOuterClass.GatherGadgetInfo;
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
import emu.grasscutter.utils.Utils;
@ -57,6 +59,13 @@ public final class GadgetGatherObject extends GadgetContent {
GameItem item = new GameItem(itemData, 1);
player.getInventory().addItem(item, ActionReason.Gather);
getGadget()
.getScene()
.getScriptManager()
.callEvent(
new ScriptArgs(
getGadget().getGroupId(), EventType.EVENT_GATHER, getGadget().getConfigId()));
getGadget()
.getScene()
.broadcastPacket(

View File

@ -133,13 +133,9 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
for (var item : items) {
if (item.getItemId() == 0) continue;
GameItem result = null;
try {
// putItem might throw exception
// ignore that exception and continue
result = putItem(item);
} catch (Exception e) {
e.printStackTrace();
}
if (result != null) {
this.triggerAddItemEvents(result);
changedItems.add(result);
@ -155,22 +151,33 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
}
private void triggerAddItemEvents(GameItem result) {
try {
getPlayer()
.getBattlePassManager()
.triggerMission(
WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount());
WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM,
result.getItemId(),
result.getCount());
getPlayer()
.getQuestManager()
.queueEvent(QuestContent.QUEST_CONTENT_OBTAIN_ITEM, result.getItemId(), result.getCount());
.queueEvent(
QuestContent.QUEST_CONTENT_OBTAIN_ITEM, result.getItemId(), result.getCount());
} catch (Exception e) {
Grasscutter.getLogger().debug("triggerAddItemEvents failed", e);
}
}
private void triggerRemItemEvents(GameItem item, int removeCount) {
try {
getPlayer()
.getBattlePassManager()
.triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, item.getItemId(), removeCount);
getPlayer()
.getQuestManager()
.queueEvent(QuestContent.QUEST_CONTENT_ITEM_LESS_THAN, item.getItemId(), item.getCount());
} catch (Exception e) {
Grasscutter.getLogger().debug("triggerRemItemEvents failed", e);
}
}
public void addItemParams(Collection<ItemParam> items) {
@ -193,8 +200,11 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
// Dont add items that dont have a valid item definition.
var data = item.getItemData();
if (data == null) return null;
try {
this.player.getProgressManager().addItemObtainedHistory(item.getItemId(), item.getCount());
} catch (Exception e) {
Grasscutter.getLogger().debug("addItemObtainedHistory failed", e);
}
if (data.isUseOnGain()) {
var params = new UseItemParams(this.player, data.getUseTarget());

View File

@ -317,7 +317,9 @@ public class StaminaManager extends BasePlayerManager {
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
entity.getWorld().broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD));
player.getScene().removeEntity(entity);
((EntityAvatar) entity).onDeath(dieType, 0);
if (entity instanceof EntityAvatar avatar)
avatar.onDeath(dieType, 0);
}
public void startSustainedStaminaHandler() {

View File

@ -345,16 +345,11 @@ public class Player implements PlayerHook, FieldFetch {
this.playerGameTime = gameTime;
// If the player is the host of the world, update the game time as well.
if (this.getWorld().getHost() == this) {
this.getWorld().changeTime(gameTime);
var world = this.getWorld();
if (world != null && world.getHost() == this) {
world.changeTime(gameTime);
}
// Trigger the script event for game time update.
var questManager = this.getQuestManager();
questManager.queueEvent(QuestCond.QUEST_COND_IS_DAYTIME);
questManager.queueEvent(QuestCond.QUEST_COND_TIME_VAR_GT_EQ);
questManager.queueEvent(QuestCond.QUEST_COND_TIME_VAR_PASS_DAY);
this.save();
}
@ -707,14 +702,16 @@ public class Player implements PlayerHook, FieldFetch {
}
public void onEnterRegion(SceneRegion region) {
var enterRegionName = "ENTER_REGION_" + region.config_id;
this.getQuestManager().forEachActiveQuest(quest -> {
if (quest.getTriggerData() != null &&
quest.getTriggers().containsKey("ENTER_REGION_"+ region.config_id)) {
quest.getTriggers().containsKey(enterRegionName) &&
region.getGroupId() == quest.getTriggerData().get(enterRegionName).getGroupId()) {
// If trigger hasn't been fired yet
if (!Boolean.TRUE.equals(quest.getTriggers().put("ENTER_REGION_" + region.config_id, true))) {
if (!Boolean.TRUE.equals(quest.getTriggers().put(enterRegionName, true))) {
this.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE,
quest.getTriggerData().get("ENTER_REGION_" + region.config_id).getId(), 0);
quest.getTriggerData().get(enterRegionName).getId(), 0);
}
}
});
@ -722,13 +719,15 @@ public class Player implements PlayerHook, FieldFetch {
}
public void onLeaveRegion(SceneRegion region) {
var leaveRegionName = "LEAVE_REGION_" + region.config_id;
this.getQuestManager().forEachActiveQuest(quest -> {
if (quest.getTriggers().containsKey("LEAVE_REGION_" + region.config_id)) {
if (quest.getTriggers().containsKey(leaveRegionName) &&
region.getGroupId() == quest.getTriggerData().get(leaveRegionName).getGroupId()) {
// If trigger hasn't been fired yet
if (!Boolean.TRUE.equals(quest.getTriggers().put("LEAVE_REGION_" + region.config_id, true))) {
if (!Boolean.TRUE.equals(quest.getTriggers().put(leaveRegionName, true))) {
this.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE,
quest.getTriggerData().get("LEAVE_REGION_" + region.config_id).getId(), 0);
quest.getTriggerData().get(leaveRegionName).getId(), 0);
}
}
});

View File

@ -4,10 +4,10 @@ import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Transient;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.quest.enums.QuestContent;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@ -29,10 +29,10 @@ public class PlayerProgress {
// keep track of EXEC_ADD_QUEST_PROGRESS count, will be used in CONTENT_ADD_QUEST_PROGRESS
// not sure where to put this, this should be saved to DB but not to individual quest, since
// it will be hard to loop and compare
private Map<Integer, Integer> questProgressCountMap;
private Map<String, Integer> questProgressCountMap;
public PlayerProgress() {
this.questProgressCountMap = new Int2IntOpenHashMap();
this.questProgressCountMap = new ConcurrentHashMap<>();
this.completedDungeons = new IntArrayList();
this.itemHistory = new Int2ObjectOpenHashMap<>();
}
@ -70,15 +70,15 @@ public class PlayerProgress {
return itemEntry.addToObtainedCount(count);
}
public int getCurrentProgress(int progressId) {
public int getCurrentProgress(String progressId) {
return questProgressCountMap.getOrDefault(progressId, -1);
}
public int addToCurrentProgress(int progressId, int count) {
public int addToCurrentProgress(String progressId, int count) {
return questProgressCountMap.merge(progressId, count, Integer::sum);
}
public int resetCurrentProgress(int progressId) {
public int resetCurrentProgress(String progressId) {
return questProgressCountMap.merge(progressId, 0, Integer::min);
}

View File

@ -300,7 +300,7 @@ public final class PlayerProgressManager extends BasePlayerDataManager {
/** Quest progress */
public void addQuestProgress(int id, int count) {
var newCount = player.getPlayerProgress().addToCurrentProgress(id, count);
var newCount = player.getPlayerProgress().addToCurrentProgress(String.valueOf(id), count);
player.save();
player
.getQuestManager()

View File

@ -5,8 +5,7 @@ import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import dev.morphia.annotations.Entity;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.net.proto.AvatarTeamOuterClass.AvatarTeam;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
@Entity
public final class TeamInfo {
@ -87,6 +86,8 @@ public final class TeamInfo {
for (int i = 0; i < this.getAvatars().size(); i++) {
Avatar avatar = player.getAvatars().getAvatarById(this.getAvatars().get(i));
if (avatar == null) continue;
avatarTeam.addAvatarGuidList(avatar.getGuid());
}

View File

@ -1,5 +1,8 @@
package emu.grasscutter.game.props;
import java.util.HashMap;
import java.util.Map;
public enum EntityIdType {
AVATAR(0x01),
MONSTER(0x02),
@ -12,10 +15,27 @@ public enum EntityIdType {
private final int id;
private static final Map<Integer, EntityType> map = new HashMap<>();
static {
map.put(EntityIdType.AVATAR.getId(), EntityType.Avatar);
map.put(EntityIdType.MONSTER.getId(), EntityType.Monster);
map.put(EntityIdType.NPC.getId(), EntityType.NPC);
map.put(EntityIdType.GADGET.getId(), EntityType.Gadget);
map.put(EntityIdType.REGION.getId(), EntityType.Region);
map.put(EntityIdType.WEAPON.getId(), EntityType.Equip);
map.put(EntityIdType.TEAM.getId(), EntityType.Team);
map.put(EntityIdType.MPLEVEL.getId(), EntityType.MPLevel);
}
EntityIdType(int id) {
this.id = id;
}
public static EntityType toEntityType(int entityId) {
return map.getOrDefault(entityId, EntityType.None);
}
public int getId() {
return id;
}

View File

@ -75,6 +75,7 @@ public enum EntityType implements IntValueEnum {
Screen(64),
EchoShell(65),
UIInteractGadget(66),
Region(98),
PlaceHolder(99);
private static final Int2ObjectMap<EntityType> map = new Int2ObjectOpenHashMap<>();

View File

@ -314,7 +314,7 @@ public class GameMainQuest {
0, new Position(avatarPosPos.get(0), avatarPosPos.get(1), avatarPosPos.get(2))); // position
posAndRot.add(
1, new Position(avatarPosRot.get(0), avatarPosRot.get(1), avatarPosRot.get(2))); // rotation
Grasscutter.getLogger().info("Succesfully loaded rewind data for subQuest {}", subId);
Grasscutter.getLogger().debug("Successfully loaded rewind data for quest {}.", subId);
return true;
}

View File

@ -51,10 +51,12 @@ public class GameQuest {
this.state = QuestState.QUEST_STATE_UNSTARTED;
this.triggerData = new HashMap<>();
this.triggers = new HashMap<>();
this.finishProgressList = new int[questData.getFinishCond().size()];
this.failProgressList = new int[questData.getFailCond().size()];
this.finishTime = 0;
}
public void start() {
this.clearProgress(false);
this.acceptTime = Utils.getCurrentSeconds();
this.startTime = this.acceptTime;
this.startGameDay = getOwner().getWorld().getTotalGameTimeDays();
@ -142,7 +144,7 @@ public class GameQuest {
}
public void setFinishProgress(int index, int value) {
finishProgressList[index] = value;
this.finishProgressList[index] = value;
}
public void setFailProgress(int index, int value) {
@ -153,17 +155,30 @@ public class GameQuest {
// TODO improve
var oldState = state;
if (questData.getFinishCond() != null && questData.getFinishCond().size() != 0) {
for (var condition : questData.getFinishCond()) {
if (condition.getType() == QuestContent.QUEST_CONTENT_LUA_NOTIFY) {
this.getOwner().getPlayerProgress().resetCurrentProgress(condition.getParamStr());
}
}
this.finishProgressList = new int[questData.getFinishCond().size()];
}
if (questData.getFailCond() != null && questData.getFailCond().size() != 0) {
for (var condition : questData.getFailCond()) {
if (condition.getType() == QuestContent.QUEST_CONTENT_LUA_NOTIFY) {
this.getOwner().getPlayerProgress().resetCurrentProgress(condition.getParamStr());
}
}
this.failProgressList = new int[questData.getFailCond().size()];
}
this.getOwner().getPlayerProgress().resetCurrentProgress(String.valueOf(this.subQuestId));
setState(QuestState.QUEST_STATE_UNSTARTED);
finishTime = 0;
acceptTime = 0;
startTime = 0;
this.getOwner().getPlayerProgress().resetCurrentProgress(this.subQuestId);
if (oldState == QuestState.QUEST_STATE_UNSTARTED) {
return false;
}

View File

@ -111,7 +111,9 @@ public class QuestManager extends BasePlayerManager {
30700, // Quest which is responsible for unlocking Crash Course.
30800, // Quest which is responsible for unlocking Sparks Amongst the Pages.
47001, 47002, 47003, 47004
47001, 47002, 47003, 47004,
2010103, 2010144 // Prologue Act 2: Chasing Shadows
));
}
}

View File

@ -14,7 +14,8 @@ public class ContentAddQuestProgress extends BaseContent {
public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
val progressId = condition.getParam()[0];
val currentCount = quest.getOwner().getPlayerProgress().getCurrentProgress(progressId);
val currentCount =
quest.getOwner().getPlayerProgress().getCurrentProgress(String.valueOf(progressId));
// if the condition count is 0 I think it is safe to assume that the
// condition count from EXEC only needs to be 1

View File

@ -3,8 +3,7 @@ package emu.grasscutter.game.quest.content;
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_TALK;
import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValueContent;
import emu.grasscutter.game.quest.*;
import lombok.val;
@QuestValueContent(QUEST_CONTENT_COMPLETE_TALK)

View File

@ -2,20 +2,16 @@ package emu.grasscutter.game.quest.content;
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_FINISH_PLOT;
import emu.grasscutter.data.binout.MainQuestData;
import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValueContent;
import emu.grasscutter.game.quest.*;
@QuestValueContent(QUEST_CONTENT_FINISH_PLOT)
public class ContentFinishPlot extends BaseContent {
@Override
public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
MainQuestData.TalkData talkData =
quest.getMainQuest().getTalks().get(Integer.valueOf(params[0]));
GameQuest subQuest = quest.getMainQuest().getChildQuestById(params[0]);
var talkData = quest.getMainQuest().getTalks().get(params[0]);
var subQuest = quest.getMainQuest().getChildQuestById(params[0]);
return (talkData != null && subQuest != null || condition.getParamStr().equals(paramStr))
&& condition.getParam()[0] == params[0];
}

View File

@ -12,6 +12,8 @@ public class ContentLuaNotify extends BaseContent {
@Override
public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
return condition.getParamStr().equals(paramStr);
return condition.getParamStr().equals(paramStr)
&& condition.getCount()
<= quest.getOwner().getPlayerProgress().getCurrentProgress(paramStr);
}
}

View File

@ -3,22 +3,16 @@ package emu.grasscutter.game.quest.content;
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_NOT_FINISH_PLOT;
import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValueContent;
import lombok.val;
import emu.grasscutter.game.quest.*;
@QuestValueContent(QUEST_CONTENT_NOT_FINISH_PLOT)
public class ContentNotFinishPlot extends BaseContent {
@Override
public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
val talkId = condition.getParam()[0];
val checkMainQuest = quest.getOwner().getQuestManager().getMainQuestByTalkId(talkId);
if (checkMainQuest == null) {
return true;
}
val talkData = checkMainQuest.getTalks().get(talkId);
return talkData == null;
var talkData = quest.getMainQuest().getTalks().get(params[0]);
var subQuest = quest.getMainQuest().getChildQuestById(params[0]);
return (talkData == null && subQuest != null || condition.getParamStr().equals(paramStr))
&& condition.getParam()[0] == params[0];
}
}

View File

@ -1,6 +1,5 @@
package emu.grasscutter.game.quest.exec;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValueExec;
@ -27,33 +26,16 @@ public class ExecNotifyGroupLua extends QuestExecHandler {
}
scene.runWhenFinished(
() -> {
val groupInstance = scriptManager.getGroupInstanceById(groupId);
if (groupInstance != null) {
// workaround to make sure the triggers are still there todo find better way of trigger
// handling
scriptManager.refreshGroup(groupInstance);
Grasscutter.getLogger()
.trace(
"group: {} \ncondition: {} \nparamStr {}",
groupInstance.getLuaGroup(),
condition,
paramStr);
} else {
Grasscutter.getLogger()
.debug(
"notify, no group instance for:\n group: {} \ncondition: {} \nparamStr {}",
groupId,
condition,
paramStr);
}
val eventType =
quest.getState() == QuestState.QUEST_STATE_FINISHED
? EventType.EVENT_QUEST_FINISH
: EventType.EVENT_QUEST_START;
scriptManager.callEvent(
new ScriptArgs(groupId, eventType, quest.getSubQuestId())
new ScriptArgs(
groupId,
eventType,
quest.getSubQuestId(),
quest.getState() == QuestState.QUEST_STATE_FINISHED ? 1 : 0)
.setEventSource(quest.getSubQuestId()));
});

View File

@ -25,6 +25,7 @@ public class ExecRefreshGroupSuite extends QuestExecHandler {
if (!scriptManager.refreshGroupSuite(groupId, suiteId, quest)) {
result = false;
}
scriptManager.getGroupById(groupId).dontUnload = true;
}
return result;

View File

@ -1,13 +1,11 @@
package emu.grasscutter.game.talk;
import static emu.grasscutter.game.quest.enums.QuestCond.QUEST_COND_COMPLETE_TALK;
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK;
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_TALK;
import static emu.grasscutter.game.quest.enums.QuestContent.*;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.MainQuestData.TalkData;
import emu.grasscutter.game.player.BasePlayerManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.*;
import lombok.NonNull;
public final class TalkManager extends BasePlayerManager {
@ -22,10 +20,10 @@ public final class TalkManager extends BasePlayerManager {
* @param npcEntityId The entity ID of the NPC being talked to.
*/
public void triggerTalkAction(int talkId, int npcEntityId) {
var talkData = GameData.getTalkConfigDataMap().get(talkId);
if (talkData == null) return;
var player = this.getPlayer();
var talkData = GameData.getTalkConfigDataMap().get(talkId);
if (talkData != null) {
// Check if the NPC id is valid.
var entity = player.getScene().getEntityById(npcEntityId);
if (entity != null) {
@ -38,14 +36,15 @@ public final class TalkManager extends BasePlayerManager {
.getFinishExec()
.forEach(e -> player.getServer().getTalkSystem().triggerExec(player, talkData, e));
// Save the talk value to the quest's data.
this.saveTalkToQuest(talkId, talkData.getQuestId());
}
// Invoke the talking events for quests.
var questManager = player.getQuestManager();
questManager.queueEvent(QUEST_CONTENT_COMPLETE_ANY_TALK, talkId);
questManager.queueEvent(QUEST_CONTENT_COMPLETE_TALK, talkId);
questManager.queueEvent(QUEST_COND_COMPLETE_TALK, talkId);
// Save the talk value to the quest's data.
this.saveTalkToQuest(talkId, talkData.getQuestId());
}
public void saveTalkToQuest(int talkId, int mainQuestId) {

View File

@ -1,54 +1,43 @@
package emu.grasscutter.game.world;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.*;
import emu.grasscutter.data.binout.SceneNpcBornEntry;
import emu.grasscutter.data.binout.routes.Route;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.data.excels.SceneData;
import emu.grasscutter.data.excels.*;
import emu.grasscutter.data.excels.codex.CodexAnimalData;
import emu.grasscutter.data.excels.monster.MonsterData;
import emu.grasscutter.data.excels.world.WorldLevelData;
import emu.grasscutter.data.server.Grid;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.dungeons.*;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.managers.blossom.BlossomManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.TeamInfo;
import emu.grasscutter.game.player.*;
import emu.grasscutter.game.props.*;
import emu.grasscutter.game.quest.QuestGroupSuite;
import emu.grasscutter.game.world.data.TeleportProperties;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.*;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.EnterTypeOuterClass;
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.SceneIndexManager;
import emu.grasscutter.scripts.SceneScriptManager;
import emu.grasscutter.scripts.*;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneBlock;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.scripts.data.*;
import emu.grasscutter.server.event.entity.EntityCreationEvent;
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.objects.KahnsSort;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
import lombok.*;
public final class Scene {
@Getter private final World world;
@ -551,19 +540,22 @@ public final class Scene {
}
var sceneTime = getSceneTimeSeconds();
getEntities().forEach((eid, e) -> e.onTick(sceneTime));
var entities = Map.copyOf(this.getEntities());
entities.forEach(
(eid, e) -> {
if (!e.isAlive()) {
this.getEntities().remove(eid);
} else e.onTick(sceneTime);
});
blossomManager.onTick();
checkNpcGroup();
this.checkNpcGroup();
this.finishLoading();
this.checkPlayerRespawn();
if (this.tickCount++ % 10 == 0) this.broadcastPacket(new PacketSceneTimeNotify(this));
if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty) {
this.getScriptManager().onDestroy();
this.getWorld().deregisterScene(this);
}
}
/** Validates a player's current position. Teleports the player if the player is out of bounds. */
@ -700,18 +692,6 @@ public final class Scene {
npcBornEntries.addAll(loadNpcForPlayer(player));
}
// clear the unreachable group for client
var toUnload =
this.npcBornEntrySet.stream()
.filter(i -> !npcBornEntries.contains(i))
.map(SceneNpcBornEntry::getGroupId)
.toList();
if (toUnload.size() > 0) {
broadcastPacket(new PacketGroupUnloadNotify(toUnload));
Grasscutter.getLogger().trace("Unload NPC Group {}", toUnload);
}
// exchange the new npcBornEntry Set
this.npcBornEntrySet = npcBornEntries;
}
@ -858,7 +838,7 @@ public final class Scene {
.collect(Collectors.toSet());
for (var group : this.loadedGroups) {
if (!visible.contains(group.id) && !group.dynamic_load)
if (!visible.contains(group.id) && !group.dynamic_load && !group.dontUnload)
unloadGroup(scriptManager.getBlocks().get(group.block_id), group.id);
}
@ -1164,14 +1144,27 @@ public final class Scene {
pos.toDoubleArray(),
Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange);
var sceneNpcBornEntries =
var sceneNpcBornCanidates =
npcList.stream().filter(i -> !this.npcBornEntrySet.contains(i)).toList();
List<SceneNpcBornEntry> sceneNpcBornEntries = new ArrayList<>();
sceneNpcBornCanidates.forEach(
i -> {
var groupInstance = scriptManager.getGroupInstanceById(i.getGroupId());
if (groupInstance == null) return;
if (i.getSuiteIdList() != null
&& !i.getSuiteIdList().contains(groupInstance.getActiveSuiteId())) return;
sceneNpcBornEntries.add(i);
});
if (sceneNpcBornEntries.size() > 0) {
this.broadcastPacket(new PacketGroupSuiteNotify(sceneNpcBornEntries));
Grasscutter.getLogger().trace("Loaded Npc Group Suite {}", sceneNpcBornEntries);
}
return npcList;
return npcList.stream()
.filter(i -> this.npcBornEntrySet.contains(i) || sceneNpcBornEntries.contains(i))
.toList();
}
public void loadGroupForQuest(List<QuestGroupSuite> sceneGroupSuite) {

View File

@ -4,17 +4,14 @@ import static emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportTy
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.dungeon.DungeonData;
import emu.grasscutter.game.entity.EntityTeam;
import emu.grasscutter.game.entity.EntityWorld;
import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.Player.SceneLoadState;
import emu.grasscutter.game.props.EnterReason;
import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.props.*;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.game.world.data.TeleportProperties;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.*;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import emu.grasscutter.scripts.data.SceneConfig;
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
@ -22,15 +19,9 @@ import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.ConversionUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import lombok.Getter;
import lombok.val;
import it.unimi.dsi.fastutil.ints.*;
import java.util.*;
import lombok.*;
import org.jetbrains.annotations.NotNull;
public class World implements Iterable<Player> {
@ -44,7 +35,8 @@ public class World implements Iterable<Player> {
private int nextPeerId = 0;
private int worldLevel;
@Getter private boolean isMultiplayer, timeLocked = false;
@Getter private boolean isMultiplayer = false;
@Getter private boolean timeLocked;
private long lastUpdateTime;
@Getter private int tickCount = 0;
@ -65,6 +57,7 @@ public class World implements Iterable<Player> {
this.entity = new EntityWorld(this);
this.worldLevel = player.getWorldLevel();
this.isMultiplayer = isMultiplayer;
this.timeLocked = player.getProperty(PlayerProperty.PROP_IS_GAME_TIME_LOCKED) != 0;
this.lastUpdateTime = System.currentTimeMillis();
this.currentWorldTime = host.getPlayerGameTime();
@ -164,6 +157,16 @@ public class World implements Iterable<Player> {
player.getTeamManager().getCurrentSinglePlayerTeamInfo(),
player.getTeamManager().getMaxTeamSize());
player.getTeamManager().setCurrentCharacterIndex(0);
if (player != this.getHost()) {
this.broadcastPacket(
new PacketPlayerChatNotify(
player,
0,
SystemHint.newBuilder()
.setType(SystemHintType.SYSTEM_HINT_TYPE_CHAT_ENTER_WORLD.getNumber())
.build()));
}
}
// Add to scene
@ -217,6 +220,14 @@ public class World implements Iterable<Player> {
victim.getSceneId(),
victim.getPosition()));
}
} else {
this.broadcastPacket(
new PacketPlayerChatNotify(
player,
0,
SystemHint.newBuilder()
.setType(SystemHintType.SYSTEM_HINT_TYPE_CHAT_LEAVE_WORLD.getNumber())
.build()));
}
}
@ -426,7 +437,11 @@ public class World implements Iterable<Player> {
// Check if there are players in this world.
if (this.getPlayerCount() == 0) return true;
// Tick all associated scenes.
this.getScenes().forEach((k, scene) -> scene.onTick());
this.getScenes()
.forEach(
(k, scene) -> {
if (scene.getPlayerCount() > 0) scene.onTick();
});
// sync time every 10 seconds
if (this.tickCount % 10 == 0) {
@ -512,10 +527,6 @@ public class World implements Iterable<Player> {
*/
public void changeTime(long gameTime) {
this.currentWorldTime = gameTime;
// Trigger script events.
this.players.forEach(
player -> player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_GAME_TIME_TICK));
}
/**

View File

@ -81,7 +81,7 @@ public final class PluginManager {
if (pluginConfig.api == null) {
Grasscutter.getLogger()
.warn(translate("plugin.invalid_api.not_present", plugin.getName()));
return;
continue;
} else if (pluginConfig.api != API_VERSION) {
Grasscutter.getLogger()
.warn(
@ -90,13 +90,13 @@ public final class PluginManager {
plugin.getName(),
pluginConfig.api,
API_VERSION));
return;
continue;
}
// Check if the plugin config is valid.
if (!pluginConfig.validate()) {
Grasscutter.getLogger().warn(translate("plugin.invalid_config", plugin.getName()));
return;
continue;
}
// Create a JAR file instance from the plugin's URL.
@ -216,9 +216,14 @@ public final class PluginManager {
Grasscutter.getLogger().info(translate("plugin.enabling_plugin", name));
try {
plugin.onEnable();
return;
} catch (NoSuchMethodError ignored) {
Grasscutter.getLogger().error(translate("plugin.invalid_api.outdated", name));
} catch (Throwable exception) {
Grasscutter.getLogger().error(translate("plugin.enabling_failed", name), exception);
}
this.disablePlugin(plugin);
});
}

View File

@ -266,7 +266,8 @@ public class SceneScriptManager {
suiteId,
groupId,
getScene().getId());
} else {
if (targetGroupInstance == null) return false;
}
Grasscutter.getLogger().debug("Refreshing group {} suite {}", groupId, suiteId);
suiteId =
refreshGroup(
@ -274,7 +275,6 @@ public class SceneScriptManager {
suiteId,
false); // If suiteId is zero, the value of suiteId changes
scene.broadcastPacket(new PacketGroupSuiteNotify(groupId, suiteId));
}
return true;
}
@ -629,7 +629,7 @@ public class SceneScriptManager {
getScene().getEntities().values().stream()
.filter(
e ->
e.getEntityType() == EntityType.Avatar.getValue()
e.getEntityType() == EntityType.Avatar
&& region.getMetaRegion().contains(e.getPosition()))
.toList();
entities.forEach(region::addEntity);
@ -644,6 +644,7 @@ public class SceneScriptManager {
.trace("Call EVENT_ENTER_REGION_{}", region.getMetaRegion().config_id);
this.callEvent(
new ScriptArgs(region.getGroupId(), EventType.EVENT_ENTER_REGION, region.getConfigId())
.setEventSource(EntityType.Avatar.getValue())
.setSourceEntityId(region.getId())
.setTargetEntityId(targetId));
@ -660,6 +661,7 @@ public class SceneScriptManager {
if (region.entityHasLeft()) {
this.callEvent(
new ScriptArgs(region.getGroupId(), EventType.EVENT_LEAVE_REGION, region.getConfigId())
.setEventSource(EntityType.Avatar.getValue())
.setSourceEntityId(region.getId())
.setTargetEntityId(region.getFirstEntityId()));
@ -681,8 +683,8 @@ public class SceneScriptManager {
|| !groupInstance.getDeadEntities().contains(m.config_id));
})
.map(g -> createGadget(group.id, group.block_id, g, groupInstance.getCachedGadgetState(g)))
.peek(g -> groupInstance.cacheGadgetState(g.getMetaGadget(), g.getState()))
.filter(Objects::nonNull)
.peek(g -> groupInstance.cacheGadgetState(g.getMetaGadget(), g.getState()))
.toList();
}
@ -801,26 +803,27 @@ public class SceneScriptManager {
private void realCallEvent(@Nonnull ScriptArgs params) {
try {
ScriptLoader.getScriptLib().setSceneScriptManager(this);
int eventType = params.type;
Set<SceneTrigger> relevantTriggers = new HashSet<>();
if (eventType == EventType.EVENT_ENTER_REGION || eventType == EventType.EVENT_LEAVE_REGION) {
relevantTriggers =
this.getTriggersByEvent(eventType).stream()
var eventType = params.type;
var relevantTriggers =
switch (eventType) {
case EventType.EVENT_ENTER_REGION, EventType.EVENT_LEAVE_REGION -> this
.getTriggersByEvent(eventType)
.stream()
.filter(
t ->
t.getCondition().contains(String.valueOf(params.param1))
t.getName().substring(13).equals(String.valueOf(params.param1))
&& (t.getSource().isEmpty()
|| t.getSource().equals(params.getEventSource())))
.collect(Collectors.toSet());
} else {
relevantTriggers =
this.getTriggersByEvent(eventType).stream()
default -> this.getTriggersByEvent(eventType).stream()
.filter(
t -> params.getGroupId() == 0 || t.getCurrentGroup().id == params.getGroupId())
.filter(
t -> (t.getSource().isEmpty() || t.getSource().equals(params.getEventSource())))
.collect(Collectors.toSet());
}
};
for (SceneTrigger trigger : relevantTriggers) {
handleEventForTrigger(params, trigger);
}

View File

@ -18,6 +18,7 @@ import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.game.world.SceneGroupInstance;
import emu.grasscutter.net.proto.EnterTypeOuterClass;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.constants.GroupKillPolicy;
import emu.grasscutter.scripts.data.SceneGroup;
@ -129,7 +130,7 @@ public class ScriptLib {
public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) {
logger.debug("[LUA] Call SetWorktopOptionsByGroupId with {},{},{}",
groupId,configId,options);
groupId, configId, options);
val entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId);
@ -152,18 +153,17 @@ public class ScriptLib {
logger.debug("[LUA] Call SetWorktopOptions with {}", printTable(table));
var callParams = this.callParams.getIfExists();
var group = this.currentGroup.getIfExists();
if(callParams == null || group == null){
if (callParams == null || group == null) {
return 1;
}
var configId = callParams.param1;
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
int[] worktopOptions = new int[table.length()];
for(int i = 1 ;i<=table.length() ;i++){
var worktopOptions = new int[table.length()];
for (int i = 1; i<=table.length(); i++) {
worktopOptions[i-1] = table.get(i).optint(-1);
}
if(!(entity instanceof EntityGadget gadget)|| worktopOptions.length == 0){
if (!(entity instanceof EntityGadget gadget) || worktopOptions.length == 0) {
return 2;
}
@ -172,9 +172,11 @@ public class ScriptLib {
}
worktop.addWorktopOptions(worktopOptions);
var scene = getSceneScriptManager().getScene();
var scene = this.getSceneScriptManager().getScene();
// Done in order to synchronize with addEntities in Scene.class.
synchronized (this.getSceneScriptManager().getScene()) {
scene.broadcastPacket(new PacketWorktopOptionNotify(gadget));
}
return 0;
}
@ -401,7 +403,7 @@ public class ScriptLib {
val old = variables.getOrDefault(var, value);
variables.put(var, value);
getSceneScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_VARIABLE_CHANGE, value, old));
getSceneScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_VARIABLE_CHANGE, value, old).setEventSource(var));
return 0;
}
@ -416,7 +418,7 @@ public class ScriptLib {
variables.put(var, old + value);
logger.debug("[LUA] Call ChangeGroupVariableValue with {},{}",
old, old+value);
getSceneScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_VARIABLE_CHANGE, old+value, old));
getSceneScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_VARIABLE_CHANGE, old+value, old).setEventSource(var));
return LuaValue.ZERO;
}
@ -609,6 +611,11 @@ public class ScriptLib {
logger.debug("[LUA] Call CreateGadget with {}",
printTable(table));
var configId = table.get("config_id").toint();
//TODO: figure out what creating gadget configId 0 does
if (configId == 0){
Grasscutter.getLogger().warn("Tried to CreateGadget with config_id 0: {}", printTable(table));
return 0;
}
var group = getCurrentGroup();
@ -667,6 +674,7 @@ public class ScriptLib {
var1);
for(var player : getSceneScriptManager().getScene().getPlayers()){
player.getPlayerProgress().addToCurrentProgress(var1, 1);
player.getQuestManager().queueEvent(QuestCond.QUEST_COND_LUA_NOTIFY, var1);
player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_LUA_NOTIFY, var1);
}
@ -702,7 +710,7 @@ public class ScriptLib {
return EntityType.None.getValue();
}
return entity.getEntityType();
return entity.getEntityType().getValue();
}
public int GetQuestState(int entityId, int questId){
@ -737,11 +745,11 @@ public class ScriptLib {
val entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId);
if(entity == null || entity.getEntityType() != entityType){
if(entity == null || entity.getEntityType().getValue() != entityType){
return 1;
}
getSceneScriptManager().getScene().removeEntity(entity);
getSceneScriptManager().getScene().removeEntity(entity, VisionType.VISION_TYPE_REMOVE);
return 0;
}
@ -815,17 +823,17 @@ public class ScriptLib {
//TODO implement
return 0;
}
public int IsPlayerAllAvatarDie(int sceneUid){
public boolean IsPlayerAllAvatarDie(int sceneUid){
logger.warn("[LUA] Call unimplemented IsPlayerAllAvatarDie {}", sceneUid);
var playerEntities = getSceneScriptManager().getScene().getEntities().values().stream().filter(e -> e.getEntityType() == EntityIdType.AVATAR.getId()).toList();
var playerEntities = getSceneScriptManager().getScene().getEntities().values().stream().filter(e -> e.getEntityType() == EntityType.Avatar).toList();
for (GameEntity p : playerEntities){
var player = (EntityAvatar)p;
if(player.isAlive()){
return 0;
return false;
}
}
//TODO check
return 1;
return true;
}
public int sendShowCommonTipsToClient(String title, String content, int closeTime) {
@ -861,6 +869,11 @@ public class ScriptLib {
//TODO implement var6 object has int success, int fail, bool fail_on_wipe
return 0;
}
public int StopChallenge(int var1, int var2){
logger.warn("[LUA] Call unimplemented StopChallenge with {} {}", var1, var2);
//TODO implement
return 0;
}
public int CreateEffigyChallengeMonster(int var1, int[] var2){
logger.warn("[LUA] Call unimplemented CreateEffigyChallengeMonster with {} {}", var1, var2);
//TODO implement
@ -1598,6 +1611,16 @@ public class ScriptLib {
return 0;
}
public int DropSubfield(LuaTable table) {
String subfield_name = table.get("subfield_name").toString();
var entity = getCurrentEntity();
if(!entity.isPresent()) return -1;
entity.get().dropSubfield(subfield_name);
return -1;
}
public int[] GetGatherConfigIdList() {
EntityGadget gadget = getCurrentEntityGadget();

View File

@ -3,5 +3,8 @@ package emu.grasscutter.scripts.constants;
public enum VisionLevelType {
VISION_LEVEL_NORMAL,
VISION_LEVEL_LITTLE_REMOTE,
VISION_LEVEL_REMOTE
VISION_LEVEL_REMOTE,
VISION_LEVEL_SUPER,
VISION_LEVEL_NEARBY,
VISION_LEVEL_SUPER_NEARBY
}

View File

@ -40,6 +40,7 @@ public final class SceneGroup {
public SceneGarbage garbages;
public SceneInitConfig init_config;
@Getter public boolean dynamic_load = false;
public boolean dontUnload = false;
public SceneReplaceable is_replaceable;

View File

@ -32,9 +32,9 @@ public class SceneRegion {
public boolean contains(Position position) {
switch (shape) {
case ScriptRegionShape.CUBIC:
return (Math.abs(pos.getX() - position.getX()) <= size.getX())
&& (Math.abs(pos.getY() - position.getY()) <= size.getY())
&& (Math.abs(pos.getZ() - position.getZ()) <= size.getZ());
return (Math.abs(pos.getX() - position.getX()) <= size.getX() / 2f)
&& (Math.abs(pos.getY() - position.getY()) <= size.getY() / 2f)
&& (Math.abs(pos.getZ() - position.getZ()) <= size.getZ() / 2f);
case ScriptRegionShape.SPHERE:
var x = Math.pow(pos.getX() - position.getX(), 2);
var y = Math.pow(pos.getY() - position.getY(), 2);

View File

@ -27,7 +27,7 @@ public final class SceneTrigger {
@Override
public int hashCode() {
return name.hashCode();
return (currentGroup.id + name).hashCode();
}
@Override

View File

@ -32,10 +32,11 @@ import emu.grasscutter.server.event.internal.*;
import emu.grasscutter.server.event.types.ServerEvent;
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
import emu.grasscutter.task.TaskMap;
import emu.grasscutter.utils.Utils;
import java.net.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.*;
import kcp.highway.*;
import lombok.*;
import org.jetbrains.annotations.NotNull;
@ -163,9 +164,6 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
// Chata manager
this.chatManager = new ChatSystem(this);
// Hook into shutdown event.
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
}
private static InetSocketAddress getAdapterInetSocketAddress() {
@ -326,16 +324,27 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
}
public void onServerShutdown() {
ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
var event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
event.call();
this.getPlayers()
.forEach(
(uid, player) -> {
player.getSession().close();
});
// Save players & the world.
this.getPlayers().forEach((uid, player) -> player.getSession().close());
this.getWorlds().forEach(World::save);
Utils.sleep(1000L); // Wait 1 second for operations to finish.
this.stop(); // Stop the server.
try {
var threadPool = GameSessionManager.getLogicThread();
// Shutdown network thread.
threadPool.shutdownGracefully();
// Wait for the network thread to finish.
if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
Grasscutter.getLogger().error("Logic thread did not terminate!");
}
} catch (InterruptedException ignored) {
}
}
@NotNull @Override

View File

@ -1,27 +1,20 @@
package emu.grasscutter.server.game;
import static emu.grasscutter.config.Configuration.GAME_INFO;
import static emu.grasscutter.config.Configuration.SERVER;
import static emu.grasscutter.config.Configuration.*;
import static emu.grasscutter.utils.lang.Language.translate;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerDebugMode;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.packet.PacketOpcodesUtils;
import emu.grasscutter.net.packet.*;
import emu.grasscutter.server.event.game.SendPacketEvent;
import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.Utils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import emu.grasscutter.utils.*;
import io.netty.buffer.*;
import java.io.File;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import lombok.Getter;
import lombok.Setter;
import lombok.*;
public class GameSession implements GameSessionManager.KcpChannel {
private final GameServer server;
@ -139,7 +132,11 @@ public class GameSession implements GameSessionManager.KcpChannel {
SendPacketEvent event = new SendPacketEvent(this, packet);
event.call();
if (!event.isCanceled()) { // If event is not cancelled, continue.
try {
tunnel.writeData(event.getPacket().build());
} catch (Exception ignored) {
Grasscutter.getLogger().debug("Unable to send packet to client.");
}
}
}
@ -152,7 +149,6 @@ public class GameSession implements GameSessionManager.KcpChannel {
@Override
public void handleReceive(byte[] bytes) {
// Decrypt and turn back into a packet
if (this.getState() != SessionState.WAITING_FOR_TOKEN)
Crypto.xor(bytes, useSecretKey() ? Crypto.ENCRYPT_KEY : Crypto.DISPATCH_KEY);
ByteBuf packet = Unpooled.wrappedBuffer(bytes);

View File

@ -2,16 +2,15 @@ package emu.grasscutter.server.game;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.utils.Utils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.*;
import io.netty.channel.DefaultEventLoop;
import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;
import kcp.highway.KcpListener;
import kcp.highway.Ukcp;
import kcp.highway.*;
import lombok.Getter;
public class GameSessionManager {
private static final DefaultEventLoop logicThread = new DefaultEventLoop();
@Getter private static final DefaultEventLoop logicThread = new DefaultEventLoop();
private static final ConcurrentHashMap<Ukcp, GameSession> sessions = new ConcurrentHashMap<>();
private static final KcpListener listener =
new KcpListener() {

View File

@ -95,10 +95,13 @@ public final class RegionHandler implements Router {
RegionInfo.newBuilder()
.setGateserverIp(region.Ip)
.setGateserverPort(region.Port)
.setSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
.build();
// Create an updated region query.
var updatedQuery = QueryCurrRegionHttpRsp.newBuilder().setRegionInfo(regionInfo).build();
var updatedQuery =
QueryCurrRegionHttpRsp.newBuilder()
.setRegionInfo(regionInfo)
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
.build();
regions.put(
region.Name,
new RegionData(

View File

@ -7,18 +7,13 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.http.Router;
import emu.grasscutter.utils.DispatchUtils;
import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.Utils;
import emu.grasscutter.utils.*;
import io.javalin.Javalin;
import io.javalin.http.ContentType;
import io.javalin.http.Context;
import io.javalin.http.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.nio.file.*;
import java.util.*;
import lombok.Getter;
/** Handles all gacha-related HTTP requests. */
@ -48,14 +43,14 @@ public final class GachaHandler implements Router {
// Make request to dispatch server.
var data = DispatchUtils.fetchGachaRecords(account.getId(), page, gachaType);
var records = data.get("records").getAsJsonArray();
var records = data.get("records").getAsString();
var maxPage = data.get("maxPage").getAsLong();
var locale = account.getLocale();
var template =
new String(
FileUtils.read(FileUtils.getDataPath("gacha/records.html")), StandardCharsets.UTF_8)
.replace("'{{REPLACE_RECORDS}}'", records.toString())
.replace("'{{REPLACE_RECORDS}}'", Utils.unescapeJson(records))
.replace("'{{REPLACE_MAXPAGE}}'", String.valueOf(maxPage))
.replace("{{TITLE}}", translate(locale, "gacha.records.title"))
.replace("{{DATE}}", translate(locale, "gacha.records.date"))

View File

@ -1,5 +1,6 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
@ -11,6 +12,11 @@ public final class HandlerClientLockGameTimeNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var packet = ClientLockGameTimeNotify.parseFrom(payload);
session.getPlayer().getWorld().lockTime(packet.getIsLock());
// session.getPlayer().getWorld().lockTime(packet.getIsLock());
// TODO: figure out what to implement here
if (packet.getIsLock())
Grasscutter.getLogger()
.warn(
"Invalid 'ClientLockGameTimeNotify' received; value is true. (please report to development channel)");
}
}

View File

@ -1,15 +1,13 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.GadgetData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.data.excels.monster.MonsterData;
import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.world.Position;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.packet.*;
import emu.grasscutter.net.proto.QuestCreateEntityReqOuterClass.QuestCreateEntityReq;
import emu.grasscutter.scripts.data.SceneGadget;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketQuestCreateEntityRsp;
import lombok.val;
@ -30,12 +28,29 @@ public class HandlerQuestCreateEntityReq extends PacketHandler {
case GADGET_ID -> {
val gadgetId = entity.getGadgetId();
val gadgetInfo = entity.getGadget();
GadgetData gadgetData = GameData.getGadgetDataMap().get(gadgetId);
var gadgetData = GameData.getGadgetDataMap().get(gadgetId);
gameEntity =
switch (gadgetData.getType()) {
case Vehicle -> new EntityVehicle(scene, session.getPlayer(), gadgetId, 0, pos, rot);
case Chest -> {
var chest = gadgetInfo.getChest();
var gadget = new EntityGadget(scene, gadgetId, pos, rot);
// Create the gadget data for the chest.
var metaGadget = new SceneGadget();
metaGadget.drop_count = 1; // TODO: Check if more items should be dropped.
metaGadget.chest_drop_id = chest.getChestDropId();
metaGadget.setShowcutscene(chest.getIsShowCutscene());
// Apply the gadget data to the chest.
gadget.setMetaGadget(metaGadget);
yield gadget;
}
default -> new EntityGadget(scene, gadgetId, pos, rot);
};
if (gameEntity instanceof EntityGadget gadget) {
gadget.buildContent();
}
}
case ITEM_ID -> {
val itemId = entity.getItemId();

View File

@ -13,7 +13,6 @@ public class PacketGetPlayerTokenRsp extends BasePacket {
super(PacketOpcodes.GetPlayerTokenRsp, true);
this.setUseDispatchKey(true);
this.shouldEncrypt = false;
GetPlayerTokenRsp p =
GetPlayerTokenRsp.newBuilder()
@ -39,7 +38,6 @@ public class PacketGetPlayerTokenRsp extends BasePacket {
super(PacketOpcodes.GetPlayerTokenRsp, true);
this.setUseDispatchKey(true);
this.shouldEncrypt = false;
GetPlayerTokenRsp p =
GetPlayerTokenRsp.newBuilder()
@ -61,7 +59,6 @@ public class PacketGetPlayerTokenRsp extends BasePacket {
super(PacketOpcodes.GetPlayerTokenRsp, true);
this.setUseDispatchKey(true);
this.shouldEncrypt = false;
GetPlayerTokenRsp p =
GetPlayerTokenRsp.newBuilder()

View File

@ -35,12 +35,12 @@ public class PacketPlayerLoginRsp extends BasePacket {
RegionInfo.newBuilder()
.setGateserverIp(lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress))
.setGateserverPort(lr(GAME_INFO.accessPort, GAME_INFO.bindPort))
.setSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
.build();
regionCache =
var regionCache =
QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp.newBuilder()
.setRegionInfo(serverRegion)
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
.build();
} catch (Exception e) {
Grasscutter.getLogger().error("Error while initializing region cache!", e);

View File

@ -1,23 +1,15 @@
package emu.grasscutter.utils;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.google.gson.stream.*;
import emu.grasscutter.data.common.DynamicFloat;
import emu.grasscutter.game.world.GridPosition;
import emu.grasscutter.game.world.Position;
import emu.grasscutter.game.world.*;
import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.*;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.*;
import lombok.val;
public interface JsonAdapters {

View File

@ -12,6 +12,7 @@ import io.javalin.http.Context;
import io.netty.buffer.*;
import it.unimi.dsi.fastutil.ints.*;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.time.*;
@ -484,6 +485,7 @@ public final class Utils {
*
* @param runnable The task to run.
*/
@SuppressWarnings("BusyWait")
public static void waitFor(Returnable<Boolean> runnable) {
while (!runnable.invoke()) {
try {
@ -493,4 +495,43 @@ public final class Utils {
}
}
}
/**
* Recursively finds all fields in a class.
*
* @param type The class to find fields in.
* @return A list of all fields in the class.
*/
public static List<Field> getAllFields(Class<?> type) {
var fields = new LinkedList<>(Arrays.asList(type.getDeclaredFields()));
// Check for superclasses.
if (type.getSuperclass() != null) {
fields.addAll(getAllFields(type.getSuperclass()));
}
return fields;
}
/**
* Sleeps the current thread without an exception.
*
* @param millis The amount of milliseconds to sleep.
*/
public static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ignored) {
}
}
/**
* Unescapes a JSON string.
*
* @param json The JSON string to unescape.
* @return The unescaped JSON string.
*/
public static String unescapeJson(String json) {
return json.replaceAll("\"", "\"");
}
}

View File

@ -1,11 +1,10 @@
package emu.grasscutter.utils.objects;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.*;
import emu.grasscutter.server.dispatch.IDispatcher;
import emu.grasscutter.utils.Utils;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.*;
public interface FieldFetch {
/**
@ -18,8 +17,7 @@ public interface FieldFetch {
// Prepare field properties.
var fieldValues = new JsonObject();
var fieldMap = new HashMap<String, Field>();
Arrays.stream(this.getClass().getDeclaredFields())
.forEach(field -> fieldMap.put(field.getName(), field));
Utils.getAllFields(this.getClass()).forEach(field -> fieldMap.put(field.getName(), field));
// Find the values of all requested fields.
for (var fieldName : fields) {

View File

@ -463,7 +463,8 @@
"disabling_failed": "Failed to disable plugin: %s",
"invalid_api": {
"not_present": "Plugin %s does not specify an API version.",
"lower": "Plugin %s is using API version %s, while the server is using API version %s."
"lower": "Plugin %s is using API version %s, while the server is using API version %s.",
"outdated": "Plugin %s is using an outdated API method."
}
}
}

View File

@ -463,7 +463,8 @@
"disabling_failed": "Error al desactivar el plugin: %s",
"invalid_api": {
"not_present": "🇺🇸Plugin %s does not specify an API version.",
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
"outdated": "🇺🇸Plugin %s is using an outdated API method."
}
}
}

View File

@ -463,7 +463,8 @@
"disabling_failed": "Impossible de désactiver le plugin %s",
"invalid_api": {
"not_present": "🇺🇸Plugin %s does not specify an API version.",
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
"outdated": "🇺🇸Plugin %s is using an outdated API method."
}
}
}

View File

@ -463,7 +463,8 @@
"disabling_failed": "Impossibile disabilitare il plug-in: %s",
"invalid_api": {
"not_present": "🇺🇸Plugin %s does not specify an API version.",
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
"outdated": "🇺🇸Plugin %s is using an outdated API method."
}
}
}

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