137 Commits

Author SHA1 Message Date
175e7f5f09 Format code [skip actions] 2023-08-01 04:23:23 +00:00
665263d9ba Fix account list subcommand 2023-07-31 17:26:30 -04:00
a4ad781d61 Format code [skip actions] 2023-07-31 16:54:59 +00:00
465582b8da Handle Dungeons with null config (#2279) 2023-07-31 12:52:42 -04:00
4320bc7d29 Format code [skip actions] 2023-07-29 15:40:10 +00:00
98fbc4e512 Improve Platforms (#2275)
* Improve Platforms

* add this.
2023-07-29 11:38:34 -04:00
f3277dee9f Fix Forging (#2278) 2023-07-29 11:37:32 -04:00
0005fcf96f Format code [skip actions] 2023-07-23 03:19:10 +00:00
f065b2b16f Format code [skip actions] 2023-07-23 03:18:53 +00:00
e9d68936f6 Format code [skip actions] 2023-07-23 03:18:29 +00:00
47971dc931 various small bug fixes (#2270)
* various small bug fixes

* Upgrade warning to error

* A few more state changes to match the others in this pull
2023-07-22 23:17:59 -04:00
fe169398ec Gadgets can be picked up too (#2272)
* Gadgets can be picked up too

* put in a warning
2023-07-22 23:17:39 -04:00
ddc082fc97 Everything triggers regions (#2271)
* Everything triggers regions

* hotfix
2023-07-22 23:17:33 -04:00
0b806e21cf Fix talks that have a quest id of 4 digits or more (#2268) 2023-07-22 23:17:18 -04:00
49ba0e55e8 make xxGroupVariableValueByGroup the same as xxGroupVariableValue (#2266) 2023-07-22 23:17:11 -04:00
ae2ab20b5b add support for 3.8 teapot binout files (scene 2005, 2204) (#2265) 2023-07-22 23:17:02 -04:00
27d495742d Format code [skip actions] 2023-07-15 03:05:16 +00:00
f17339f1b6 Send global value packet after the scene host has finished initializing the scene 2023-07-14 23:03:49 -04:00
f0775f70f3 Send packet after scene load & Directly send back entity ID to clients 2023-07-14 21:22:45 -04:00
fecf83cfa4 Revert AvatarUpgradeRsp 2023-07-14 21:09:57 -04:00
dfbe4022f3 Merge remote-tracking branch 'origin/development' into development 2023-07-14 19:47:56 -04:00
e859d87ae3 Implement SetEntityServerGlobalValueByEntityId 2023-07-14 19:46:30 -04:00
acb3575c77 update zh-TW.json (#2260) 2023-07-14 19:37:54 -04:00
f725d9203d Fix QUEST_CONTENT_LEAVE_SCENE (#2262) 2023-07-14 19:37:29 -04:00
d62394e35e Remove obsolete code in ScriptLib.java (#2263) 2023-07-14 19:37:08 -04:00
a4d5de06d1 Fix starting wrong quest for story quests (#2264) 2023-07-14 19:36:50 -04:00
73acfa1178 Update README_zh-TW (#2261)
* Update README_zh-TW.md

添加繁體版快速開始

* Update README_zh-TW.md
2023-07-12 22:01:20 -04:00
0d71d29932 fix first entering teapot failure (#2259) 2023-07-12 22:00:55 -04:00
d0a4da8a1f Update languages [skip actions] 2023-07-09 06:04:19 +00:00
d332861ed8 add italian support (italian translation fix) (#2249)
* Updated IT Readme

* Update it-IT.json

* Update it-IT.json (2)

* fixed a couple errors while reviewing
2023-07-09 02:03:54 -04:00
47186a47b2 It now can bind on correct addr (#2254)
Now Grasscutter will bind on address specified in config.json (bindAddress), instead of 0.0.0.0
2023-07-08 12:27:12 -04:00
5090b17b80 Update ru-RU.json (#2247)
ty Scaldy for help♥♥♥
2023-07-03 23:32:15 -04:00
5b9508d7a4 Update French translations (#2246) 2023-07-03 23:30:22 -04:00
df7941bc1b Format code [skip actions] 2023-07-03 11:03:03 +00:00
9cac0953fa Add alternate val name (#2245) 2023-07-03 07:01:50 -04:00
7cdb774b1f Merge remote-tracking branch 'origin/development' into development 2023-07-01 01:29:40 -04:00
f40cdfd23d Update protocol definition for AvatarUpgradeRsp 2023-07-01 01:29:30 -04:00
4e71a15479 Move unknown condition handler message to debug 2023-07-01 01:29:14 -04:00
6afa1bf276 Bump to 1.6.2 & Fix handbook generation error 2023-07-01 01:28:35 -04:00
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
9e5b57a043 Merge unstable into development (#2173)
* Remove more scene synchronized

* Fix worktop options not appearing

* Format code [skip actions]

* Fix delay with server tasks

* Format code [skip actions]

* Fully fix fairy clock (#2146)

* Fix scene transition

* fully fix fairy clock

* Re-add call to `Player#updatePlayerGameTime`

* Format code [skip actions]

* Initialize the script loader in `ResourceLoader#loadAll`

* Fix region removal checking

* Format code [skip actions]

* Use Lombok's `EqualsAndHashCode` for comparing scene regions

* Format code [skip actions]

* Move 'invalid gather object' to `trace`

* Add more information to the 'unknown condition handler' message

* Move invalid ability action to trace

* Make `KcpTunnel` public

* Validate the NPC being talked to

* Format code [skip actions]

* NPCs are not spawned server side; change logic to handle it

* Format code [skip actions]

* unload scene when there are no players (#2147)

* unload scene when there are no players

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

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

---------

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

* Check if a command should be copied or HTTP should be used

* Lint Code [skip actions]

* Fix character names rendering incorrectly

* Add basic troubleshooting command

* Implement handbook teleporting

also a few formatting changes and sort data by logical sense

* Fix listener `ConcurrentModificationException` issue

* Add color change to `Join the Community!`

* Lint Code [skip actions]

* Make clickable buttons appear clickable

* Remove 'Mechanicus' entities from the list of entities

* Format code [skip actions]

* Fix going back returning a blank screen

* Implement entity spawning

* Add setting level to entity card

* Add support for 'plain text' mode

* Make descriptions of objects scrollable

* Lint Code [skip actions]

* Format code [skip actions]

* Change the way existing hooks work

* Format code [skip actions]

* Upgrade Javalin to 5.5.0 & Fix project warnings

* Upgrade logging libraries

* Fix gacha mappings static file issue

* Add temporary backwards compatability for `ServerHelper`

* Format code [skip actions]

* Remove artifact signatures from VCS

* Fix forge queue data protocol definition

* Run `spotlessApply`

* Format code [skip actions]

* Download data required for building artifacts

* Add call for Facebook logins

* Add the wiki page as a submodule

* Format code [skip actions]

* Update translation (#2150)

* Update translation

* Update translation

* Separate the dispatch and game servers (pt. 1)

gacha is still broken, handbook still needs to be done

* Format code [skip actions]

* Separate the dispatch and game servers (pt. 2)

this commit fixes the gacha page

* Add description for '/troubleshoot'

* Set default avatar talent level to 10

* Separate the dispatch and game servers (pt. 3)

implement handbook across servers!

* Format code [skip actions]

* Update GitHub Actions to use 'download-file' over 'wget'

* Gm handbook lmao (#2149)

* Fix font issue

* Fix avatars

* Fix text overflow in commands

* Fix virtualized lists and items page 😭😭

* magix why 💀

* use hover style in all minicards

* button

* remove console.log

* lint

* Add icons

* magix asked

* Fix overflow padding issue

* Fix achievement text overflow

* remove icons from repo

* Change command icon

* Add the wiki page as a submodule

* total magix moment

* fix text overflow in commands

* Fix discord button

* Make text scale on Minicard

* import icons and font from another source

* Add hover effects to siebar buttons

* move font and readme to submodule repo

* Make data folder a submodule

* import icons and font from data submodule

* Update README.md

* total magix moment

* magix moment v2

* submodule change

* Import `.webp` files

* Resize `HomeButton`

* Fix 'Copy Command' reappearing after changing pages

---------

Co-authored-by: KingRainbow44 <kobedo11@gmail.com>

* Lint Code [skip actions]

* Download data for the build, not for the lint

* format imports

this is really just to see if build handbook works kek

* Implement proper handbook authentication (pt. 1)

* Implement proper handbook authentication (pt. 2)

* Format code [skip actions]

* Add quest data dumping for the handbook

* Change colors to fit _something suitable_

* Format code [skip actions]

* Fix force pushing to branches after linting

* Fix logic of `SetPlayerPropReq`

* Move more group loading to `trace`

* Add handbook IP authentication in hybrid mode

* Fix player level up not displaying on the client properly

* Format code [skip actions]

* Fix game time locking

* Format code [skip actions]

* Update player properties

* Format code [skip actions]

* Move `warn`s for groups to `debug`

* Fix player pausing

* Move more logs to `trace`

* Use `removeItemById` for deleting items via quests

* Clean up logger more

* Pause in-game time when the world is paused

* Format code [skip actions]

* More player property documentation

* Multi-threaded resource loading

* Format code [skip actions]

* Add quest widgets

* Add quests page (basic impl.)

* Add/fix colors

also fix tailwind

* Remove banned packets

client modifications already perform the job of blocking malicious packets from being executed, no point in having this if self-windy is wanted

* Re-add `BeginCameraSceneLookNotify`

* Fix being unable to attack (#2157)

* Add `PlayerOpenChestEvent`

* Add methods to get players from the server

* Add static methods to register an event handler

* Add `PlayerEnterDungeonEvent`

* Remove legacy documentation from `PlayerMoveEvent`

* Add `PlayerChatEvent`

* Add defaults to `Position`

* Clean up `.utils`

* Revert `Multi-threaded resource loading`

* Fix changing target UID when talking to the server

* Lint Code [skip actions]

* Format code [skip actions]

* fix NPC talk triggering main quest in 46101 (#2158)

Make it so that only talks where the param matches the talkId are checked.

* Format code [skip actions]

* Partially fix Chasing Shadows (#2159)

* Partially fix Chasing Shadows

* Go ahead and move it before the return before Magix tells me to.

* Format code [skip actions]

* Bring back period lol (#2160)

* Disable SNI for the HTTPS server

* Add `EntityCreationEvent`

* Add initial startup message

this is so the server appears like its preparing to start

* Format code [skip actions]

* Enable debug mode for plugin loggers if enabled for the primary logger

* Add documentation about `WorldAreaConfigData`

* Make more fields in excels accessible

* Remove deprecated fields from `GetShopRsp`

* Run `spotlessApply` on definitions

* Add `PlayerEnterAreaEvent`

* Optimize event calls

* Fix event invokes

* Format code [skip actions]

* Remove manual autofinish for main quests. (#2162)

* Add world areas to the textmap cache

* Format code [skip actions]

* Don't overdefine variables in extended classes (#2163)

* Add dumper for world areas

* Format code [skip actions]

* instantiate personalLineList (#2165)

* Fix protocol definitions

thank you Nazrin! (+ hiro for raw definitions)

* Fix the background color leaking from the character widget

* Change HTML spacing to 2 spaces

* Implement hiding widgets

* Change scrollbar to a vibrant color

* Add _some_ scaling to the home buttons and its text

* Build the handbook with Gradle

* Fix the 'finer details' with the handbook UI

* Lint Code [skip actions]

* Fix target destination for the Gradle-built handbook

* Implement fetching a player across servers & Add a chainable JsonObject

useful for plugins! might be used in grasscutter eventually

* Fix GitHub actions

* Fix event calling & canceling

* Run `spotlessApply`

* Rename fields (might be wrong)

* Add/update all/more protocol definitions

* Add/update all/more protocol definitions

* Remove outdated packet

* Fix protocol definitions

* Format code [skip actions]

* Implement some lua variables for less console spam (#2172)

* Implement some lua variables for less console spam

* Add GetHostQuestState

This fixes some chapter 3 stuff.

* Format code [skip actions]

* Fix merge import

* Format code [skip actions]

* Fully fix fairy clock for real this time (#2167)

* Fully fix fairy clock For real this time

* Make it so relogging keeps the time lock state.

* Refactor out questLockTime

* Per Hartie, the client packet needs to be changed too

* 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

* Remove all code not needed to get clock working

---------

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

* Implement a proper ability system (#2166)

* Apply fix `21dec2fe`

* Apply fix `89d01d5f`

* Apply fix `d900f154`

this one was already implemented; updated to use call from previous commit

* Ability changing commit

TODO: change info to debug

* Remove use of deprecated methods/fields

* Temp commit v2
(Adding LoseHP and some fixes)

* Oopsie

* Probably fix monster battle

* Fix issue with reflecting into fields

* Fix some things

* Fix ability names for 3.6 resources

* Improve logging

---------

Co-authored-by: StartForKiller <jesussanz2003@gmail.com>

* Format code [skip actions]

* Add system for sending messages between servers

* Format some code

* Remove protocol definitions from Spotless

* Default debug to false; enable with `-debug`

* Implement completely useless global value copying

* HACK: Return the avatar which holds the weapon when the weapon is referred to by ID

* Add properties to `AbilityModifier`

* Change the way HTML is served after authentication

* Use thread executors to speed up the database loading process

* Format code [skip actions]

* Add system for setting handbook address and port

* Lint Code [skip actions]

* Format code [skip actions]

* Fix game-related data not saving

* Format code [skip actions]

* Fix handbook server details

* Lint Code [skip actions]

* Format code [skip actions]

* Use the headers provided by a context to get the IP address

should acknowledge #1975

* Format code [skip actions]

* Move more logs to `trace`

* Format code [skip actions]

* more trace

* Fix something and implement weapon entities

* Format code [skip actions]

* Fix `EntityWeapon`

* Remove deprecated API & Fix resource checking

* Fix unnecessary warning for first-time setup

* Implement handbook request limiting

* Format code [skip actions]

* Fix new avatar weapons being null

* Format code [skip actions]

* Fix issue with 35303 being un-completable & Try to fix fulfilled quest conditions being met

* Load activity config on server startup

* Require plugins to specify an API version and match with the server

* Add default open state ignore list

* Format code [skip actions]

* Quick fix for questing, needs more investigation
This would make the questing work again

* Remove existing hack for 35303

* Fix ignored open states from being set

* Format code [skip actions]

* fix the stupidest bug ive ever seen

* Optimize player kicking on server close

* Format code [skip actions]

* Re-add hack to fix 35303

* Update GitHub actions

* Format code [skip actions]

* Potentially fix issues with regions

* Download additional handbook data

* Revert "Potentially fix issues with regions"

This reverts commit 84e3823695.

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: scooterboo <lewasite@yahoo.com>
Co-authored-by: Tesutarin <105267106+Tesutarin@users.noreply.github.com>
Co-authored-by: Scald <104459145+Arikatsu@users.noreply.github.com>
Co-authored-by: StartForKiller <jesussanz2003@gmail.com>
2023-05-31 23:48:16 -04:00
f46fd372d2 Remove re-open condition from 'protect_files' 2023-05-30 03:18:51 -04:00
131 changed files with 4666 additions and 2654 deletions

View File

@ -4,7 +4,6 @@ on:
pull_request_target: pull_request_target:
types: types:
- opened - opened
- reopened
branches: branches:
- development - development
paths: paths:

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) ![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> <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). **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+) - Click the small button next to launch.
- Click the launch button.
* Proxy Daemon: [mitmproxy](https://mitmproxy.org/) (mitmdump, recommended), [Fiddler Classic](https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe), etc. - Log in with whatever username you want. Password doesn't matter.
### 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.**
### Building ### Building
@ -80,7 +52,7 @@ Grasscutter uses Gradle to handle dependencies & building.
##### Windows ##### Windows
```shell ```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 cd Grasscutter
.\gradlew.bat # Setting up environments .\gradlew.bat # Setting up environments
.\gradlew jar # Compile .\gradlew jar # Compile
@ -89,7 +61,7 @@ cd Grasscutter
##### Linux (GNU) ##### Linux (GNU)
```bash ```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 cd Grasscutter
chmod +x gradlew chmod +x gradlew
./gradlew jar # Compile ./gradlew jar # Compile

View File

@ -57,7 +57,7 @@ sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17
group = 'io.grasscutter' group = 'io.grasscutter'
version = '2.0.0-unstable' version = '1.6.2'
java { java {
withJavadocJar() withJavadocJar()
@ -335,23 +335,55 @@ tasks.register('generateHandbook') {
return return
} }
def nodeVersion = { // Resolve the NPM command.
var npm = 'npm'
if (Os.isFamily(Os.FAMILY_WINDOWS))
npm = 'npm.cmd'
def npmVersion = {
try { try {
return 'node --version'.execute().text.trim() return "${npm} --version".execute()
} catch (ignored) { } catch (ignored) {
return 'NODE_NOT_FOUND' ignored.printStackTrace()
return 'NPM_NOT_FOUND'
} }
} }
// Check if Node is installed. // Check if Node is installed.
if (nodeVersion() == 'NODE_NOT_FOUND') { if (npmVersion() == 'NPM_NOT_FOUND') {
println('Node is not installed. Skipping handbook generation.') println('NPM is not installed. Skipping handbook generation.')
} else { } else {
// Build the handbook. // Check if the handbook resources are present.
var npm = 'npm' if (!file('src/handbook/data/commands.json')) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) println('Command data was not found. Skipping handbook generation.')
npm = 'npm.cmd' 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.
exec { exec {
workingDir 'src/handbook' workingDir 'src/handbook'
commandLine npm, 'run', 'build' commandLine npm, 'run', 'build'

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) ![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> <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) ![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> <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) ![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> <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) ![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> <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) ![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> <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>
@ -18,90 +18,57 @@
* Apparition de monstres via la console * Apparition de monstres via la console
* Inventaire (obtention d'objets/de personnages, amélioration d'objets/personnages, etc) * Inventaire (obtention d'objets/de personnages, amélioration d'objets/personnages, etc)
## Guide de démarrage rapide ## Guide d'installation rapide
**Note:** Pour obtenir un support, rejoignez notre serveur [Discord](https://discord.gg/T5vZU6UyeG) (en anglais). **Note:** Pour obtenir un support, rejoignez notre serveur [Discord](https://discord.gg/T5vZU6UyeG) (en anglais).
### Logiciels requis ### Démarage rapide (Automatique)
* Java SE - 17 ([link](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)) - Téléchargez Java 17: https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html
- Téléchargez [MongoDB Community Server](https://www.mongodb.com/try/download/community)
- Téléchargez la version du jeu REL3.7 (Le client de jeut peut être obtenu ici si vous ne l'avez pas): https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/3.7.0.md
**Note:** Si vous voulez juste **l'exécuter**, Alors vous pouvez télécharger seulement le **jre** - Téléchargez la [dernière version de Cultivation](https://github.com/Grasscutters/Cultivation/releases/latest). Ulilisez l'installateur en `.msi`.
- Après avoir ouvert Cultivation (en administrateur), appuyez sur le bouton de téléchargement en haut a droite.
- Cliquez sur le bouton `Téléchargez tout-en-un`
- Cliquez sur l'engrenage dans le coin en haut a droite.
- Définisez l'emplacement d'installation du jeu.
- Définisez le chemin Java personnalisé à `C:\Program Files\Java\jdk-17\bin\java.exe`
- Laissez tous les autres paramètes par défauts
* MongoDB (4.0+ recommandé) - Appuyez sur le bouton a coté de Lancer.
- Appuyez sur le bouton Lancer.
- Connectez vous avec le nom d'utilisateur que vous voulez. Le mot de passe n'a pas d'importance.
* Proxy daemon: mitmproxy (mitmdump, recommended), Fiddler Classic, etc. ### Compilation
### Lancement Grasscutter utilise Gradle pour la gestion des dépendances et la compilation.
**Note:** Si vous avez mis à jour depuis une ancienne version, supprimez `config.json` pour le regénérer. **Prérequis**
1. Obtenez `grasscutter.jar` - [Java SE Development Kits - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) ou plus récent
- Téléchargez le depuis les [actions](https://github.com/Grasscutters/Grasscutter/suites/6895963598/artifacts/267483297)
- [Buildez le par vous-même](#Building)
2. Créez un dossier `resources` dans le dossier où grasscutter.jar est situé et déplacez vos dossiers `BinOutput` et `ExcelBinOutput` ici *(Vérifiez le [wiki](https://github.com/Grasscutters/Grasscutter/wiki) pour plus de détails sur comment les obtenir.)*
3. Exécutez Grasscutter avec `java -jar grasscutter.jar`. **Soyez sûr que le service MongoDB est en cours d'exécution.**
### Connection avec le client
½. Créez un compte avec la [console de commande du serveur](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting).
1. Redirection du traffic: (Choisissez-en un)
- mitmdump: `mitmdump -s proxy.py -k`
Approuvez le certificat CA:
**Note:**Le certificat CA est généralement stocké sous `%USERPROFILE%\ .mitmproxy`, ou vous pouvez le télécharger depuis `http://mitm.it`
Double-cliquez pour [installer](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) oo ...
- Via la ligne de commande
```shell
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
```
- Fiddler Classic: Exécutez Fiddler Classic, Activez `Decrypt https traffic` dans les paramètres et changez le port par défaut ici (Tools -> Options -> Connections) à autre chose que `8888`, et chargez [ce script](https://github.lunatic.moe/fiddlerscript).
- [Fichier hosts](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. Définissez le proxy du réseau comme `127.0.0.1:8080` ou le port du proxy que vous avez spécifié.
**Vous pouvez aussi utiliser `start.cmd` to démarrer les serveurs et le proxy automatiquement, mais vous devez mettre en place la variable d'environnement JAVA_HOME**
### Building
Grasscutter utilise Gradle pour gérer les dépendances et la construction.
**Logiciels requis:**
- [Java SE Development Kits - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
- [Git](https://git-scm.com/downloads) - [Git](https://git-scm.com/downloads)
##### Windows ##### Windows
```shell ```shell
git clone https://github.com/Grasscutters/Grasscutter.git git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter cd Grasscutter
.\gradlew.bat # Mettre en place l'environnement .\gradlew.bat # Setting up environments
.\gradlew jar # Compiler .\gradlew jar # Compile
``` ```
##### Linux ##### Linux (GNU)
```bash ```bash
git clone https://github.com/Grasscutters/Grasscutter.git git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter cd Grasscutter
chmod +x gradlew chmod +x gradlew
./gradlew jar # Compiler ./gradlew jar # Compile
``` ```
Vous trouverez le fichier jar compilé à la racine du dossier du projet. Vous pouvez trouver le jar de sortie dans la racine du dossier du projet.
### Les commandes ont été déplacé vers le [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)! (en anglais) ### Dépanage
# Dépannage rapide Pour une liste des problèmes communs et leur solution et pour demander de l'aide, veuillez rejoindre [notre serveur Discord](https://discord.gg/T5vZU6UyeG) (en anglais) et dirigez vous vers le salon de support.
* Si la compilation a échoué, veuillez vérifier votre installation de votre JDK (JDK 17 et le bon dossier bin du JDK dans la variable PATH)
* Mon client ne se connecte pas au serveur, impossible de se connecter a mon compte, 4206, etc... - La plupart du temps, *le problème* vient de la configuration de votre proxy. Si vous utilisez Fiddler, vérifiez s'il est exécuté sur un port autre que 8888
* Séquence de démarrage : MongoDB > Grasscutter > Proxy (mitmdump, fiddler, etc...) > Jeu

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) ![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> <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) ![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> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.md) [EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.md)
**Attenzione:** Diamo sempre il benvenuto ai contributori del progetto. Prima di aggiungere il tuo contributo, leggi attentamente il nostro [Codice di condotta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md). **Attenzione:** Diamo sempre il benvenuto ai contributori del progetto. Prima di contribuire, leggi attentamente il nostro [Codice di condotta](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
## Funzionalità attuali ## Funzionalità attuali
@ -15,12 +15,12 @@
* Teletrasporto * Teletrasporto
* Sistema Gacha * Sistema Gacha
* Cooperativa *parzialmente* funzionale * Cooperativa *parzialmente* funzionale
* Evoca mostri dalla console * Evocazione nemici usando la console
* Funzionalità dell'inventario (ricevi oggetti/personaggi, aggiorna oggetti/personaggi, ecc.) * Inventario (ricevi e aggiorna oggetti/personaggi, ecc.)
## Guida rapida all'installazione ## Guida rapida all'installazione
**Nota:** Per il supporto, unisciti al nostro [Discord](https://discord.gg/T5vZU6UyeG). **Nota:** Se hai bisogno di aiuto, unisciti al nostro [Discord](https://discord.gg/T5vZU6UyeG).
### Requisiti ### Requisiti
@ -30,30 +30,30 @@
* [MongoDB](https://www.mongodb.com/try/download/community) (consigliato 4.0+) * [MongoDB](https://www.mongodb.com/try/download/community) (consigliato 4.0+)
* Servizio proxy: mitmproxy (mitmdump, consigliato), Fiddler Classic, ecc. * Servizi proxy: mitmproxy (mitmdump, consigliato), Fiddler Classic, ecc.
### Esecuzione ### Esecuzione
**Nota:** Se hai eseguito l'aggiornamento da una versione precedente, rimuovi `config.json` in modo che venga generato di nuovo. **Nota:** Se hai aggiornato da una versione precedente, elimina `config.json` in modo che venga generato di nuovo.
1. Ottieni "grasscutter.jar". 1. Ottieni "grasscutter.jar".
- Scarica da [azioni](https://github.com/Grasscutters/Grasscutter/suites/6895963598/artifacts/267483297) - Scarica da [azioni](https://github.com/Grasscutters/Grasscutter/suites/6895963598/artifacts/267483297)
- [Compilalo tu stesso](#Compilazione) - [Compilalo tu stesso](#Compilazione)
2. Crea una cartella `resources` nella directory in cui si trova grasscutter.jar e sposta lì le cartelle `BinOutput` ed `ExcelBinOutput` *(Vedi il [wiki](https://github.com/Grasscutters/Grasscutter/wiki ) per maggiori dettagli su come ottenerli.)* 2. Crea una cartella chiamata `resources` nella directory in cui si trova grasscutter.jar e sposta lì le cartelle `BinOutput` ed `ExcelBinOutput` *(Vedi il [wiki](https://github.com/Grasscutters/Grasscutter/wiki ) per maggiori dettagli su come ottenerli.)*
3. Eseguire Grasscutter con `java -jar grasscutter.jar`. **Assicurati che il servizio mongodb sia attivo.** 3. Esegui Grasscutter con `java -jar grasscutter.jar`. **Assicurati che il servizio mongodb sia attivo.**
### Connessione client ### Connessione al client
½. Crea un account usando [il comando corrispondente nella console del server](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting). ½. Crea un account usando [il comando corrispondente nella console del server](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting).
1. Reindirizza il traffico: (scegli uno) 1. Reindirizza il traffico: (scegli uno)
- mitmdump: `mitmdump -s proxy.py -k` - Con mitmdump: `mitmdump -s proxy.py -k`
Autorizza il certificato CA: Autorizza il certificato CA:
**Nota:**Il certificato CA si trova solitamente in `%USERPROFILE%\ .mitmproxy`, oppure puoi scaricarlo da `http://mitm.it` **Nota:**Il certificato CA si trova solitamente in `%USERPROFILE%\ .mitmproxy`, oppure puoi scaricarlo da `http://mitm.it`
Fare doppio clic su [installa](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) o ... Fai doppio clic su [installa](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) o ...
- Con riga di comando - Con riga di comando
@ -61,11 +61,11 @@
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
``` ```
- Fiddler Classic: esegui Fiddler Classic, abilita `Decrypt https traffic` nelle opzioni e cambia la porta predefinita in (Strumenti -> Opzioni -> Connessioni) in qualcosa di diverso da `8888`, e carica [questo script](https :/ /github.lunatic.moe/fiddlerscript). - Con Fiddler Classic: esegui Fiddler Classic, abilita `Decrypt https traffic` nelle opzioni e cambia la porta predefinita in (Strumenti -> Opzioni -> Connessioni) in qualcosa di diverso da `8888`, e carica [questo script](https://github.lunatic.moe/fiddlerscript).
- [File host](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map) - [File host](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
2. Impostare il proxy di rete su `127.0.0.1:8080` o la porta proxy impostata. 2. Imposta il proxy di rete a `127.0.0.1:8080` o la porta proxy impostata.
**Puoi anche usare `start.cmd` per avviare automaticamente il server e il servizio proxy, ma devi impostare l'ambiente JAVA_HOME** **Puoi anche usare `start.cmd` per avviare automaticamente il server e il servizio proxy, ma devi impostare l'ambiente JAVA_HOME**
@ -98,11 +98,11 @@ chmod +x gradlew
Puoi trovare il jar generato nella cartella principale del progetto. Puoi trovare il jar generato nella cartella principale del progetto.
### I comandi sono stati spostati nel [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)! ### I comandi sono stati spostati al [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)!
# Soluzioni agli errori comuni # Soluzioni agli errori comuni
* Se la compilazione non riesce, controlla l'installazione di JDK (JDK 17 e convalida la variabile JDK bin PATH) * Se la compilazione non riesce, controlla l'installazione di JDK (JDK 17 e convalida la variabile JDK bin PATH)
* Il mio client non si connette, non accede, 4206, ecc... - Probabilmente le tue impostazioni proxy sono *il problema*, se usi * Se il tuo client non si connette, non accede, da errore 4206, ecc... - Probabilmente *il problema* sono le tue impostazioni proxy, se usi
Fiddler assicurati di utilizzare una porta diversa da 8888 Fiddler assicurati di utilizzare una porta diversa da 8888
* Sequenza di avvio: MongoDB > Grasscutter > Servizio proxy (mitmdump, fiddler, ecc.) > Gioco * Sequenza di avvio: MongoDB > Grasscutter > Servizio proxy (mitmdump, fiddler, ecc.) > Gioco

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) ![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> <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) ![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> <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) ![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> <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) ![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> <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) ![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> <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) ![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> <div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.md) [EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.md)
**注意:** 欢迎成为本项目的贡献者。但在提交 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) - [Git](https://git-scm.com/downloads)
##### Windows ##### Windows
```shell ```shell
git clone https://github.com/Grasscutters/Grasscutter.git git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter cd Grasscutter
.\gradlew.bat # 建立开发环境 .\gradlew.bat # 设置开发环境
.\gradlew jar # 编译 .\gradlew jar # 编译
``` ```
##### Linux ##### LinuxGNU
```bash ```bash
git clone https://github.com/Grasscutters/Grasscutter.git git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
cd Grasscutter cd Grasscutter
chmod +x gradlew chmod +x gradlew
./gradlew jar # 编译 ./gradlew jar # 编译
``` ```
* 编译后的 JAR 文件会在源码根目录生成 你可以在项目的根目录找到输出的jar。
### 命令列表请到 [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands) 查看 ### 故障排除
# 快速问题排除 获取常见问题的解决方案或寻求帮助,请加入[我们的Discord服务器](https://discord.gg/T5vZU6UyeG)并进入“support”频道。
* 如果编译失败, 请检查 JDK 安装是否正确 (需要 JDK 17 并确认 JDK 的 bin 文件夹处于环境变量 `PATH` 中)
* 客户端无法登录、连接、错误 4206 等其他问题... - 大部分情况是因为代理设置出现了*问题*。
如果使用 Fiddler请确认 Fiddler 监听端口不是 `8888`
* 启动顺序: MongoDB > Grasscutter > 代理程序 (mitmdump, Fiddler 等) > 客户端

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) ![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> <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,52 +22,23 @@
**注意:** 如需幫助請加入 [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)
- 下載遊戲版本 REL3.7(如果你沒有的話,可以在[這裡](https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/3.7.0.md)找到 3.7 客戶端)
**注意:** 如果僅想**執行服務端**, 使用 **jre** 即可 - 下載 [最新的 Cultivation 版本](https://github.com/Grasscutters/Cultivation/releases/latest)。使用 `.msi` 安裝程式。
- 以管理員身分打開 Culivation按右上角的下載按鈕。
- 點擊 `Download All-in-One`
- 點擊右上角的齒輪
- 將遊戲安裝路徑設置為你的遊戲所在的位置。
- 將自定義 Java 路徑設置為 `C:\Program Files\Java\jdk-17\bin\java.exe`
- 其他設置保持預設
* [MongoDB](https://www.mongodb.com/try/download/community) (推薦 4.0+) - 點擊啟動旁邊的小按鈕。
- 點擊啟動按鈕。
* 代理程式: mitmproxy (推薦 mitmdump), Fiddler Classic 等 - 用你想要的用戶名登錄,密碼無所謂。
### 執行
**注意:** 從舊版本升級到新版本, 需要刪除 `config.json`
1. 獲取 `grasscutter.jar`
- 從 [actions](https://github.com/Grasscutters/Grasscutter/suites/6895963598/artifacts/267483297) 下載
- [自行編譯](#編譯)
2. 在 JAR 檔案根目錄中建立 `resources` 資料夾並複製 `BinOutput``ExcelBinOutput` *(查看 [wiki](https://github.com/Grasscutters/Grasscutter/wiki) 瞭解更多)*
3. 命令列 `java -jar grasscutter.jar` 執行 Grasscutter。**在此之前請確認 MongoDB 服務執行正常**
### 客戶端連線
½. 在伺服器控制台[建立賬戶](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` 環境變數**
### 編譯 ### 編譯

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

@ -224,6 +224,123 @@ public final class ChatInfoOuterClass {
emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.class, emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.Builder.class); 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 public interface SystemHintOrBuilder extends
// @@protoc_insertion_point(interface_extends:ChatInfo.SystemHint) // @@protoc_insertion_point(interface_extends:ChatInfo.SystemHint)
com.google.protobuf.MessageOrBuilder { com.google.protobuf.MessageOrBuilder {
@ -1907,13 +2024,16 @@ public final class ChatInfoOuterClass {
descriptor; descriptor;
static { static {
java.lang.String[] descriptorData = { 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" + "\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" + "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 " + "(\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" + "\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" + "t\022\014\n\004type\030\r \001(\r\"~\n\016SystemHintType\022\036\n\032SYS" +
"utter.net.protob\006proto3" "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 descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData, .internalBuildGeneratedFileFrom(descriptorData,

View File

@ -25,23 +25,23 @@ public final class ForgeQueueDataOuterClass {
int getAvatarId(); int getAvatarId();
/** /**
* <code>uint32 unfinish_count = 15;</code> * <code>uint32 finish_count = 15;</code>
* @return The unfinishCount.
*/
int getUnfinishCount();
/**
* <code>uint32 next_finish_timestamp = 13;</code>
* @return The nextFinishTimestamp.
*/
int getNextFinishTimestamp();
/**
* <code>uint32 finish_count = 4;</code>
* @return The finishCount. * @return The finishCount.
*/ */
int getFinishCount(); int getFinishCount();
/**
* <code>uint32 total_finish_timestamp = 13;</code>
* @return The totalFinishTimestamp.
*/
int getTotalFinishTimestamp();
/**
* <code>uint32 queue_id = 4;</code>
* @return The queueId.
*/
int getQueueId();
/** /**
* <code>uint32 forge_id = 1;</code> * <code>uint32 forge_id = 1;</code>
* @return The forgeId. * @return The forgeId.
@ -49,16 +49,16 @@ public final class ForgeQueueDataOuterClass {
int getForgeId(); int getForgeId();
/** /**
* <code>uint32 total_finish_timestamp = 8;</code> * <code>uint32 next_finish_timestamp = 8;</code>
* @return The totalFinishTimestamp. * @return The nextFinishTimestamp.
*/ */
int getTotalFinishTimestamp(); int getNextFinishTimestamp();
/** /**
* <code>uint32 queue_id = 9;</code> * <code>uint32 unfinish_count = 9;</code>
* @return The queueId. * @return The unfinishCount.
*/ */
int getQueueId(); int getUnfinishCount();
} }
/** /**
* <pre> * <pre>
@ -116,22 +116,22 @@ public final class ForgeQueueDataOuterClass {
} }
case 32: { case 32: {
finishCount_ = input.readUInt32(); queueId_ = input.readUInt32();
break; break;
} }
case 64: { case 64: {
totalFinishTimestamp_ = input.readUInt32(); nextFinishTimestamp_ = input.readUInt32();
break; break;
} }
case 72: { case 72: {
queueId_ = input.readUInt32(); unfinishCount_ = input.readUInt32();
break; break;
} }
case 104: { case 104: {
nextFinishTimestamp_ = input.readUInt32(); totalFinishTimestamp_ = input.readUInt32();
break; break;
} }
case 112: { case 112: {
@ -141,7 +141,7 @@ public final class ForgeQueueDataOuterClass {
} }
case 120: { case 120: {
unfinishCount_ = input.readUInt32(); finishCount_ = input.readUInt32();
break; break;
} }
default: { default: {
@ -187,32 +187,10 @@ public final class ForgeQueueDataOuterClass {
return avatarId_; return avatarId_;
} }
public static final int UNFINISH_COUNT_FIELD_NUMBER = 15; public static final int FINISH_COUNT_FIELD_NUMBER = 15;
private int unfinishCount_;
/**
* <code>uint32 unfinish_count = 15;</code>
* @return The unfinishCount.
*/
@java.lang.Override
public int getUnfinishCount() {
return unfinishCount_;
}
public static final int NEXT_FINISH_TIMESTAMP_FIELD_NUMBER = 13;
private int nextFinishTimestamp_;
/**
* <code>uint32 next_finish_timestamp = 13;</code>
* @return The nextFinishTimestamp.
*/
@java.lang.Override
public int getNextFinishTimestamp() {
return nextFinishTimestamp_;
}
public static final int FINISH_COUNT_FIELD_NUMBER = 4;
private int finishCount_; private int finishCount_;
/** /**
* <code>uint32 finish_count = 4;</code> * <code>uint32 finish_count = 15;</code>
* @return The finishCount. * @return The finishCount.
*/ */
@java.lang.Override @java.lang.Override
@ -220,6 +198,28 @@ public final class ForgeQueueDataOuterClass {
return finishCount_; return finishCount_;
} }
public static final int TOTAL_FINISH_TIMESTAMP_FIELD_NUMBER = 13;
private int totalFinishTimestamp_;
/**
* <code>uint32 total_finish_timestamp = 13;</code>
* @return The totalFinishTimestamp.
*/
@java.lang.Override
public int getTotalFinishTimestamp() {
return totalFinishTimestamp_;
}
public static final int QUEUE_ID_FIELD_NUMBER = 4;
private int queueId_;
/**
* <code>uint32 queue_id = 4;</code>
* @return The queueId.
*/
@java.lang.Override
public int getQueueId() {
return queueId_;
}
public static final int FORGE_ID_FIELD_NUMBER = 1; public static final int FORGE_ID_FIELD_NUMBER = 1;
private int forgeId_; private int forgeId_;
/** /**
@ -231,26 +231,26 @@ public final class ForgeQueueDataOuterClass {
return forgeId_; return forgeId_;
} }
public static final int TOTAL_FINISH_TIMESTAMP_FIELD_NUMBER = 8; public static final int NEXT_FINISH_TIMESTAMP_FIELD_NUMBER = 8;
private int totalFinishTimestamp_; private int nextFinishTimestamp_;
/** /**
* <code>uint32 total_finish_timestamp = 8;</code> * <code>uint32 next_finish_timestamp = 8;</code>
* @return The totalFinishTimestamp. * @return The nextFinishTimestamp.
*/ */
@java.lang.Override @java.lang.Override
public int getTotalFinishTimestamp() { public int getNextFinishTimestamp() {
return totalFinishTimestamp_; return nextFinishTimestamp_;
} }
public static final int QUEUE_ID_FIELD_NUMBER = 9; public static final int UNFINISH_COUNT_FIELD_NUMBER = 9;
private int queueId_; private int unfinishCount_;
/** /**
* <code>uint32 queue_id = 9;</code> * <code>uint32 unfinish_count = 9;</code>
* @return The queueId. * @return The unfinishCount.
*/ */
@java.lang.Override @java.lang.Override
public int getQueueId() { public int getUnfinishCount() {
return queueId_; return unfinishCount_;
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
@ -270,23 +270,23 @@ public final class ForgeQueueDataOuterClass {
if (forgeId_ != 0) { if (forgeId_ != 0) {
output.writeUInt32(1, forgeId_); output.writeUInt32(1, forgeId_);
} }
if (finishCount_ != 0) {
output.writeUInt32(4, finishCount_);
}
if (totalFinishTimestamp_ != 0) {
output.writeUInt32(8, totalFinishTimestamp_);
}
if (queueId_ != 0) { if (queueId_ != 0) {
output.writeUInt32(9, queueId_); output.writeUInt32(4, queueId_);
} }
if (nextFinishTimestamp_ != 0) { if (nextFinishTimestamp_ != 0) {
output.writeUInt32(13, nextFinishTimestamp_); output.writeUInt32(8, nextFinishTimestamp_);
}
if (unfinishCount_ != 0) {
output.writeUInt32(9, unfinishCount_);
}
if (totalFinishTimestamp_ != 0) {
output.writeUInt32(13, totalFinishTimestamp_);
} }
if (avatarId_ != 0) { if (avatarId_ != 0) {
output.writeUInt32(14, avatarId_); output.writeUInt32(14, avatarId_);
} }
if (unfinishCount_ != 0) { if (finishCount_ != 0) {
output.writeUInt32(15, unfinishCount_); output.writeUInt32(15, finishCount_);
} }
unknownFields.writeTo(output); unknownFields.writeTo(output);
} }
@ -301,29 +301,29 @@ public final class ForgeQueueDataOuterClass {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(1, forgeId_); .computeUInt32Size(1, forgeId_);
} }
if (finishCount_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(4, finishCount_);
}
if (totalFinishTimestamp_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(8, totalFinishTimestamp_);
}
if (queueId_ != 0) { if (queueId_ != 0) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(9, queueId_); .computeUInt32Size(4, queueId_);
} }
if (nextFinishTimestamp_ != 0) { if (nextFinishTimestamp_ != 0) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(13, nextFinishTimestamp_); .computeUInt32Size(8, nextFinishTimestamp_);
}
if (unfinishCount_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(9, unfinishCount_);
}
if (totalFinishTimestamp_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(13, totalFinishTimestamp_);
} }
if (avatarId_ != 0) { if (avatarId_ != 0) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(14, avatarId_); .computeUInt32Size(14, avatarId_);
} }
if (unfinishCount_ != 0) { if (finishCount_ != 0) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(15, unfinishCount_); .computeUInt32Size(15, finishCount_);
} }
size += unknownFields.getSerializedSize(); size += unknownFields.getSerializedSize();
memoizedSize = size; memoizedSize = size;
@ -342,18 +342,18 @@ public final class ForgeQueueDataOuterClass {
if (getAvatarId() if (getAvatarId()
!= other.getAvatarId()) return false; != other.getAvatarId()) return false;
if (getUnfinishCount()
!= other.getUnfinishCount()) return false;
if (getNextFinishTimestamp()
!= other.getNextFinishTimestamp()) return false;
if (getFinishCount() if (getFinishCount()
!= other.getFinishCount()) return false; != other.getFinishCount()) return false;
if (getForgeId()
!= other.getForgeId()) return false;
if (getTotalFinishTimestamp() if (getTotalFinishTimestamp()
!= other.getTotalFinishTimestamp()) return false; != other.getTotalFinishTimestamp()) return false;
if (getQueueId() if (getQueueId()
!= other.getQueueId()) return false; != other.getQueueId()) return false;
if (getForgeId()
!= other.getForgeId()) return false;
if (getNextFinishTimestamp()
!= other.getNextFinishTimestamp()) return false;
if (getUnfinishCount()
!= other.getUnfinishCount()) return false;
if (!unknownFields.equals(other.unknownFields)) return false; if (!unknownFields.equals(other.unknownFields)) return false;
return true; return true;
} }
@ -367,18 +367,18 @@ public final class ForgeQueueDataOuterClass {
hash = (19 * hash) + getDescriptor().hashCode(); hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + AVATAR_ID_FIELD_NUMBER; hash = (37 * hash) + AVATAR_ID_FIELD_NUMBER;
hash = (53 * hash) + getAvatarId(); hash = (53 * hash) + getAvatarId();
hash = (37 * hash) + UNFINISH_COUNT_FIELD_NUMBER;
hash = (53 * hash) + getUnfinishCount();
hash = (37 * hash) + NEXT_FINISH_TIMESTAMP_FIELD_NUMBER;
hash = (53 * hash) + getNextFinishTimestamp();
hash = (37 * hash) + FINISH_COUNT_FIELD_NUMBER; hash = (37 * hash) + FINISH_COUNT_FIELD_NUMBER;
hash = (53 * hash) + getFinishCount(); hash = (53 * hash) + getFinishCount();
hash = (37 * hash) + FORGE_ID_FIELD_NUMBER;
hash = (53 * hash) + getForgeId();
hash = (37 * hash) + TOTAL_FINISH_TIMESTAMP_FIELD_NUMBER; hash = (37 * hash) + TOTAL_FINISH_TIMESTAMP_FIELD_NUMBER;
hash = (53 * hash) + getTotalFinishTimestamp(); hash = (53 * hash) + getTotalFinishTimestamp();
hash = (37 * hash) + QUEUE_ID_FIELD_NUMBER; hash = (37 * hash) + QUEUE_ID_FIELD_NUMBER;
hash = (53 * hash) + getQueueId(); hash = (53 * hash) + getQueueId();
hash = (37 * hash) + FORGE_ID_FIELD_NUMBER;
hash = (53 * hash) + getForgeId();
hash = (37 * hash) + NEXT_FINISH_TIMESTAMP_FIELD_NUMBER;
hash = (53 * hash) + getNextFinishTimestamp();
hash = (37 * hash) + UNFINISH_COUNT_FIELD_NUMBER;
hash = (53 * hash) + getUnfinishCount();
hash = (29 * hash) + unknownFields.hashCode(); hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash; memoizedHashCode = hash;
return hash; return hash;
@ -518,18 +518,18 @@ public final class ForgeQueueDataOuterClass {
super.clear(); super.clear();
avatarId_ = 0; avatarId_ = 0;
unfinishCount_ = 0;
nextFinishTimestamp_ = 0;
finishCount_ = 0; finishCount_ = 0;
forgeId_ = 0;
totalFinishTimestamp_ = 0; totalFinishTimestamp_ = 0;
queueId_ = 0; queueId_ = 0;
forgeId_ = 0;
nextFinishTimestamp_ = 0;
unfinishCount_ = 0;
return this; return this;
} }
@ -557,12 +557,12 @@ public final class ForgeQueueDataOuterClass {
public emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData buildPartial() { public emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData buildPartial() {
emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData result = new emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData(this); emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData result = new emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData(this);
result.avatarId_ = avatarId_; result.avatarId_ = avatarId_;
result.unfinishCount_ = unfinishCount_;
result.nextFinishTimestamp_ = nextFinishTimestamp_;
result.finishCount_ = finishCount_; result.finishCount_ = finishCount_;
result.forgeId_ = forgeId_;
result.totalFinishTimestamp_ = totalFinishTimestamp_; result.totalFinishTimestamp_ = totalFinishTimestamp_;
result.queueId_ = queueId_; result.queueId_ = queueId_;
result.forgeId_ = forgeId_;
result.nextFinishTimestamp_ = nextFinishTimestamp_;
result.unfinishCount_ = unfinishCount_;
onBuilt(); onBuilt();
return result; return result;
} }
@ -614,24 +614,24 @@ public final class ForgeQueueDataOuterClass {
if (other.getAvatarId() != 0) { if (other.getAvatarId() != 0) {
setAvatarId(other.getAvatarId()); setAvatarId(other.getAvatarId());
} }
if (other.getUnfinishCount() != 0) {
setUnfinishCount(other.getUnfinishCount());
}
if (other.getNextFinishTimestamp() != 0) {
setNextFinishTimestamp(other.getNextFinishTimestamp());
}
if (other.getFinishCount() != 0) { if (other.getFinishCount() != 0) {
setFinishCount(other.getFinishCount()); setFinishCount(other.getFinishCount());
} }
if (other.getForgeId() != 0) {
setForgeId(other.getForgeId());
}
if (other.getTotalFinishTimestamp() != 0) { if (other.getTotalFinishTimestamp() != 0) {
setTotalFinishTimestamp(other.getTotalFinishTimestamp()); setTotalFinishTimestamp(other.getTotalFinishTimestamp());
} }
if (other.getQueueId() != 0) { if (other.getQueueId() != 0) {
setQueueId(other.getQueueId()); setQueueId(other.getQueueId());
} }
if (other.getForgeId() != 0) {
setForgeId(other.getForgeId());
}
if (other.getNextFinishTimestamp() != 0) {
setNextFinishTimestamp(other.getNextFinishTimestamp());
}
if (other.getUnfinishCount() != 0) {
setUnfinishCount(other.getUnfinishCount());
}
this.mergeUnknownFields(other.unknownFields); this.mergeUnknownFields(other.unknownFields);
onChanged(); onChanged();
return this; return this;
@ -692,71 +692,9 @@ public final class ForgeQueueDataOuterClass {
return this; return this;
} }
private int unfinishCount_ ;
/**
* <code>uint32 unfinish_count = 15;</code>
* @return The unfinishCount.
*/
@java.lang.Override
public int getUnfinishCount() {
return unfinishCount_;
}
/**
* <code>uint32 unfinish_count = 15;</code>
* @param value The unfinishCount to set.
* @return This builder for chaining.
*/
public Builder setUnfinishCount(int value) {
unfinishCount_ = value;
onChanged();
return this;
}
/**
* <code>uint32 unfinish_count = 15;</code>
* @return This builder for chaining.
*/
public Builder clearUnfinishCount() {
unfinishCount_ = 0;
onChanged();
return this;
}
private int nextFinishTimestamp_ ;
/**
* <code>uint32 next_finish_timestamp = 13;</code>
* @return The nextFinishTimestamp.
*/
@java.lang.Override
public int getNextFinishTimestamp() {
return nextFinishTimestamp_;
}
/**
* <code>uint32 next_finish_timestamp = 13;</code>
* @param value The nextFinishTimestamp to set.
* @return This builder for chaining.
*/
public Builder setNextFinishTimestamp(int value) {
nextFinishTimestamp_ = value;
onChanged();
return this;
}
/**
* <code>uint32 next_finish_timestamp = 13;</code>
* @return This builder for chaining.
*/
public Builder clearNextFinishTimestamp() {
nextFinishTimestamp_ = 0;
onChanged();
return this;
}
private int finishCount_ ; private int finishCount_ ;
/** /**
* <code>uint32 finish_count = 4;</code> * <code>uint32 finish_count = 15;</code>
* @return The finishCount. * @return The finishCount.
*/ */
@java.lang.Override @java.lang.Override
@ -764,7 +702,7 @@ public final class ForgeQueueDataOuterClass {
return finishCount_; return finishCount_;
} }
/** /**
* <code>uint32 finish_count = 4;</code> * <code>uint32 finish_count = 15;</code>
* @param value The finishCount to set. * @param value The finishCount to set.
* @return This builder for chaining. * @return This builder for chaining.
*/ */
@ -775,7 +713,7 @@ public final class ForgeQueueDataOuterClass {
return this; return this;
} }
/** /**
* <code>uint32 finish_count = 4;</code> * <code>uint32 finish_count = 15;</code>
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder clearFinishCount() { public Builder clearFinishCount() {
@ -785,6 +723,68 @@ public final class ForgeQueueDataOuterClass {
return this; return this;
} }
private int totalFinishTimestamp_ ;
/**
* <code>uint32 total_finish_timestamp = 13;</code>
* @return The totalFinishTimestamp.
*/
@java.lang.Override
public int getTotalFinishTimestamp() {
return totalFinishTimestamp_;
}
/**
* <code>uint32 total_finish_timestamp = 13;</code>
* @param value The totalFinishTimestamp to set.
* @return This builder for chaining.
*/
public Builder setTotalFinishTimestamp(int value) {
totalFinishTimestamp_ = value;
onChanged();
return this;
}
/**
* <code>uint32 total_finish_timestamp = 13;</code>
* @return This builder for chaining.
*/
public Builder clearTotalFinishTimestamp() {
totalFinishTimestamp_ = 0;
onChanged();
return this;
}
private int queueId_ ;
/**
* <code>uint32 queue_id = 4;</code>
* @return The queueId.
*/
@java.lang.Override
public int getQueueId() {
return queueId_;
}
/**
* <code>uint32 queue_id = 4;</code>
* @param value The queueId to set.
* @return This builder for chaining.
*/
public Builder setQueueId(int value) {
queueId_ = value;
onChanged();
return this;
}
/**
* <code>uint32 queue_id = 4;</code>
* @return This builder for chaining.
*/
public Builder clearQueueId() {
queueId_ = 0;
onChanged();
return this;
}
private int forgeId_ ; private int forgeId_ ;
/** /**
* <code>uint32 forge_id = 1;</code> * <code>uint32 forge_id = 1;</code>
@ -816,64 +816,64 @@ public final class ForgeQueueDataOuterClass {
return this; return this;
} }
private int totalFinishTimestamp_ ; private int nextFinishTimestamp_ ;
/** /**
* <code>uint32 total_finish_timestamp = 8;</code> * <code>uint32 next_finish_timestamp = 8;</code>
* @return The totalFinishTimestamp. * @return The nextFinishTimestamp.
*/ */
@java.lang.Override @java.lang.Override
public int getTotalFinishTimestamp() { public int getNextFinishTimestamp() {
return totalFinishTimestamp_; return nextFinishTimestamp_;
} }
/** /**
* <code>uint32 total_finish_timestamp = 8;</code> * <code>uint32 next_finish_timestamp = 8;</code>
* @param value The totalFinishTimestamp to set. * @param value The nextFinishTimestamp to set.
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder setTotalFinishTimestamp(int value) { public Builder setNextFinishTimestamp(int value) {
totalFinishTimestamp_ = value; nextFinishTimestamp_ = value;
onChanged(); onChanged();
return this; return this;
} }
/** /**
* <code>uint32 total_finish_timestamp = 8;</code> * <code>uint32 next_finish_timestamp = 8;</code>
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder clearTotalFinishTimestamp() { public Builder clearNextFinishTimestamp() {
totalFinishTimestamp_ = 0; nextFinishTimestamp_ = 0;
onChanged(); onChanged();
return this; return this;
} }
private int queueId_ ; private int unfinishCount_ ;
/** /**
* <code>uint32 queue_id = 9;</code> * <code>uint32 unfinish_count = 9;</code>
* @return The queueId. * @return The unfinishCount.
*/ */
@java.lang.Override @java.lang.Override
public int getQueueId() { public int getUnfinishCount() {
return queueId_; return unfinishCount_;
} }
/** /**
* <code>uint32 queue_id = 9;</code> * <code>uint32 unfinish_count = 9;</code>
* @param value The queueId to set. * @param value The unfinishCount to set.
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder setQueueId(int value) { public Builder setUnfinishCount(int value) {
queueId_ = value; unfinishCount_ = value;
onChanged(); onChanged();
return this; return this;
} }
/** /**
* <code>uint32 queue_id = 9;</code> * <code>uint32 unfinish_count = 9;</code>
* @return This builder for chaining. * @return This builder for chaining.
*/ */
public Builder clearQueueId() { public Builder clearUnfinishCount() {
queueId_ = 0; unfinishCount_ = 0;
onChanged(); onChanged();
return this; return this;
} }
@ -945,10 +945,10 @@ public final class ForgeQueueDataOuterClass {
static { static {
java.lang.String[] descriptorData = { java.lang.String[] descriptorData = {
"\n\024ForgeQueueData.proto\"\264\001\n\016ForgeQueueDat" + "\n\024ForgeQueueData.proto\"\264\001\n\016ForgeQueueDat" +
"a\022\021\n\tavatar_id\030\016 \001(\r\022\026\n\016unfinish_count\030\017" + "a\022\021\n\tavatar_id\030\016 \001(\r\022\024\n\014finish_count\030\017 \001" +
" \001(\r\022\035\n\025next_finish_timestamp\030\r \001(\r\022\024\n\014f" + "(\r\022\036\n\026total_finish_timestamp\030\r \001(\r\022\020\n\010qu" +
"inish_count\030\004 \001(\r\022\020\n\010forge_id\030\001 \001(\r\022\036\n\026t" + "eue_id\030\004 \001(\r\022\020\n\010forge_id\030\001 \001(\r\022\035\n\025next_f" +
"otal_finish_timestamp\030\010 \001(\r\022\020\n\010queue_id\030" + "inish_timestamp\030\010 \001(\r\022\026\n\016unfinish_count\030" +
"\t \001(\rB\033\n\031emu.grasscutter.net.protob\006prot" + "\t \001(\rB\033\n\031emu.grasscutter.net.protob\006prot" +
"o3" "o3"
}; };
@ -961,7 +961,7 @@ public final class ForgeQueueDataOuterClass {
internal_static_ForgeQueueData_fieldAccessorTable = new internal_static_ForgeQueueData_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_ForgeQueueData_descriptor, internal_static_ForgeQueueData_descriptor,
new java.lang.String[] { "AvatarId", "UnfinishCount", "NextFinishTimestamp", "FinishCount", "ForgeId", "TotalFinishTimestamp", "QueueId", }); new java.lang.String[] { "AvatarId", "FinishCount", "TotalFinishTimestamp", "QueueId", "ForgeId", "NextFinishTimestamp", "UnfinishCount", });
} }
// @@protoc_insertion_point(outer_class_scope) // @@protoc_insertion_point(outer_class_scope)

View File

@ -8,7 +8,7 @@ import emu.grasscutter.auth.*;
import emu.grasscutter.command.*; import emu.grasscutter.command.*;
import emu.grasscutter.config.ConfigContainer; import emu.grasscutter.config.ConfigContainer;
import emu.grasscutter.data.ResourceLoader; import emu.grasscutter.data.ResourceLoader;
import emu.grasscutter.database.DatabaseManager; import emu.grasscutter.database.*;
import emu.grasscutter.plugin.PluginManager; import emu.grasscutter.plugin.PluginManager;
import emu.grasscutter.plugin.api.ServerHelper; import emu.grasscutter.plugin.api.ServerHelper;
import emu.grasscutter.server.dispatch.DispatchServer; import emu.grasscutter.server.dispatch.DispatchServer;
@ -183,6 +183,25 @@ public final class Grasscutter {
private static void onShutdown() { private static void onShutdown() {
// Disable all plugins. // Disable all plugins.
if (pluginManager != null) pluginManager.disablePlugins(); 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.Grasscutter;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.*;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.util.*; import java.util.*;
import org.reflections.Reflections; import org.reflections.Reflections;

View File

@ -4,11 +4,9 @@ import static emu.grasscutter.utils.lang.Language.translate;
import at.favre.lib.crypto.bcrypt.BCrypt; import at.favre.lib.crypto.bcrypt.BCrypt;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.*;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.config.Configuration; import emu.grasscutter.config.Configuration;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.*;
import emu.grasscutter.database.DatabaseManager;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.util.List; import java.util.List;
@ -31,17 +29,17 @@ public final class AccountCommand implements CommandHandler {
return; return;
} }
if (args.size() < 2) {
sendUsageMessage(sender);
return;
}
String action = args.get(0); String action = args.get(0);
String username = args.get(1);
switch (action) { switch (action) {
default -> this.sendUsageMessage(sender); default -> this.sendUsageMessage(sender);
case "create" -> { case "create" -> {
if (args.size() < 2) {
this.sendUsageMessage(sender);
return;
}
var username = args.get(1);
int uid = 0; int uid = 0;
String password = ""; String password = "";
if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) { if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
@ -94,6 +92,12 @@ public final class AccountCommand implements CommandHandler {
} }
} }
case "delete" -> { case "delete" -> {
if (args.size() < 2) {
this.sendUsageMessage(sender);
return;
}
var username = args.get(1);
// Get the account we want to delete. // Get the account we want to delete.
Account toDelete = DatabaseHelper.getAccountByName(username); Account toDelete = DatabaseHelper.getAccountByName(username);
if (toDelete == null) { if (toDelete == null) {
@ -104,6 +108,12 @@ public final class AccountCommand implements CommandHandler {
CommandHandler.sendMessage(sender, translate(sender, "commands.account.delete")); CommandHandler.sendMessage(sender, translate(sender, "commands.account.delete"));
} }
case "resetpass" -> { case "resetpass" -> {
if (args.size() < 2) {
this.sendUsageMessage(sender);
return;
}
var username = args.get(1);
if (!Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) { if (!Configuration.ACCOUNT.EXPERIMENTAL_RealPassword) {
CommandHandler.sendMessage( CommandHandler.sendMessage(
sender, "resetpass requires EXPERIMENTAL_RealPassword to be true."); sender, "resetpass requires EXPERIMENTAL_RealPassword to be true.");

View File

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

View File

@ -12,7 +12,7 @@ import java.util.Map;
@Command( @Command(
label = "list", label = "list",
aliases = {"players"}, aliases = {"players"},
usage = {"[<UID>]"}, usage = {"[uid]"},
targetRequirement = Command.TargetRequirement.NONE) targetRequirement = Command.TargetRequirement.NONE)
public final class ListCommand implements CommandHandler { 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 static emu.grasscutter.utils.lang.Language.translate;
import emu.grasscutter.command.Command; import emu.grasscutter.command.*;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.GameQuest;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Command( @Command(
label = "quest", label = "quest",
aliases = {"q"}, aliases = {"q"},
usage = {"(add|finish) [<questId>]"}, usage = {"(add|finish|running|talking|debug|triggers|grouptriggers) [<questId>]", "dungeons"},
permission = "player.quest", permission = "player.quest",
permissionTargeted = "player.quest.others") permissionTargeted = "player.quest.others")
public final class QuestCommand implements CommandHandler { public final class QuestCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { 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); sendUsageMessage(sender);
return; return;
} }
@ -112,7 +112,7 @@ public final class QuestCommand implements CommandHandler {
var shouldAdd = !loggedQuests.contains(questId); var shouldAdd = !loggedQuests.contains(questId);
if (shouldAdd) loggedQuests.add(questId); if (shouldAdd) loggedQuests.add(questId);
else loggedQuests.remove(questId); else loggedQuests.remove(loggedQuests.indexOf(questId));
CommandHandler.sendMessage( CommandHandler.sendMessage(
sender, sender,
@ -131,6 +131,22 @@ public final class QuestCommand implements CommandHandler {
"Triggers registered for %s: %s." "Triggers registered for %s: %s."
.formatted(questId, String.join(", ", quest.getTriggers().keySet()))); .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); default -> this.sendUsageMessage(sender);
} }
} }

View File

@ -12,6 +12,7 @@ import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@Command( @Command(
@ -107,6 +108,7 @@ public final class SetPropCommand implements CommandHandler {
case "on", "true" -> 1; case "on", "true" -> 1;
case "off", "false" -> 0; case "off", "false" -> 0;
case "toggle" -> -1; case "toggle" -> -1;
case "all" -> -2;
default -> Integer.parseInt(valueStr); default -> Integer.parseInt(valueStr);
}; };
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
@ -126,7 +128,7 @@ public final class SetPropCommand implements CommandHandler {
sender, targetPlayer, prop.pseudoProp, value); sender, targetPlayer, prop.pseudoProp, value);
case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1); case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0); 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); default -> targetPlayer.setProperty(prop.prop, value);
}; };
@ -217,13 +219,30 @@ public final class SetPropCommand implements CommandHandler {
return true; return true;
} }
private boolean unlockMap(Player targetPlayer) { private boolean unlockMap(Player targetPlayer, int value) {
// Unlock. // Unlock.
GameData.getScenePointsPerScene() GameData.getScenePointsPerScene()
.forEach( .forEach(
(sceneId, scenePoints) -> { (sceneId, scenePoints) -> {
// Unlock trans points. if (value == -2) {
targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints); // 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. // Unlock map areas.
targetPlayer.getUnlockedSceneAreas(sceneId).addAll(sceneAreas); targetPlayer.getUnlockedSceneAreas(sceneId).addAll(sceneAreas);

View File

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

View File

@ -17,19 +17,21 @@ import static emu.grasscutter.Grasscutter.*;
public class ConfigContainer { public class ConfigContainer {
/* /*
* Configuration changes: * Configuration changes:
* Version 5 - 'questing' has been changed from a boolean * Version 5 - 'questing' has been changed from a boolean
* to a container of options ('questOptions'). * to a container of options ('questOptions').
* This field will be removed in future versions. * This field will be removed in future versions.
* Version 6 - 'questing' has been fully replaced with 'questOptions'. * Version 6 - 'questing' has been fully replaced with 'questOptions'.
* The field for 'legacyResources' has been removed. * The field for 'legacyResources' has been removed.
* Version 7 - 'regionKey' is being added for authentication * Version 7 - 'regionKey' is being added for authentication
* with the new dispatch server. * with the new dispatch server.
* Version 8 - 'server' is being added for enforcing handbook server * Version 8 - 'server' is being added for enforcing handbook server
* addresses. * addresses.
* Version 9 - 'limits' was added for handbook requests. * Version 9 - 'limits' was added for handbook requests.
* Version 10 - 'trialCostumes' was added for enabling costumes
* on trial avatars.
*/ */
private static int version() { private static int version() {
return 9; return 10;
} }
/** /**
@ -255,6 +257,8 @@ public class ConfigContainer {
public boolean staminaUsage = true; public boolean staminaUsage = true;
public boolean energyUsage = true; public boolean energyUsage = true;
public boolean fishhookTeleport = true; public boolean fishhookTeleport = true;
public boolean trialCostumes = false;
@SerializedName(value = "questing", alternate = "questOptions") @SerializedName(value = "questing", alternate = "questOptions")
public Questing questing = new Questing(); public Questing questing = new Questing();
public ResinOptions resinOptions = new ResinOptions(); 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.WorldAreaData;
import emu.grasscutter.data.excels.world.WorldLevelData; import emu.grasscutter.data.excels.world.WorldLevelData;
import emu.grasscutter.data.server.ActivityCondGroup; 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.GadgetMapping;
import emu.grasscutter.data.server.MonsterMapping; import emu.grasscutter.data.server.MonsterMapping;
import emu.grasscutter.data.server.SubfieldMapping;
import emu.grasscutter.game.dungeons.DungeonDropEntry; import emu.grasscutter.game.dungeons.DungeonDropEntry;
import emu.grasscutter.game.quest.QuestEncryptionKey; import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.game.quest.RewindData; import emu.grasscutter.game.quest.RewindData;
@ -451,6 +454,18 @@ public final class GameData {
private static final Int2ObjectMap<GadgetMapping> gadgetMappingMap = private static final Int2ObjectMap<GadgetMapping> gadgetMappingMap =
new Int2ObjectOpenHashMap<>(); 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 @Getter
private static final Int2ObjectMap<MonsterMapping> monsterMappingMap = private static final Int2ObjectMap<MonsterMapping> monsterMappingMap =
new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();

View File

@ -9,6 +9,7 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.*; import emu.grasscutter.data.binout.*;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.data.binout.config.*; import emu.grasscutter.data.binout.config.*;
import emu.grasscutter.data.binout.routes.*;
import emu.grasscutter.data.common.PointData; import emu.grasscutter.data.common.PointData;
import emu.grasscutter.data.custom.*; import emu.grasscutter.data.custom.*;
import emu.grasscutter.data.excels.trial.TrialAvatarActivityDataData; import emu.grasscutter.data.excels.trial.TrialAvatarActivityDataData;
@ -107,6 +108,7 @@ public final class ResourceLoader {
// Load default home layout // Load default home layout
loadHomeworldDefaultSaveData(); loadHomeworldDefaultSaveData();
loadNpcBornData(); loadNpcBornData();
loadRoutes();
loadBlossomResources(); loadBlossomResources();
cacheTalentLevelSets(); cacheTalentLevelSets();
// Load activities. // Load activities.
@ -116,6 +118,7 @@ public final class ResourceLoader {
loadConfigLevelEntityData(); loadConfigLevelEntityData();
loadQuestShareConfig(); loadQuestShareConfig();
loadGadgetMappings(); loadGadgetMappings();
loadSubfieldMappings();
loadMonsterMappings(); loadMonsterMappings();
loadActivityCondGroups(); loadActivityCondGroups();
loadGroupReplacements(); loadGroupReplacements();
@ -263,6 +266,32 @@ public final class ResourceLoader {
} }
} }
private static void loadRoutes() {
try {
Files.newDirectoryStream(getResourcePath("BinOutput/LevelDesign/Routes/"), "*.json")
.forEach(
path -> {
try {
val data = JsonUtils.loadToClass(path, SceneRoutes.class);
val routesArray = data.getRoutes();
if (routesArray == null) return;
val routesMap =
GameData.getSceneRouteData()
.getOrDefault(data.getSceneId(), new Int2ObjectOpenHashMap<>());
for (Route route : routesArray) {
routesMap.put(route.getLocalId(), route);
}
GameData.getSceneRouteData().put(data.getSceneId(), routesMap);
} catch (IOException ignored) {
}
});
Grasscutter.getLogger()
.debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneRouteDatas.");
} catch (IOException e) {
Grasscutter.getLogger().error("Failed to load SceneRouteData folder.");
}
}
private static void cacheTalentLevelSets() { private static void cacheTalentLevelSets() {
// All known levels, keyed by proudSkillGroupId // All known levels, keyed by proudSkillGroupId
GameData.getProudSkillDataMap() GameData.getProudSkillDataMap()
@ -805,6 +834,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() { private static void loadMonsterMappings() {
try { try {
var monsterMap = GameData.getMonsterMappingMap(); var monsterMap = GameData.getMonsterMappingMap();

View File

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

View File

@ -323,9 +323,28 @@ public class AbilityModifier implements Serializable {
public int skillID; 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 param1;
public int param2; public int param2;
public int param3; public int param3;
public enum DropType {
LevelControl,
BigWorldOnly,
ForceDrop
}
} }
// The following should be implemented into DynamicFloat if older resource formats need to be // The following should be implemented into DynamicFloat if older resource formats need to be

View File

@ -11,38 +11,58 @@ import lombok.experimental.FieldDefaults;
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class HomeworldDefaultSaveData { public class HomeworldDefaultSaveData {
@SerializedName(value = "KFHBFNPDJBE", alternate = "PKACPHDGGEI") @SerializedName(
value = "KFHBFNPDJBE",
alternate = {"PKACPHDGGEI", "AKOLOBLHDFK"})
List<HomeBlock> homeBlockLists; List<HomeBlock> homeBlockLists;
@SerializedName(value = "IJNPADKGNKE", alternate = "MINCKHBNING") @SerializedName(
value = "IJNPADKGNKE",
alternate = {"MINCKHBNING", "MBICDPDEKDM"})
Position bornPos; Position bornPos;
@SerializedName("IPIIGEMFLHK") @SerializedName(
value = "IPIIGEMFLHK",
alternate = {"EJJIOJKFKCO"})
Position bornRot; Position bornRot;
@SerializedName("HHOLBNPIHEM") @SerializedName(
value = "HHOLBNPIHEM",
alternate = {"CJAKHCIFHNP"})
Position djinPos; Position djinPos;
@SerializedName("KNHCJKHCOAN") @SerializedName(
value = "KNHCJKHCOAN",
alternate = {"AMDNOHPGKMI"})
HomeFurniture mainhouse; HomeFurniture mainhouse;
@SerializedName("NIHOJFEKFPG") @SerializedName(
value = "NIHOJFEKFPG",
alternate = {"BHCPEAOPIDC"})
List<HomeFurniture> doorLists; List<HomeFurniture> doorLists;
@SerializedName("EPGELGEFJFK") @SerializedName(
value = "EPGELGEFJFK",
alternate = {"AABEPENIFLN"})
List<HomeFurniture> stairLists; List<HomeFurniture> stairLists;
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public static class HomeBlock { public static class HomeBlock {
@SerializedName(value = "FGIJCELCGFI", alternate = "PGDPDIDJEEL") @SerializedName(
value = "FGIJCELCGFI",
alternate = {"PGDPDIDJEEL", "ANICBLBOBKD"})
int blockId; int blockId;
@SerializedName("BEAPOFELABD") @SerializedName(
value = "BEAPOFELABD",
alternate = {"NCIMIKKFLOH"})
List<HomeFurniture> furnitures; List<HomeFurniture> furnitures;
@SerializedName("MLIODLGDFHJ") @SerializedName(
value = "MLIODLGDFHJ",
alternate = {"GJGNLIINBGB"})
List<HomeFurniture> persistentFurnitures; List<HomeFurniture> persistentFurnitures;
} }
@ -50,10 +70,14 @@ public class HomeworldDefaultSaveData {
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public static class HomeFurniture { public static class HomeFurniture {
@SerializedName(value = "ENHNGKJBJAB", alternate = "KMAAJJHPNBA") @SerializedName(
value = "ENHNGKJBJAB",
alternate = {"KMAAJJHPNBA", "FFLCGFGGGND"})
int id; int id;
@SerializedName(value = "NGIEEIOLPPO", alternate = "JFKAHNCPDME") @SerializedName(
value = "NGIEEIOLPPO",
alternate = {"JFKAHNCPDME", "BPCGGBKIAMG"})
Position pos; Position pos;
// @SerializedName(value = "HEOCEHKEBFM", alternate = "LKCKOOGFDBM") // @SerializedName(value = "HEOCEHKEBFM", alternate = "LKCKOOGFDBM")
Position rot; Position rot;

View File

@ -11,4 +11,6 @@ public class ConfigLevelEntity {
@Getter private List<ConfigAbilityData> avatarAbilities; @Getter private List<ConfigAbilityData> avatarAbilities;
@Getter private List<ConfigAbilityData> teamAbilities; @Getter private List<ConfigAbilityData> teamAbilities;
@Getter private List<Integer> preloadMonsterEntityIDs; @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 pos;
@Getter private Position rot; @Getter private Position rot;
@Getter private Position size; @Getter private Position size;
@Getter private boolean forbidSimpleUnlock;
@Getter private boolean unlocked;
@SerializedName( @SerializedName(
value = "dungeonIds", value = "dungeonIds",

View File

@ -89,7 +89,14 @@ public class ItemData extends GameResource {
@SerializedName( @SerializedName(
value = "roomSceneId", value = "roomSceneId",
alternate = {"BMEPAMCNABE", "DANFGGLKLNO", "JFDLJGDFIGL", "OHIANNAEEAK", "MFGACDIOHGF"}) alternate = {
"BMEPAMCNABE",
"DANFGGLKLNO",
"JFDLJGDFIGL",
"OHIANNAEEAK",
"MFGACDIOHGF",
"roomSceneID"
})
private int roomSceneId; private int roomSceneId;
// Custom // Custom

View File

@ -1,12 +1,10 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.*;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.talk.TalkExec; import emu.grasscutter.game.talk.TalkExec;
import java.util.List; import java.util.List;
import lombok.Data; import lombok.*;
import lombok.EqualsAndHashCode;
@ResourceType(name = "TalkExcelConfigData.json") @ResourceType(name = "TalkExcelConfigData.json")
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@ -38,6 +36,11 @@ public final class TalkConfigData extends GameResource {
this.finishExec == null this.finishExec == null
? List.of() ? List.of()
: this.finishExec.stream().filter(x -> x.getType() != null).toList(); : 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, id.length() - 2));
}
} }
@Data @Data

View File

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

View File

@ -6,12 +6,13 @@ import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.quest.enums.LogicType; import emu.grasscutter.game.quest.enums.LogicType;
import java.util.List; import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
@ResourceType(name = "DungeonPassExcelConfigData.json") @ResourceType(name = "DungeonPassExcelConfigData.json")
public class DungeonPassConfigData extends GameResource { public class DungeonPassConfigData extends GameResource {
@Getter private int id; @Getter private int id;
@Getter private LogicType logicType; @Getter private LogicType logicType;
@Getter private List<DungeonPassCondition> conds; @Getter @Setter private List<DungeonPassCondition> conds;
public static class DungeonPassCondition { public static class DungeonPassCondition {
@Getter private DungeonPassConditionType condType; @Getter private DungeonPassConditionType condType;

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

View File

@ -30,30 +30,50 @@ public class AbilityLocalIdGenerator {
} }
public void initializeActionLocalIds( public void initializeActionLocalIds(
AbilityModifierAction[] actions, Map<Integer, AbilityModifierAction> localIdToAction) { AbilityModifierAction actions[], Map<Integer, AbilityModifierAction> localIdToAction) {
this.initializeActionLocalIds(actions, localIdToAction, false);
}
public void initializeActionLocalIds(
AbilityModifierAction[] actions,
Map<Integer, AbilityModifierAction> localIdToAction,
boolean preserveActionIndex) {
if (actions == null) return; if (actions == null) return;
actionIndex = 0; if (!preserveActionIndex) this.actionIndex = 0;
for (AbilityModifierAction action : actions) { for (int i = 0; i < actions.length; i++) {
actionIndex++; this.actionIndex++;
long id = GetLocalId();
localIdToAction.put((int) id, action); 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);
}
} }
actionIndex = 0; if (!preserveActionIndex) actionIndex = 0;
} }
public void initializeMixinsLocalIds( public void initializeMixinsLocalIds(
AbilityMixinData[] mixins, Map<Integer, AbilityMixinData> localIdToAction) { AbilityMixinData[] mixins, Map<Integer, AbilityMixinData> localIdToAction) {
if (mixins == null) return; if (mixins == null) return;
mixinIndex = 0; this.mixinIndex = 0;
for (AbilityMixinData mixin : mixins) { for (var mixin : mixins) {
long id = GetLocalId(); var id = GetLocalId();
localIdToAction.put((int) id, mixin); localIdToAction.put((int) id, mixin);
mixinIndex++; this.mixinIndex++;
} }
mixinIndex = 0; this.mixinIndex = 0;
} }
public long GetLocalId() { 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.ability.mixins.*;
import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.*; import emu.grasscutter.game.player.*;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
import emu.grasscutter.net.proto.AbilityMetaAddAbilityOuterClass.AbilityMetaAddAbility; import emu.grasscutter.net.proto.AbilityMetaAddAbilityOuterClass.AbilityMetaAddAbility;
import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange; import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange;
import emu.grasscutter.net.proto.AbilityMetaReInitOverrideMapOuterClass.AbilityMetaReInitOverrideMap; 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.AbilityScalarTypeOuterClass.AbilityScalarType;
import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry; import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry;
import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction; 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 case ABILITY_INVOKE_ARGUMENT_META_MODIFIER_DURABILITY_CHANGE -> this
.handleModifierDurabilityChange(invoke); .handleModifierDurabilityChange(invoke);
case ABILITY_INVOKE_ARGUMENT_META_ADD_NEW_ABILITY -> this.handleAddNewAbility(invoke); case ABILITY_INVOKE_ARGUMENT_META_ADD_NEW_ABILITY -> this.handleAddNewAbility(invoke);
case ABILITY_INVOKE_ARGUMENT_META_SET_KILLED_SETATE -> this.handleKillState(invoke);
default -> {} default -> {}
} }
} }
@ -535,6 +538,25 @@ public final class AbilityManager extends BasePlayerManager {
entity.getInstancedAbilities().size()); 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) { public void addAbilityToEntity(GameEntity entity, String name) {
AbilityData data = GameData.getAbilityData(name); AbilityData data = GameData.getAbilityData(name);
if (data != null) addAbilityToEntity(entity, data); if (data != null) addAbilityToEntity(entity, data);

View File

@ -3,7 +3,7 @@ package emu.grasscutter.game.ability.actions;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.game.ability.Ability; import emu.grasscutter.game.ability.Ability;
import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.*;
@AbilityAction(AbilityModifierAction.Type.ExecuteGadgetLua) @AbilityAction(AbilityModifierAction.Type.ExecuteGadgetLua)
public class ActionExecuteGadgetLua extends AbilityActionHandler { 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; package emu.grasscutter.game.ability.actions;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.game.ability.Ability; import emu.grasscutter.game.ability.Ability;
import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.GameEntity;
@ -10,9 +11,14 @@ public final class ActionKillSelf extends AbilityActionHandler {
@Override @Override
public boolean execute( public boolean execute(
Ability ability, AbilityModifierAction action, ByteString abilityData, GameEntity target) { Ability ability, AbilityModifierAction action, ByteString abilityData, GameEntity target) {
GameEntity owner = ability.getOwner(); // KillSelf should not have a target field, so target it's the actual entity to be applied.
owner.getScene().killEntity(owner); // 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; return true;
} }
} }

View File

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

@ -15,7 +15,7 @@ public class UnknownActivityConditionHandler extends ActivityConditionBaseHandle
@Override @Override
public boolean execute( public boolean execute(
PlayerActivityData activityData, ActivityConfigItem activityConfig, int... params) { PlayerActivityData activityData, ActivityConfigItem activityConfig, int... params) {
Grasscutter.getLogger().error("Called unknown condition handler {}.", conditions.name()); Grasscutter.getLogger().debug("Called unknown condition handler {}.", conditions.name());
return false; return false;
} }
} }

View File

@ -1243,13 +1243,15 @@ public class Avatar {
}); });
// Add costume if avatar has a costume. // Add costume if avatar has a costume.
GameData.getAvatarCostumeDataItemIdMap() if (GAME_OPTIONS.trialCostumes) {
.values() GameData.getAvatarCostumeDataItemIdMap()
.forEach( .values()
costumeData -> { .forEach(
if (costumeData.getCharacterId() != this.getAvatarId()) return; costumeData -> {
this.setCostume(costumeData.getId()); if (costumeData.getCharacterId() != this.getAvatarId()) return;
}); this.setCostume(costumeData.getId());
});
}
} }
/** Equips the items applied from {@link Avatar#applyTrialItems()}. */ /** Equips the items applied from {@link Avatar#applyTrialItems()}. */

View File

@ -80,6 +80,14 @@ public final class DropSystem extends BaseGameSystem {
return dropData.getDropId(); 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) { public boolean handleMonsterDrop(EntityMonster monster) {
int dropId; int dropId;
int level = monster.getLevel(); int level = monster.getLevel();

View File

@ -53,8 +53,13 @@ public final class DungeonManager {
public DungeonManager(@NonNull Scene scene, @NonNull DungeonData dungeonData) { public DungeonManager(@NonNull Scene scene, @NonNull DungeonData dungeonData) {
this.scene = scene; this.scene = scene;
this.dungeonData = dungeonData; this.dungeonData = dungeonData;
this.passConfigData = GameData.getDungeonPassConfigDataMap().get(dungeonData.getPassCond()); if (dungeonData.getPassCond() == 0) {
this.finishedConditions = new int[passConfigData.getConds().size()]; this.passConfigData = new DungeonPassConfigData();
this.passConfigData.setConds(new ArrayList<>());
} else {
this.passConfigData = GameData.getDungeonPassConfigDataMap().get(dungeonData.getPassCond());
}
this.finishedConditions = new int[this.passConfigData.getConds().size()];
} }
public void triggerEvent(DungeonPassConditionType conditionType, int... params) { public void triggerEvent(DungeonPassConditionType conditionType, int... params) {
@ -76,6 +81,7 @@ public final class DungeonManager {
} }
public boolean isFinishedSuccessfully() { public boolean isFinishedSuccessfully() {
if (passConfigData.getLogicType() == null) return false;
return LogicType.calculate(passConfigData.getLogicType(), finishedConditions); return LogicType.calculate(passConfigData.getLogicType(), finishedConditions);
} }
@ -134,7 +140,16 @@ public final class DungeonManager {
} }
// Get and roll rewards. // 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. // Add rewards to player and send notification.
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop); player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards)); player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
@ -187,7 +202,7 @@ public final class DungeonManager {
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities()); 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) { if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
amount *= 2; amount *= 2;
} }

View File

@ -70,7 +70,7 @@ public abstract class EntityBaseGadget extends GameEntity {
getGadgetId()) getGadgetId())
.setSourceEntityId(getId()) .setSourceEntityId(getId())
.setParam3((int) this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP)) .setParam3((int) this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP))
.setEventSource(Integer.toString(getConfigId()))); .setEventSource(getConfigId()));
} }
protected void fillFightProps(ConfigEntityGadget configGadget) { protected void fillFightProps(ConfigEntityGadget configGadget) {

View File

@ -7,12 +7,11 @@ import emu.grasscutter.data.binout.config.fields.ConfigAbilityData;
import emu.grasscutter.data.excels.GadgetData; import emu.grasscutter.data.excels.GadgetData;
import emu.grasscutter.game.entity.gadget.*; import emu.grasscutter.game.entity.gadget.*;
import emu.grasscutter.game.entity.gadget.platform.BaseRoute; import emu.grasscutter.game.entity.gadget.platform.BaseRoute;
import emu.grasscutter.game.entity.gadget.platform.ConfigRoute;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.*;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.world.*;
import emu.grasscutter.game.world.Position; import emu.grasscutter.net.proto.*;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.SceneGroupInstance;
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
@ -20,31 +19,21 @@ import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; 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.PropPairOuterClass.PropPair;
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.net.proto.VectorOuterClass.Vector; import emu.grasscutter.net.proto.VectorOuterClass.Vector;
import emu.grasscutter.net.proto.VisionTypeOuterClass;
import emu.grasscutter.scripts.EntityControllerScriptManager; import emu.grasscutter.scripts.EntityControllerScriptManager;
import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.*;
import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.server.packet.send.*;
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.utils.helpers.ProtoHelper; import emu.grasscutter.utils.helpers.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatMap; import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import java.util.*;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import lombok.Getter; import lombok.*;
import lombok.Setter;
import lombok.ToString;
@ToString(callSuper = true) @ToString(callSuper = true)
public class EntityGadget extends EntityBaseGadget { public class EntityGadget extends EntityBaseGadget {
@ -258,6 +247,62 @@ public class EntityGadget extends EntityBaseGadget {
if (routeConfig.isStarted()) { if (routeConfig.isStarted()) {
return true; return true;
} }
if (routeConfig instanceof ConfigRoute configRoute) {
var route = this.getScene().getSceneRouteById(configRoute.getRouteId());
if (route != null) {
var points = route.getPoints();
val currIndex = configRoute.getStartIndex();
Position prevpos;
if (currIndex == 0) {
prevpos = getPosition();
this.getScene()
.getScriptManager()
.callEvent(
new ScriptArgs(
this.getGroupId(),
EventType.EVENT_PLATFORM_REACH_POINT,
this.getConfigId(),
configRoute.getRouteId())
.setParam3(0)
.setEventSource(this.getConfigId()));
} else {
prevpos = points[currIndex].getPos();
}
double time = 0;
for (var i = currIndex; i < points.length; ++i) {
time += points[i].getPos().computeDistance(prevpos) / points[i].getTargetVelocity();
prevpos = points[i].getPos();
val I = i;
configRoute
.getScheduledIndexes()
.add(
this.getScene()
.getScheduler()
.scheduleDelayedTask(
() -> {
if (points[I].isHasReachEvent() && I > currIndex) {
this.getScene()
.getScriptManager()
.callEvent(
new ScriptArgs(
this.getGroupId(),
EventType.EVENT_PLATFORM_REACH_POINT,
this.getConfigId(),
configRoute.getRouteId())
.setParam3(I)
.setEventSource(this.getConfigId()));
}
configRoute.setStartIndex(I);
this.position.set(points[I].getPos());
},
(int) time));
}
}
}
getScene().broadcastPacket(new PacketSceneTimeNotify(getScene())); getScene().broadcastPacket(new PacketSceneTimeNotify(getScene()));
routeConfig.startRoute(getScene()); routeConfig.startRoute(getScene());
getScene().broadcastPacket(new PacketPlatformStartRouteNotify(this)); getScene().broadcastPacket(new PacketPlatformStartRouteNotify(this));
@ -273,6 +318,14 @@ public class EntityGadget extends EntityBaseGadget {
if (!routeConfig.isStarted()) { if (!routeConfig.isStarted()) {
return true; return true;
} }
if (routeConfig instanceof ConfigRoute configRoute) {
for (var task : configRoute.getScheduledIndexes()) {
this.getScene().getScheduler().cancelTask(task);
}
configRoute.getScheduledIndexes().clear();
}
routeConfig.stopRoute(getScene()); routeConfig.stopRoute(getScene());
getScene().broadcastPacket(new PacketPlatformStopRouteNotify(this)); getScene().broadcastPacket(new PacketPlatformStopRouteNotify(this));

View File

@ -37,14 +37,30 @@ public class EntityItem extends EntityBaseGadget {
this(scene, player, itemData, pos, count, true); 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 // In official game, some drop items are shared to all players, and some other items are
// independent to all players // independent to all players
// For example, if you killed a monster in MP mode, all players could get drops but rarity and // For example, if you killed a monster in MP mode, all players could get drops but rarity and
// number of them are different // number of them are different
// but if you broke regional mine, when someone picked up the drop then it disappeared // but if you broke regional mine, when someone picked up the drop then it disappeared
public EntityItem( public EntityItem(
Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) { Scene scene,
super(scene, pos, null); Player player,
ItemData itemData,
Position pos,
Position rotation,
int count,
boolean share) {
super(scene, pos, rotation);
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
this.guid = this.guid =
player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid(); 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(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) { for(var affixId : affixes) {
var affix = GameData.getMonsterAffixDataMap().get(affixId.intValue()); var affix = GameData.getMonsterAffixDataMap().get(affixId.intValue());
if (!affix.isPreAdd()) continue; if (!affix.isPreAdd()) continue;
@ -229,7 +235,7 @@ public class EntityMonster extends GameEntity {
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EVENT_SPECIFIC_MONSTER_HP_CHANGE, getConfigId(), monsterData.getId()) getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EVENT_SPECIFIC_MONSTER_HP_CHANGE, getConfigId(), monsterData.getId())
.setSourceEntityId(getId()) .setSourceEntityId(getId())
.setParam3((int) this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP)) .setParam3((int) this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP))
.setEventSource(Integer.toString(getConfigId()))); .setEventSource(getConfigId()));
} }
@Override @Override

View File

@ -1,5 +1,6 @@
package emu.grasscutter.game.entity; package emu.grasscutter.game.entity;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.ability.*; import emu.grasscutter.game.ability.*;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.*; import emu.grasscutter.game.props.*;
@ -51,8 +52,8 @@ public abstract class GameEntity {
public abstract void initAbilities(); public abstract void initAbilities();
public int getEntityType() { public EntityType getEntityType() {
return this.getId() >> 24; return EntityIdType.toEntityType(this.getId() >> 24);
} }
public abstract int getEntityTypeId(); public abstract int getEntityTypeId();
@ -226,6 +227,82 @@ public abstract class GameEntity {
public void onRemoved() {} 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) { public void onTick(int sceneTime) {
if (entityController != null) { if (entityController != null) {
entityController.onTimer(this, sceneTime); entityController.onTimer(this, sceneTime);

View File

@ -75,6 +75,7 @@ public class GadgetChest extends GadgetContent {
} else if (chest.chest_drop_id != 0) { } else if (chest.chest_drop_id != 0) {
status = dropSystem.handleChestDrop(chest.chest_drop_id, chest.drop_count, getGadget()); status = dropSystem.handleChestDrop(chest.chest_drop_id, chest.drop_count, getGadget());
} }
if (status) { if (status) {
getGadget().updateState(ScriptGadgetState.ChestOpened); getGadget().updateState(ScriptGadgetState.ChestOpened);
player.sendPacket( 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.GatherGadgetInfoOuterClass.GatherGadgetInfo;
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; 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.server.packet.send.PacketGadgetInteractRsp;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
@ -57,6 +59,13 @@ public final class GadgetGatherObject extends GadgetContent {
GameItem item = new GameItem(itemData, 1); GameItem item = new GameItem(itemData, 1);
player.getInventory().addItem(item, ActionReason.Gather); player.getInventory().addItem(item, ActionReason.Gather);
var ScriptArgs =
new ScriptArgs(getGadget().getGroupId(), EventType.EVENT_GATHER, getGadget().getConfigId());
if (getGadget().getMetaGadget() != null) {
ScriptArgs.setEventSource(getGadget().getMetaGadget().config_id);
}
getGadget().getScene().getScriptManager().callEvent(ScriptArgs);
getGadget() getGadget()
.getScene() .getScene()
.broadcastPacket( .broadcastPacket(

View File

@ -1,18 +1,54 @@
package emu.grasscutter.game.entity.gadget; package emu.grasscutter.game.entity.gadget;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.GatherData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass; import emu.grasscutter.net.proto.GadgetInteractReqOuterClass;
import emu.grasscutter.net.proto.InteractTypeOuterClass;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass; import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
public class GadgetObject extends GadgetContent { public class GadgetObject extends GadgetContent {
private int itemId;
public GadgetObject(EntityGadget gadget) { public GadgetObject(EntityGadget gadget) {
super(gadget); super(gadget);
GatherData gatherData = GameData.getGatherDataMap().get(gadget.getPointType());
if (gatherData != null) {
this.itemId = gatherData.getItemId();
}
} }
@Override @Override
public boolean onInteract(Player player, GadgetInteractReqOuterClass.GadgetInteractReq req) { public boolean onInteract(Player player, GadgetInteractReqOuterClass.GadgetInteractReq req) {
return false; // This is a workaround until a proper gadget interaction system can be put in place.
ItemData itemData = GameData.getItemDataMap().get(this.itemId);
if (itemData == null) {
return false;
}
GameItem item = new GameItem(itemData, 1);
player.getInventory().addItem(item, ActionReason.Gather);
var ScriptArgs =
new ScriptArgs(getGadget().getGroupId(), EventType.EVENT_GATHER, getGadget().getConfigId());
if (getGadget().getMetaGadget() != null) {
ScriptArgs.setEventSource(getGadget().getMetaGadget().config_id);
}
getGadget().getScene().getScriptManager().callEvent(ScriptArgs);
getGadget()
.getScene()
.broadcastPacket(
new PacketGadgetInteractRsp(
getGadget(), InteractTypeOuterClass.InteractType.INTERACT_TYPE_GATHER));
return true;
} }
@Override @Override

View File

@ -4,27 +4,36 @@ import emu.grasscutter.game.world.Position;
import emu.grasscutter.net.proto.MovingPlatformTypeOuterClass; import emu.grasscutter.net.proto.MovingPlatformTypeOuterClass;
import emu.grasscutter.net.proto.PlatformInfoOuterClass; import emu.grasscutter.net.proto.PlatformInfoOuterClass;
import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.SceneGadget;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
public class ConfigRoute extends BaseRoute { public class ConfigRoute extends BaseRoute {
@Getter @Setter private int routeId; @Getter @Setter private int routeId;
@Getter @Setter private int startIndex;
@Getter @Setter private List<Integer> scheduledIndexes;
public ConfigRoute(SceneGadget gadget) { public ConfigRoute(SceneGadget gadget) {
super(gadget); super(gadget);
this.routeId = gadget.route_id; this.routeId = gadget.route_id;
this.startIndex = 0;
this.scheduledIndexes = new ArrayList<>();
} }
public ConfigRoute(Position startRot, boolean startRoute, boolean isActive, int routeId) { public ConfigRoute(Position startRot, boolean startRoute, boolean isActive, int routeId) {
super(startRot, startRoute, isActive); super(startRot, startRoute, isActive);
this.routeId = routeId; this.routeId = routeId;
this.startIndex = 0;
this.scheduledIndexes = new ArrayList<>();
} }
@Override @Override
public PlatformInfoOuterClass.PlatformInfo.Builder toProto() { public PlatformInfoOuterClass.PlatformInfo.Builder toProto() {
return super.toProto() return super.toProto()
.setRouteId(routeId) .setRouteId(this.routeId)
.setStartIndex(this.startIndex)
.setMovingPlatformType( .setMovingPlatformType(
MovingPlatformTypeOuterClass.MovingPlatformType.MOVING_PLATFORM_TYPE_USE_CONFIG); MovingPlatformTypeOuterClass.MovingPlatformType.MOVING_PLATFORM_TYPE_USE_CONFIG);
} }

View File

@ -133,13 +133,9 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
for (var item : items) { for (var item : items) {
if (item.getItemId() == 0) continue; if (item.getItemId() == 0) continue;
GameItem result = null; GameItem result = null;
try {
// putItem might throw exception result = putItem(item);
// ignore that exception and continue
result = putItem(item);
} catch (Exception e) {
e.printStackTrace();
}
if (result != null) { if (result != null) {
this.triggerAddItemEvents(result); this.triggerAddItemEvents(result);
changedItems.add(result); changedItems.add(result);
@ -155,22 +151,33 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
} }
private void triggerAddItemEvents(GameItem result) { private void triggerAddItemEvents(GameItem result) {
getPlayer() try {
.getBattlePassManager() getPlayer()
.triggerMission( .getBattlePassManager()
WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount()); .triggerMission(
getPlayer() WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM,
.getQuestManager() result.getItemId(),
.queueEvent(QuestContent.QUEST_CONTENT_OBTAIN_ITEM, result.getItemId(), result.getCount()); result.getCount());
getPlayer()
.getQuestManager()
.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) { private void triggerRemItemEvents(GameItem item, int removeCount) {
getPlayer() try {
.getBattlePassManager() getPlayer()
.triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, item.getItemId(), removeCount); .getBattlePassManager()
getPlayer() .triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, item.getItemId(), removeCount);
.getQuestManager() getPlayer()
.queueEvent(QuestContent.QUEST_CONTENT_ITEM_LESS_THAN, item.getItemId(), item.getCount()); .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) { 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. // Dont add items that dont have a valid item definition.
var data = item.getItemData(); var data = item.getItemData();
if (data == null) return null; if (data == null) return null;
try {
this.player.getProgressManager().addItemObtainedHistory(item.getItemId(), item.getCount()); this.player.getProgressManager().addItemObtainedHistory(item.getItemId(), item.getCount());
} catch (Exception e) {
Grasscutter.getLogger().debug("addItemObtainedHistory failed", e);
}
if (data.isUseOnGain()) { if (data.isUseOnGain()) {
var params = new UseItemParams(this.player, data.getUseTarget()); 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 PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
entity.getWorld().broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD)); entity.getWorld().broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD));
player.getScene().removeEntity(entity); player.getScene().removeEntity(entity);
((EntityAvatar) entity).onDeath(dieType, 0);
if (entity instanceof EntityAvatar avatar)
avatar.onDeath(dieType, 0);
} }
public void startSustainedStaminaHandler() { public void startSustainedStaminaHandler() {

View File

@ -345,16 +345,11 @@ public class Player implements PlayerHook, FieldFetch {
this.playerGameTime = gameTime; this.playerGameTime = gameTime;
// If the player is the host of the world, update the game time as well. // If the player is the host of the world, update the game time as well.
if (this.getWorld().getHost() == this) { var world = this.getWorld();
this.getWorld().changeTime(gameTime); 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(); this.save();
} }
@ -707,14 +702,16 @@ public class Player implements PlayerHook, FieldFetch {
} }
public void onEnterRegion(SceneRegion region) { public void onEnterRegion(SceneRegion region) {
var enterRegionName = "ENTER_REGION_" + region.config_id;
this.getQuestManager().forEachActiveQuest(quest -> { this.getQuestManager().forEachActiveQuest(quest -> {
if (quest.getTriggerData() != null && 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 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.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE, 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) { public void onLeaveRegion(SceneRegion region) {
var leaveRegionName = "LEAVE_REGION_" + region.config_id;
this.getQuestManager().forEachActiveQuest(quest -> { 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 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.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE, this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE,
quest.getTriggerData().get("LEAVE_REGION_" + region.config_id).getId(), 0); quest.getTriggerData().get(leaveRegionName).getId(), 0);
} }
} }
}); });
@ -1537,6 +1536,12 @@ public class Player implements PlayerHook, FieldFetch {
} }
} }
@Override
public boolean equals(Object obj) {
return obj instanceof Player otherPlayer &&
this.id == otherPlayer.getUid();
}
public enum SceneLoadState { public enum SceneLoadState {
NONE(0), LOADING(1), INIT(2), LOADED(3); NONE(0), LOADING(1), INIT(2), LOADED(3);
@ -1547,5 +1552,4 @@ public class Player implements PlayerHook, FieldFetch {
this.value = value; this.value = value;
} }
} }
} }

View File

@ -4,10 +4,10 @@ import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Transient; import dev.morphia.annotations.Transient;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.quest.enums.QuestContent; 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.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; 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 // 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 // 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 // it will be hard to loop and compare
private Map<Integer, Integer> questProgressCountMap; private Map<String, Integer> questProgressCountMap;
public PlayerProgress() { public PlayerProgress() {
this.questProgressCountMap = new Int2IntOpenHashMap(); this.questProgressCountMap = new ConcurrentHashMap<>();
this.completedDungeons = new IntArrayList(); this.completedDungeons = new IntArrayList();
this.itemHistory = new Int2ObjectOpenHashMap<>(); this.itemHistory = new Int2ObjectOpenHashMap<>();
} }
@ -70,15 +70,15 @@ public class PlayerProgress {
return itemEntry.addToObtainedCount(count); return itemEntry.addToObtainedCount(count);
} }
public int getCurrentProgress(int progressId) { public int getCurrentProgress(String progressId) {
return questProgressCountMap.getOrDefault(progressId, -1); 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); return questProgressCountMap.merge(progressId, count, Integer::sum);
} }
public int resetCurrentProgress(int progressId) { public int resetCurrentProgress(String progressId) {
return questProgressCountMap.merge(progressId, 0, Integer::min); return questProgressCountMap.merge(progressId, 0, Integer::min);
} }

View File

@ -300,7 +300,7 @@ public final class PlayerProgressManager extends BasePlayerDataManager {
/** Quest progress */ /** Quest progress */
public void addQuestProgress(int id, int count) { 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.save();
player player
.getQuestManager() .getQuestManager()

View File

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

View File

@ -1,5 +1,8 @@
package emu.grasscutter.game.props; package emu.grasscutter.game.props;
import java.util.HashMap;
import java.util.Map;
public enum EntityIdType { public enum EntityIdType {
AVATAR(0x01), AVATAR(0x01),
MONSTER(0x02), MONSTER(0x02),
@ -12,10 +15,27 @@ public enum EntityIdType {
private final int id; 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) { EntityIdType(int id) {
this.id = id; this.id = id;
} }
public static EntityType toEntityType(int entityId) {
return map.getOrDefault(entityId, EntityType.None);
}
public int getId() { public int getId() {
return id; return id;
} }

View File

@ -75,6 +75,7 @@ public enum EntityType implements IntValueEnum {
Screen(64), Screen(64),
EchoShell(65), EchoShell(65),
UIInteractGadget(66), UIInteractGadget(66),
Region(98),
PlaceHolder(99); PlaceHolder(99);
private static final Int2ObjectMap<EntityType> map = new Int2ObjectOpenHashMap<>(); 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 0, new Position(avatarPosPos.get(0), avatarPosPos.get(1), avatarPosPos.get(2))); // position
posAndRot.add( posAndRot.add(
1, new Position(avatarPosRot.get(0), avatarPosRot.get(1), avatarPosRot.get(2))); // rotation 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; return true;
} }

View File

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

View File

@ -111,7 +111,9 @@ public class QuestManager extends BasePlayerManager {
30700, // Quest which is responsible for unlocking Crash Course. 30700, // Quest which is responsible for unlocking Crash Course.
30800, // Quest which is responsible for unlocking Sparks Amongst the Pages. 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( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
val progressId = condition.getParam()[0]; 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 // if the condition count is 0 I think it is safe to assume that the
// condition count from EXEC only needs to be 1 // 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 static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_TALK;
import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.*;
import emu.grasscutter.game.quest.QuestValueContent;
import lombok.val; import lombok.val;
@QuestValueContent(QUEST_CONTENT_COMPLETE_TALK) @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 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.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.*;
import emu.grasscutter.game.quest.QuestValueContent;
@QuestValueContent(QUEST_CONTENT_FINISH_PLOT) @QuestValueContent(QUEST_CONTENT_FINISH_PLOT)
public class ContentFinishPlot extends BaseContent { public class ContentFinishPlot extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
MainQuestData.TalkData talkData = var talkData = quest.getMainQuest().getTalks().get(params[0]);
quest.getMainQuest().getTalks().get(Integer.valueOf(params[0])); var subQuest = quest.getMainQuest().getChildQuestById(params[0]);
GameQuest subQuest = quest.getMainQuest().getChildQuestById(params[0]);
return (talkData != null && subQuest != null || condition.getParamStr().equals(paramStr)) return (talkData != null && subQuest != null || condition.getParamStr().equals(paramStr))
&& condition.getParam()[0] == params[0]; && condition.getParam()[0] == params[0];
} }

View File

@ -12,6 +12,6 @@ public class ContentLeaveScene extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
return quest.getOwner().getScene().getPrevScene() == params[0]; return condition.getParam()[0] == params[0];
} }
} }

View File

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

View File

@ -13,9 +13,11 @@ public class ContentQuestStateEqual extends BaseContent {
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
GameQuest checkQuest = quest.getOwner().getQuestManager().getQuestById(condition.getParam()[0]); GameQuest checkQuest = quest.getOwner().getQuestManager().getQuestById(condition.getParam()[0]);
if (checkQuest == null) { if (checkQuest == null) {
return false; return false;
} }
return checkQuest.getState().getValue() == params[1];
return checkQuest.getState().getValue() == condition.getParam()[1];
} }
} }

View File

@ -12,12 +12,12 @@ public class ContentQuestStateNotEqual extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
GameQuest checkQuest = quest.getOwner().getQuestManager().getQuestById(params[0]); GameQuest checkQuest = quest.getOwner().getQuestManager().getQuestById(condition.getParam()[0]);
if (checkQuest != null) { if (checkQuest == null) {
return checkQuest.getState().getValue() != params[1]; return false;
} }
return false; return checkQuest.getState().getValue() != condition.getParam()[1];
} }
} }

View File

@ -13,8 +13,8 @@ public class ContentQuestVarEqual extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
int questVarValue = quest.getMainQuest().getQuestVars()[params[0]]; int questVarValue = quest.getMainQuest().getQuestVars()[condition.getParam()[0]];
Grasscutter.getLogger().debug("questVar {} : {}", params[0], questVarValue); Grasscutter.getLogger().debug("questVar {} : {}", condition.getParam()[0], questVarValue);
return questVarValue == params[1]; return questVarValue == condition.getParam()[1];
} }
} }

View File

@ -13,8 +13,8 @@ public class ContentQuestVarGreater extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
int questVarValue = quest.getMainQuest().getQuestVars()[params[0]]; int questVarValue = quest.getMainQuest().getQuestVars()[condition.getParam()[0]];
Grasscutter.getLogger().debug("questVar {} : {}", params[0], questVarValue); Grasscutter.getLogger().debug("questVar {} : {}", condition.getParam()[0], questVarValue);
return questVarValue > params[1]; return questVarValue > condition.getParam()[1];
} }
} }

View File

@ -13,8 +13,8 @@ public class ContentQuestVarLess extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
int questVarValue = quest.getMainQuest().getQuestVars()[params[0]]; int questVarValue = quest.getMainQuest().getQuestVars()[condition.getParam()[0]];
Grasscutter.getLogger().debug("questVar {} : {}", params[0], questVarValue); Grasscutter.getLogger().debug("questVar {} : {}", condition.getParam()[0], questVarValue);
return questVarValue < params[1]; return questVarValue < condition.getParam()[1];
} }
} }

View File

@ -1,6 +1,5 @@
package emu.grasscutter.game.quest.exec; package emu.grasscutter.game.quest.exec;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValueExec; import emu.grasscutter.game.quest.QuestValueExec;
@ -27,33 +26,16 @@ public class ExecNotifyGroupLua extends QuestExecHandler {
} }
scene.runWhenFinished( 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 = val eventType =
quest.getState() == QuestState.QUEST_STATE_FINISHED quest.getState() == QuestState.QUEST_STATE_FINISHED
? EventType.EVENT_QUEST_FINISH ? EventType.EVENT_QUEST_FINISH
: EventType.EVENT_QUEST_START; : EventType.EVENT_QUEST_START;
scriptManager.callEvent( 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())); .setEventSource(quest.getSubQuestId()));
}); });

View File

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

View File

@ -1,13 +1,11 @@
package emu.grasscutter.game.talk; package emu.grasscutter.game.talk;
import static emu.grasscutter.game.quest.enums.QuestCond.QUEST_COND_COMPLETE_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.*;
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_TALK;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.MainQuestData.TalkData; import emu.grasscutter.data.binout.MainQuestData.TalkData;
import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.*;
import emu.grasscutter.game.player.Player;
import lombok.NonNull; import lombok.NonNull;
public final class TalkManager extends BasePlayerManager { public final class TalkManager extends BasePlayerManager {
@ -22,30 +20,31 @@ public final class TalkManager extends BasePlayerManager {
* @param npcEntityId The entity ID of the NPC being talked to. * @param npcEntityId The entity ID of the NPC being talked to.
*/ */
public void triggerTalkAction(int talkId, int npcEntityId) { public void triggerTalkAction(int talkId, int npcEntityId) {
var talkData = GameData.getTalkConfigDataMap().get(talkId);
if (talkData == null) return;
var player = this.getPlayer(); var player = this.getPlayer();
// Check if the NPC id is valid.
var entity = player.getScene().getEntityById(npcEntityId);
if (entity != null) {
// The config ID of the entity is the NPC's ID.
if (!talkData.getNpcId().contains(entity.getConfigId())) return;
}
// Execute the talk action on associated handlers. var talkData = GameData.getTalkConfigDataMap().get(talkId);
talkData if (talkData != null) {
.getFinishExec() // Check if the NPC id is valid.
.forEach(e -> player.getServer().getTalkSystem().triggerExec(player, talkData, e)); var entity = player.getScene().getEntityById(npcEntityId);
if (entity != null) {
// The config ID of the entity is the NPC's ID.
if (!talkData.getNpcId().contains(entity.getConfigId())) return;
}
// Execute the talk action on associated handlers.
talkData
.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. // Invoke the talking events for quests.
var questManager = player.getQuestManager(); var questManager = player.getQuestManager();
questManager.queueEvent(QUEST_CONTENT_COMPLETE_ANY_TALK, talkId); questManager.queueEvent(QUEST_CONTENT_COMPLETE_ANY_TALK, talkId);
questManager.queueEvent(QUEST_CONTENT_COMPLETE_TALK, talkId); questManager.queueEvent(QUEST_CONTENT_COMPLETE_TALK, talkId);
questManager.queueEvent(QUEST_COND_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) { public void saveTalkToQuest(int talkId, int mainQuestId) {

View File

@ -1,54 +1,44 @@
package emu.grasscutter.game.world; package emu.grasscutter.game.world;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.*;
import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.binout.SceneNpcBornEntry; import emu.grasscutter.data.binout.SceneNpcBornEntry;
import emu.grasscutter.data.binout.routes.Route; import emu.grasscutter.data.binout.routes.Route;
import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.data.excels.*;
import emu.grasscutter.data.excels.SceneData;
import emu.grasscutter.data.excels.codex.CodexAnimalData; import emu.grasscutter.data.excels.codex.CodexAnimalData;
import emu.grasscutter.data.excels.monster.MonsterData; import emu.grasscutter.data.excels.monster.MonsterData;
import emu.grasscutter.data.excels.world.WorldLevelData; import emu.grasscutter.data.excels.world.WorldLevelData;
import emu.grasscutter.data.server.Grid; import emu.grasscutter.data.server.Grid;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.dungeons.DungeonManager; import emu.grasscutter.game.dungeons.*;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge; import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType; import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.entity.*; import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.entity.gadget.GadgetWorktop; import emu.grasscutter.game.entity.gadget.GadgetWorktop;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.managers.blossom.BlossomManager; import emu.grasscutter.game.managers.blossom.BlossomManager;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.*;
import emu.grasscutter.game.player.TeamInfo;
import emu.grasscutter.game.props.*; import emu.grasscutter.game.props.*;
import emu.grasscutter.game.quest.QuestGroupSuite; import emu.grasscutter.game.quest.QuestGroupSuite;
import emu.grasscutter.game.world.data.TeleportProperties; import emu.grasscutter.game.world.data.TeleportProperties;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.*;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; 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.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.SceneIndexManager; import emu.grasscutter.scripts.*;
import emu.grasscutter.scripts.SceneScriptManager;
import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneBlock; import emu.grasscutter.scripts.data.*;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.event.entity.EntityCreationEvent; import emu.grasscutter.server.event.entity.EntityCreationEvent;
import emu.grasscutter.server.event.player.PlayerTeleportEvent; import emu.grasscutter.server.event.player.PlayerTeleportEvent;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
import emu.grasscutter.utils.objects.KahnsSort; import emu.grasscutter.utils.objects.KahnsSort;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import lombok.Getter; import lombok.*;
import lombok.Setter;
import lombok.val;
public final class Scene { public final class Scene {
@Getter private final World world; @Getter private final World world;
@ -62,7 +52,6 @@ public final class Scene {
@Getter private final Set<SceneGroup> loadedGroups; @Getter private final Set<SceneGroup> loadedGroups;
@Getter private final BlossomManager blossomManager; @Getter private final BlossomManager blossomManager;
private final HashSet<Integer> unlockedForces; private final HashSet<Integer> unlockedForces;
private final List<Runnable> afterLoadedCallbacks = new ArrayList<>();
private final long startWorldTime; private final long startWorldTime;
@Getter @Setter DungeonManager dungeonManager; @Getter @Setter DungeonManager dungeonManager;
@Getter Int2ObjectMap<Route> sceneRoutes; @Getter Int2ObjectMap<Route> sceneRoutes;
@ -79,7 +68,11 @@ public final class Scene {
@Getter private int tickCount = 0; @Getter private int tickCount = 0;
@Getter private boolean isPaused = false; @Getter private boolean isPaused = false;
private final List<Runnable> afterLoadedCallbacks = new ArrayList<>();
private final List<Runnable> afterHostInitCallbacks = new ArrayList<>();
@Getter private GameEntity sceneEntity; @Getter private GameEntity sceneEntity;
@Getter private final ServerTaskScheduler scheduler;
public Scene(World world, SceneData sceneData) { public Scene(World world, SceneData sceneData) {
this.world = world; this.world = world;
@ -103,6 +96,7 @@ public final class Scene {
this.blossomManager = new BlossomManager(this); this.blossomManager = new BlossomManager(this);
this.unlockedForces = new HashSet<>(); this.unlockedForces = new HashSet<>();
this.sceneEntity = new EntityScene(this); this.sceneEntity = new EntityScene(this);
this.scheduler = new ServerTaskScheduler();
} }
public int getId() { public int getId() {
@ -117,6 +111,13 @@ public final class Scene {
return this.getPlayers().size(); return this.getPlayers().size();
} }
/**
* @return The scene's world's host.
*/
public Player getHost() {
return this.getWorld().getHost();
}
public GameEntity getEntityById(int id) { public GameEntity getEntityById(int id) {
// Check if the scene's entity ID is referenced. // Check if the scene's entity ID is referenced.
if (id == 0x13800001) return this.sceneEntity; if (id == 0x13800001) return this.sceneEntity;
@ -535,6 +536,10 @@ public final class Scene {
return; return;
} }
if (!isPaused) {
this.getScheduler().runTasks();
}
if (this.getScriptManager().isInit()) { if (this.getScriptManager().isInit()) {
// this.checkBlocks(); // this.checkBlocks();
this.checkGroups(); this.checkGroups();
@ -551,19 +556,22 @@ public final class Scene {
} }
var sceneTime = getSceneTimeSeconds(); 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(); blossomManager.onTick();
checkNpcGroup(); this.checkNpcGroup();
this.finishLoading(); this.finishLoading();
this.checkPlayerRespawn(); this.checkPlayerRespawn();
if (this.tickCount++ % 10 == 0) this.broadcastPacket(new PacketSceneTimeNotify(this)); 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. */ /** Validates a player's current position. Teleports the player if the player is out of bounds. */
@ -686,6 +694,29 @@ public final class Scene {
this.afterLoadedCallbacks.add(runnable); this.afterLoadedCallbacks.add(runnable);
} }
/**
* Invoked when a player initializes loading the scene.
*
* @param player The player that initialized loading the scene.
*/
public void playerSceneInitialized(Player player) {
// Check if the player is the host.
if (!player.equals(this.getHost())) return;
// Run all callbacks.
this.afterHostInitCallbacks.forEach(Runnable::run);
this.afterHostInitCallbacks.clear();
}
/**
* Run a callback when the host initializes loading the scene.
*
* @param runnable The callback to be executed.
*/
public void runWhenHostInitialized(Runnable runnable) {
this.afterHostInitCallbacks.add(runnable);
}
public int getEntityLevel(int baseLevel, int worldLevelOverride) { public int getEntityLevel(int baseLevel, int worldLevelOverride) {
int level = worldLevelOverride > 0 ? worldLevelOverride + baseLevel - 22 : baseLevel; int level = worldLevelOverride > 0 ? worldLevelOverride + baseLevel - 22 : baseLevel;
level = Math.min(level, 100); level = Math.min(level, 100);
@ -700,18 +731,6 @@ public final class Scene {
npcBornEntries.addAll(loadNpcForPlayer(player)); 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; this.npcBornEntrySet = npcBornEntries;
} }
@ -858,7 +877,7 @@ public final class Scene {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
for (var group : this.loadedGroups) { 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); unloadGroup(scriptManager.getBlocks().get(group.block_id), group.id);
} }
@ -1164,14 +1183,27 @@ public final class Scene {
pos.toDoubleArray(), pos.toDoubleArray(),
Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange);
var sceneNpcBornEntries = var sceneNpcBornCanidates =
npcList.stream().filter(i -> !this.npcBornEntrySet.contains(i)).toList(); 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) { if (sceneNpcBornEntries.size() > 0) {
this.broadcastPacket(new PacketGroupSuiteNotify(sceneNpcBornEntries)); this.broadcastPacket(new PacketGroupSuiteNotify(sceneNpcBornEntries));
Grasscutter.getLogger().trace("Loaded Npc Group Suite {}", 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) { 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.GameData;
import emu.grasscutter.data.excels.dungeon.DungeonData; import emu.grasscutter.data.excels.dungeon.DungeonData;
import emu.grasscutter.game.entity.EntityTeam; import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.entity.EntityWorld;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.Player.SceneLoadState; import emu.grasscutter.game.player.Player.SceneLoadState;
import emu.grasscutter.game.props.EnterReason; import emu.grasscutter.game.props.*;
import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.quest.enums.QuestContent; import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.game.world.data.TeleportProperties; import emu.grasscutter.game.world.data.TeleportProperties;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.*;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import emu.grasscutter.scripts.data.SceneConfig; import emu.grasscutter.scripts.data.SceneConfig;
import emu.grasscutter.server.event.player.PlayerTeleportEvent; 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.game.GameServer;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.ConversionUtils; import emu.grasscutter.utils.ConversionUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import java.util.*;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import lombok.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import lombok.Getter;
import lombok.val;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class World implements Iterable<Player> { public class World implements Iterable<Player> {
@ -44,7 +35,8 @@ public class World implements Iterable<Player> {
private int nextPeerId = 0; private int nextPeerId = 0;
private int worldLevel; private int worldLevel;
@Getter private boolean isMultiplayer, timeLocked = false; @Getter private boolean isMultiplayer = false;
@Getter private boolean timeLocked;
private long lastUpdateTime; private long lastUpdateTime;
@Getter private int tickCount = 0; @Getter private int tickCount = 0;
@ -65,6 +57,7 @@ public class World implements Iterable<Player> {
this.entity = new EntityWorld(this); this.entity = new EntityWorld(this);
this.worldLevel = player.getWorldLevel(); this.worldLevel = player.getWorldLevel();
this.isMultiplayer = isMultiplayer; this.isMultiplayer = isMultiplayer;
this.timeLocked = player.getProperty(PlayerProperty.PROP_IS_GAME_TIME_LOCKED) != 0;
this.lastUpdateTime = System.currentTimeMillis(); this.lastUpdateTime = System.currentTimeMillis();
this.currentWorldTime = host.getPlayerGameTime(); this.currentWorldTime = host.getPlayerGameTime();
@ -164,6 +157,16 @@ public class World implements Iterable<Player> {
player.getTeamManager().getCurrentSinglePlayerTeamInfo(), player.getTeamManager().getCurrentSinglePlayerTeamInfo(),
player.getTeamManager().getMaxTeamSize()); player.getTeamManager().getMaxTeamSize());
player.getTeamManager().setCurrentCharacterIndex(0); 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 // Add to scene
@ -217,6 +220,14 @@ public class World implements Iterable<Player> {
victim.getSceneId(), victim.getSceneId(),
victim.getPosition())); 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. // Check if there are players in this world.
if (this.getPlayerCount() == 0) return true; if (this.getPlayerCount() == 0) return true;
// Tick all associated scenes. // 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 // sync time every 10 seconds
if (this.tickCount % 10 == 0) { if (this.tickCount % 10 == 0) {
@ -512,10 +527,6 @@ public class World implements Iterable<Player> {
*/ */
public void changeTime(long gameTime) { public void changeTime(long gameTime) {
this.currentWorldTime = 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) { if (pluginConfig.api == null) {
Grasscutter.getLogger() Grasscutter.getLogger()
.warn(translate("plugin.invalid_api.not_present", plugin.getName())); .warn(translate("plugin.invalid_api.not_present", plugin.getName()));
return; continue;
} else if (pluginConfig.api != API_VERSION) { } else if (pluginConfig.api != API_VERSION) {
Grasscutter.getLogger() Grasscutter.getLogger()
.warn( .warn(
@ -90,13 +90,13 @@ public final class PluginManager {
plugin.getName(), plugin.getName(),
pluginConfig.api, pluginConfig.api,
API_VERSION)); API_VERSION));
return; continue;
} }
// Check if the plugin config is valid. // Check if the plugin config is valid.
if (!pluginConfig.validate()) { if (!pluginConfig.validate()) {
Grasscutter.getLogger().warn(translate("plugin.invalid_config", plugin.getName())); Grasscutter.getLogger().warn(translate("plugin.invalid_config", plugin.getName()));
return; continue;
} }
// Create a JAR file instance from the plugin's URL. // 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)); Grasscutter.getLogger().info(translate("plugin.enabling_plugin", name));
try { try {
plugin.onEnable(); plugin.onEnable();
return;
} catch (NoSuchMethodError ignored) {
Grasscutter.getLogger().error(translate("plugin.invalid_api.outdated", name));
} catch (Throwable exception) { } catch (Throwable exception) {
Grasscutter.getLogger().error(translate("plugin.enabling_failed", name), exception); Grasscutter.getLogger().error(translate("plugin.enabling_failed", name), exception);
} }
this.disablePlugin(plugin);
}); });
} }

View File

@ -10,7 +10,7 @@ import emu.grasscutter.data.server.Grid;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.entity.*; import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.entity.gadget.platform.BaseRoute; import emu.grasscutter.game.entity.gadget.platform.BaseRoute;
import emu.grasscutter.game.props.EntityType; import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.quest.*; import emu.grasscutter.game.quest.*;
import emu.grasscutter.game.world.*; import emu.grasscutter.game.world.*;
import emu.grasscutter.net.proto.VisionTypeOuterClass; import emu.grasscutter.net.proto.VisionTypeOuterClass;
@ -99,7 +99,13 @@ public class SceneScriptManager {
} }
public SceneConfig getConfig() { public SceneConfig getConfig() {
return this.isInit ? this.meta.config : null; for (int i = 0; i < 10; ++i) {
if (this.isInit) {
return this.meta.config;
}
Utils.sleep(100);
}
return null;
} }
public Map<Integer, SceneBlock> getBlocks() { public Map<Integer, SceneBlock> getBlocks() {
@ -209,7 +215,14 @@ public class SceneScriptManager {
var suiteData = group.getSuiteByIndex(suiteIndex); var suiteData = group.getSuiteByIndex(suiteIndex);
if (suiteData == null) { if (suiteData == null) {
Grasscutter.getLogger().warn("Group {} suite {} not found", group.id, suiteIndex); Grasscutter.getLogger().warn("Group {} suite {} not found", group.id, suiteIndex);
return 0; group.setLoaded(false);
group.load(this.scene.getId());
suiteData = group.getSuiteByIndex(suiteIndex);
if (suiteData == null) {
return 0;
}
Grasscutter.getLogger()
.error("Group {} suite {} nvm, I found it. This is BAD", group.id, suiteIndex);
} }
int prevSuiteIndex = groupInstance.getActiveSuiteId(); int prevSuiteIndex = groupInstance.getActiveSuiteId();
@ -266,15 +279,15 @@ public class SceneScriptManager {
suiteId, suiteId,
groupId, groupId,
getScene().getId()); getScene().getId());
} else { if (targetGroupInstance == null) return false;
Grasscutter.getLogger().debug("Refreshing group {} suite {}", groupId, suiteId);
suiteId =
refreshGroup(
targetGroupInstance,
suiteId,
false); // If suiteId is zero, the value of suiteId changes
scene.broadcastPacket(new PacketGroupSuiteNotify(groupId, suiteId));
} }
Grasscutter.getLogger().debug("Refreshing group {} suite {}", groupId, suiteId);
suiteId =
refreshGroup(
targetGroupInstance,
suiteId,
false); // If suiteId is zero, the value of suiteId changes
scene.broadcastPacket(new PacketGroupSuiteNotify(groupId, suiteId));
return true; return true;
} }
@ -627,27 +640,25 @@ public class SceneScriptManager {
// add other types of entity // add other types of entity
var entities = var entities =
getScene().getEntities().values().stream() getScene().getEntities().values().stream()
.filter( .filter(e -> region.getMetaRegion().contains(e.getPosition()))
e ->
e.getEntityType() == EntityType.Avatar.getValue()
&& region.getMetaRegion().contains(e.getPosition()))
.toList(); .toList();
var entitiesIds = entities.stream().map(GameEntity::getId).toList();
var enterEntities =
entitiesIds.stream().filter(e -> !region.getEntities().contains(e)).toList();
var leaveEntities =
region.getEntities().stream().filter(e -> !entitiesIds.contains(e)).toList();
entities.forEach(region::addEntity); entities.forEach(region::addEntity);
var targetId = 0; for (var targetId : enterEntities) {
if (entities.size() > 0) {
targetId = entities.get(0).getId();
}
if (region.entityHasEntered()) {
Grasscutter.getLogger() Grasscutter.getLogger()
.trace("Call EVENT_ENTER_REGION_{}", region.getMetaRegion().config_id); .trace("Call EVENT_ENTER_REGION_{}", region.getMetaRegion().config_id);
this.callEvent( this.callEvent(
new ScriptArgs(region.getGroupId(), EventType.EVENT_ENTER_REGION, region.getConfigId()) new ScriptArgs(region.getGroupId(), EventType.EVENT_ENTER_REGION, region.getConfigId())
.setEventSource(EntityIdType.toEntityType(targetId >> 24).getValue())
.setSourceEntityId(region.getId()) .setSourceEntityId(region.getId())
.setTargetEntityId(targetId)); .setTargetEntityId(targetId));
region.resetNewEntities();
} }
for (var entityId : region.getEntities()) { for (var entityId : region.getEntities()) {
@ -657,13 +668,12 @@ public class SceneScriptManager {
} }
} }
if (region.entityHasLeft()) { for (var targetId : leaveEntities) {
this.callEvent( this.callEvent(
new ScriptArgs(region.getGroupId(), EventType.EVENT_LEAVE_REGION, region.getConfigId()) new ScriptArgs(region.getGroupId(), EventType.EVENT_LEAVE_REGION, region.getConfigId())
.setEventSource(EntityIdType.toEntityType(targetId >> 24).getValue())
.setSourceEntityId(region.getId()) .setSourceEntityId(region.getId())
.setTargetEntityId(region.getFirstEntityId())); .setTargetEntityId(targetId));
region.resetNewEntities();
} }
} }
} }
@ -681,8 +691,8 @@ public class SceneScriptManager {
|| !groupInstance.getDeadEntities().contains(m.config_id)); || !groupInstance.getDeadEntities().contains(m.config_id));
}) })
.map(g -> createGadget(group.id, group.block_id, g, groupInstance.getCachedGadgetState(g))) .map(g -> createGadget(group.id, group.block_id, g, groupInstance.getCachedGadgetState(g)))
.peek(g -> groupInstance.cacheGadgetState(g.getMetaGadget(), g.getState()))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.peek(g -> groupInstance.cacheGadgetState(g.getMetaGadget(), g.getState()))
.toList(); .toList();
} }
@ -801,26 +811,27 @@ public class SceneScriptManager {
private void realCallEvent(@Nonnull ScriptArgs params) { private void realCallEvent(@Nonnull ScriptArgs params) {
try { try {
ScriptLoader.getScriptLib().setSceneScriptManager(this); ScriptLoader.getScriptLib().setSceneScriptManager(this);
int eventType = params.type;
Set<SceneTrigger> relevantTriggers = new HashSet<>(); var eventType = params.type;
if (eventType == EventType.EVENT_ENTER_REGION || eventType == EventType.EVENT_LEAVE_REGION) { var relevantTriggers =
relevantTriggers = switch (eventType) {
this.getTriggersByEvent(eventType).stream() case EventType.EVENT_ENTER_REGION, EventType.EVENT_LEAVE_REGION -> this
.getTriggersByEvent(eventType)
.stream()
.filter( .filter(
t -> t ->
t.getCondition().contains(String.valueOf(params.param1)) t.getName().substring(13).equals(String.valueOf(params.param1))
&& (t.getSource().isEmpty() && (t.getSource().isEmpty()
|| t.getSource().equals(params.getEventSource()))) || t.getSource().equals(params.getEventSource())))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} else { default -> this.getTriggersByEvent(eventType).stream()
relevantTriggers =
this.getTriggersByEvent(eventType).stream()
.filter( .filter(
t -> params.getGroupId() == 0 || t.getCurrentGroup().id == params.getGroupId()) t -> params.getGroupId() == 0 || t.getCurrentGroup().id == params.getGroupId())
.filter( .filter(
t -> (t.getSource().isEmpty() || t.getSource().equals(params.getEventSource()))) t -> (t.getSource().isEmpty() || t.getSource().equals(params.getEventSource())))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} };
for (SceneTrigger trigger : relevantTriggers) { for (SceneTrigger trigger : relevantTriggers) {
handleEventForTrigger(params, trigger); handleEventForTrigger(params, trigger);
} }
@ -890,7 +901,6 @@ public class SceneScriptManager {
.toList() .toList()
.get(0); .get(0);
this.getScene().getPlayers().forEach(p -> p.onEnterRegion(region.getMetaRegion())); this.getScene().getPlayers().forEach(p -> p.onEnterRegion(region.getMetaRegion()));
this.deregisterRegion(region.getMetaRegion());
} else if (trigger.getEvent() == EventType.EVENT_LEAVE_REGION) { } else if (trigger.getEvent() == EventType.EVENT_LEAVE_REGION) {
var region = var region =
this.regions.values().stream() this.regions.values().stream()
@ -898,7 +908,6 @@ public class SceneScriptManager {
.toList() .toList()
.get(0); .get(0);
this.getScene().getPlayers().forEach(p -> p.onLeaveRegion(region.getMetaRegion())); this.getScene().getPlayers().forEach(p -> p.onLeaveRegion(region.getMetaRegion()));
this.deregisterRegion(region.getMetaRegion());
} }
if (trigger.getEvent() == EVENT_TIMER_EVENT) { if (trigger.getEvent() == EVENT_TIMER_EVENT) {

View File

@ -8,36 +8,25 @@ import emu.grasscutter.game.dungeons.challenge.enums.FatherChallengeProperty;
import emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactory; import emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactory;
import emu.grasscutter.game.entity.*; import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.entity.gadget.GadgetWorktop; import emu.grasscutter.game.entity.gadget.GadgetWorktop;
import emu.grasscutter.game.entity.gadget.platform.ConfigRoute; import emu.grasscutter.game.entity.gadget.platform.*;
import emu.grasscutter.game.entity.gadget.platform.PointArrayRoute; import emu.grasscutter.game.props.*;
import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.quest.enums.*;
import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.world.*;
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.quest.enums.QuestCond;
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.EnterTypeOuterClass;
import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.constants.GroupKillPolicy; import emu.grasscutter.scripts.constants.*;
import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.*;
import emu.grasscutter.scripts.data.SceneObject;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.game.world.Position;
import io.netty.util.concurrent.FastThreadLocal; import io.netty.util.concurrent.FastThreadLocal;
import lombok.val; import lombok.val;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.*;
import org.luaj.vm2.LuaValue; import org.slf4j.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.util.*;
import static emu.grasscutter.game.props.EnterReason.Lua; import static emu.grasscutter.game.props.EnterReason.Lua;
import static emu.grasscutter.scripts.ScriptUtils.luaToPos; import static emu.grasscutter.scripts.ScriptUtils.*;
import static emu.grasscutter.scripts.ScriptUtils.posToLua;
import static emu.grasscutter.scripts.constants.GroupKillPolicy.*; import static emu.grasscutter.scripts.constants.GroupKillPolicy.*;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -129,7 +118,7 @@ public class ScriptLib {
public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) { public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) {
logger.debug("[LUA] Call SetWorktopOptionsByGroupId with {},{},{}", logger.debug("[LUA] Call SetWorktopOptionsByGroupId with {},{},{}",
groupId,configId,options); groupId, configId, options);
val entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId); val entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId);
@ -152,18 +141,17 @@ public class ScriptLib {
logger.debug("[LUA] Call SetWorktopOptions with {}", printTable(table)); logger.debug("[LUA] Call SetWorktopOptions with {}", printTable(table));
var callParams = this.callParams.getIfExists(); var callParams = this.callParams.getIfExists();
var group = this.currentGroup.getIfExists(); var group = this.currentGroup.getIfExists();
if(callParams == null || group == null){ if (callParams == null || group == null) {
return 1; return 1;
} }
var configId = callParams.param1; var configId = callParams.param1;
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId); var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
var worktopOptions = new int[table.length()];
int[] worktopOptions = new int[table.length()]; for (int i = 1; i<=table.length(); i++) {
for(int i = 1 ;i<=table.length() ;i++){
worktopOptions[i-1] = table.get(i).optint(-1); 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; return 2;
} }
@ -172,9 +160,11 @@ public class ScriptLib {
} }
worktop.addWorktopOptions(worktopOptions); worktop.addWorktopOptions(worktopOptions);
var scene = this.getSceneScriptManager().getScene();
var scene = getSceneScriptManager().getScene(); // Done in order to synchronize with addEntities in Scene.class.
scene.broadcastPacket(new PacketWorktopOptionNotify(gadget)); synchronized (this.getSceneScriptManager().getScene()) {
scene.broadcastPacket(new PacketWorktopOptionNotify(gadget));
}
return 0; return 0;
} }
@ -254,12 +244,6 @@ public class ScriptLib {
Grasscutter.getLogger().warn("trying to get suite that doesn't exist: {} {}", groupId, suite); Grasscutter.getLogger().warn("trying to get suite that doesn't exist: {} {}", groupId, suite);
return 1; return 1;
} }
// avoid spawn wrong monster
if(getSceneScriptManager().getScene().getChallenge() != null)
if(!getSceneScriptManager().getScene().getChallenge().inProgress() ||
getSceneScriptManager().getScene().getChallenge().getGroup().id != groupId){
return 0;
}
this.getSceneScriptManager().addGroupSuite(groupInstance, suiteData); this.getSceneScriptManager().addGroupSuite(groupInstance, suiteData);
return 0; return 0;
@ -396,12 +380,12 @@ public class ScriptLib {
logger.debug("[LUA] Call SetGroupVariableValue with {},{}", logger.debug("[LUA] Call SetGroupVariableValue with {},{}",
var, value); var, value);
val groupId= currentGroup.get().id; val groupId = currentGroup.get().id;
val variables = getSceneScriptManager().getVariables(groupId); val variables = getSceneScriptManager().getVariables(groupId);
val old = variables.getOrDefault(var, value); val old = variables.getOrDefault(var, value);
variables.put(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; return 0;
} }
@ -409,17 +393,46 @@ public class ScriptLib {
logger.debug("[LUA] Call ChangeGroupVariableValue with {},{}", logger.debug("[LUA] Call ChangeGroupVariableValue with {},{}",
var, value); var, value);
val groupId= currentGroup.get().id; val groupId = currentGroup.get().id;
val variables = getSceneScriptManager().getVariables(groupId); val variables = getSceneScriptManager().getVariables(groupId);
val old = variables.getOrDefault(var, 0); val old = variables.getOrDefault(var, 0);
variables.put(var, old + value); variables.put(var, old + value);
logger.debug("[LUA] Call ChangeGroupVariableValue with {},{}", getSceneScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_VARIABLE_CHANGE, old+value, old).setEventSource(var));
old, old+value);
getSceneScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_VARIABLE_CHANGE, old+value, old));
return LuaValue.ZERO; return LuaValue.ZERO;
} }
public int GetGroupVariableValueByGroup(String var, int groupId){
logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{}",
var,groupId);
return getSceneScriptManager().getVariables(groupId).getOrDefault(var, 0);
}
public int SetGroupVariableValueByGroup(String var, int value, int groupId){
logger.debug("[LUA] Call SetGroupVariableValueByGroup with {},{},{}",
var,value,groupId);
val variables = getSceneScriptManager().getVariables(groupId);
val old = variables.getOrDefault(var, value);
variables.put(var, value);
getSceneScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_VARIABLE_CHANGE, value, old).setEventSource(var));
return 0;
}
public int ChangeGroupVariableValueByGroup(String var, int value, int groupId){
logger.debug("[LUA] Call ChangeGroupVariableValueByGroup with {},{}",
var,groupId);
val variables = getSceneScriptManager().getVariables(groupId);
val old = variables.getOrDefault(var, 0);
variables.put(var, old + value);
getSceneScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_VARIABLE_CHANGE, old+value, old).setEventSource(var));
return 0;
}
/** /**
* Set the actions and triggers to designated group * Set the actions and triggers to designated group
*/ */
@ -530,22 +543,22 @@ public class ScriptLib {
var entity = scene.getEntityByConfigId(cfgId); var entity = scene.getEntityByConfigId(cfgId);
if (entity == null) return 2; if (entity == null) return 2;
scene.broadcastPacket( scene.runWhenHostInitialized(() -> scene.broadcastPacket(
new PacketServerGlobalValueChangeNotify(entity, sgvName, value)); new PacketServerGlobalValueChangeNotify(entity, sgvName, value)));
return 0; return 0;
} }
public int GetGroupVariableValueByGroup(String name, int groupId){ public int SetEntityServerGlobalValueByEntityId(int entityId, String sgvName, int value) {
logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{}", logger.debug("[LUA] Call SetEntityServerGlobalValueByEntityId with {}, {}, {}",
name,groupId); entityId, sgvName, value);
return getSceneScriptManager().getVariables(groupId).getOrDefault(name, 0); var scriptManager = this.getSceneScriptManager();
} if (scriptManager == null) return 1;
public int ChangeGroupVariableValueByGroup(String name, int value, int groupId){
logger.debug("[LUA] Call ChangeGroupVariableValueByGroup with {},{}", var scene = scriptManager.getScene();
name,groupId);
//TODO test scene.runWhenHostInitialized(() -> scene.broadcastPacket(
getSceneScriptManager().getVariables(groupId).put(name, value); new PacketServerGlobalValueChangeNotify(entityId, sgvName, value)));
return 0; return 0;
} }
@ -573,14 +586,6 @@ public class ScriptLib {
return 0; return 0;
} }
public int SetGroupVariableValueByGroup(String key, int value, int groupId){
logger.debug("[LUA] Call SetGroupVariableValueByGroup with {},{},{}",
key,value,groupId);
getSceneScriptManager().getVariables(groupId).put(key, value);
return 0;
}
public int CreateMonster(LuaTable table){ public int CreateMonster(LuaTable table){
logger.debug("[LUA] Call CreateMonster with {}", logger.debug("[LUA] Call CreateMonster with {}",
printTable(table)); printTable(table));
@ -609,6 +614,11 @@ public class ScriptLib {
logger.debug("[LUA] Call CreateGadget with {}", logger.debug("[LUA] Call CreateGadget with {}",
printTable(table)); printTable(table));
var configId = table.get("config_id").toint(); 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(); var group = getCurrentGroup();
@ -667,6 +677,7 @@ public class ScriptLib {
var1); var1);
for(var player : getSceneScriptManager().getScene().getPlayers()){ for(var player : getSceneScriptManager().getScene().getPlayers()){
player.getPlayerProgress().addToCurrentProgress(var1, 1);
player.getQuestManager().queueEvent(QuestCond.QUEST_COND_LUA_NOTIFY, var1); player.getQuestManager().queueEvent(QuestCond.QUEST_COND_LUA_NOTIFY, var1);
player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_LUA_NOTIFY, var1); player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_LUA_NOTIFY, var1);
} }
@ -702,7 +713,7 @@ public class ScriptLib {
return EntityType.None.getValue(); return EntityType.None.getValue();
} }
return entity.getEntityType(); return entity.getEntityType().getValue();
} }
public int GetQuestState(int entityId, int questId){ public int GetQuestState(int entityId, int questId){
@ -737,11 +748,11 @@ public class ScriptLib {
val entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId); val entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId);
if(entity == null || entity.getEntityType() != entityType){ if(entity == null || entity.getEntityType().getValue() != entityType){
return 1; return 1;
} }
getSceneScriptManager().getScene().removeEntity(entity); getSceneScriptManager().getScene().removeEntity(entity, VisionType.VISION_TYPE_REMOVE);
return 0; return 0;
} }
@ -815,17 +826,17 @@ public class ScriptLib {
//TODO implement //TODO implement
return 0; return 0;
} }
public int IsPlayerAllAvatarDie(int sceneUid){ public boolean IsPlayerAllAvatarDie(int sceneUid){
logger.warn("[LUA] Call unimplemented IsPlayerAllAvatarDie {}", 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){ for (GameEntity p : playerEntities){
var player = (EntityAvatar)p; var player = (EntityAvatar)p;
if(player.isAlive()){ if(player.isAlive()){
return 0; return false;
} }
} }
//TODO check //TODO check
return 1; return true;
} }
public int sendShowCommonTipsToClient(String title, String content, int closeTime) { public int sendShowCommonTipsToClient(String title, String content, int closeTime) {
@ -861,6 +872,11 @@ public class ScriptLib {
//TODO implement var6 object has int success, int fail, bool fail_on_wipe //TODO implement var6 object has int success, int fail, bool fail_on_wipe
return 0; 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){ public int CreateEffigyChallengeMonster(int var1, int[] var2){
logger.warn("[LUA] Call unimplemented CreateEffigyChallengeMonster with {} {}", var1, var2); logger.warn("[LUA] Call unimplemented CreateEffigyChallengeMonster with {} {}", var1, var2);
//TODO implement //TODO implement
@ -946,7 +962,7 @@ public class ScriptLib {
return 0; return 0;
} }
public int EndTimeAxis(String var1){ public int EndTimeAxis(String var1){
logger.warn("[LUA] Call unimplemented EndTimeAxis with {} {} {}", var1); logger.warn("[LUA] Call unimplemented EndTimeAxis with {}", var1);
//TODO implement var1 == name? //TODO implement var1 == name?
return 0; return 0;
} }
@ -1062,6 +1078,12 @@ public class ScriptLib {
return 0; return 0;
} }
public int ClearPlayerEyePoint(int var1){
logger.warn("[LUA] Call unimplemented ClearPlayerEyePoint with {}", var1);
//TODO implement
return 0;
}
public int MoveAvatarByPointArray(int uid, int targetId, LuaTable var3, String var4){ public int MoveAvatarByPointArray(int uid, int targetId, LuaTable var3, String var4){
logger.warn("[LUA] Call unimplemented MoveAvatarByPointArray with {} {} {} {}", uid, targetId, printTable(var3), var4); logger.warn("[LUA] Call unimplemented MoveAvatarByPointArray with {} {} {} {}", uid, targetId, printTable(var3), var4);
//TODO implement var3 contains int speed, var4 is a json string //TODO implement var3 contains int speed, var4 is a json string
@ -1120,7 +1142,7 @@ public class ScriptLib {
} }
public int PlayCutSceneWithParam(int cutsceneId, int var2, LuaTable var3){ public int PlayCutSceneWithParam(int cutsceneId, int var2, LuaTable var3){
logger.warn("[LUA] Call unimplemented PlayCutScene with {} {}", cutsceneId, var2, var3); logger.warn("[LUA] Call unimplemented PlayCutScene with {} {} {}", cutsceneId, var2, var3);
//TODO implement //TODO implement
return 0; return 0;
} }
@ -1297,6 +1319,13 @@ public class ScriptLib {
} }
configRoute.setRouteId(routeId); configRoute.setRouteId(routeId);
configRoute.setStartIndex(0);
configRoute.setStarted(false);
for(var task : configRoute.getScheduledIndexes()) {
sceneScriptManager.get().getScene().getScheduler().cancelTask(task);
}
configRoute.getScheduledIndexes().clear();
sceneScriptManager.get().getScene().broadcastPacket(new PacketPlatformChangeRouteNotify(entityGadget)); sceneScriptManager.get().getScene().broadcastPacket(new PacketPlatformChangeRouteNotify(entityGadget));
return 0; return 0;
} }
@ -1598,6 +1627,16 @@ public class ScriptLib {
return 0; 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() { public int[] GetGatherConfigIdList() {
EntityGadget gadget = getCurrentEntityGadget(); EntityGadget gadget = getCurrentEntityGadget();

View File

@ -3,5 +3,8 @@ package emu.grasscutter.scripts.constants;
public enum VisionLevelType { public enum VisionLevelType {
VISION_LEVEL_NORMAL, VISION_LEVEL_NORMAL,
VISION_LEVEL_LITTLE_REMOTE, 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 SceneGarbage garbages;
public SceneInitConfig init_config; public SceneInitConfig init_config;
@Getter public boolean dynamic_load = false; @Getter public boolean dynamic_load = false;
public boolean dontUnload = false;
public SceneReplaceable is_replaceable; public SceneReplaceable is_replaceable;

View File

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

View File

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

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