Compare commits

..

316 Commits

Author SHA1 Message Date
s809 4a771a3e21 Restore ordering of session config entries 2024-09-08 21:21:42 +05:00
s809 0aa109a341 Refactor session config 2024-09-08 19:05:47 +05:00
s809 6d44255175 Fix crash on F3 when commit hash was failed to retrieve 2024-09-07 21:47:45 +05:00
s809 f8bb35cb2b Fix compilation on older versions 2024-09-06 00:12:09 +05:00
s809 52f1aed124 Fix client crashing 2024-09-05 23:45:08 +05:00
s809 6ae1ba1e17 Prefill levelKeyPrefix in new worlds 2024-09-05 14:22:08 +05:00
s809 9105f30fec Fix compilation 2024-09-04 22:53:06 +05:00
s809 839c849a9d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into serverside 2024-09-04 18:22:52 +05:00
s809 275f507096 Limit number of retries on request errors
Add a delay if rate limit is hit
2024-09-02 15:31:43 +05:00
s809 01c5a4072a Delay loading first level when on server 2024-08-31 20:47:03 +05:00
s809 1697707114 Restore LOD fetching by distance 2024-08-29 17:09:13 +05:00
s809 34b0b7dc31 Print entire buffer in log 2024-08-28 16:19:17 +05:00
s809 691e1022e3 Do not start generator until server responds with config 2024-08-27 16:35:27 +05:00
s809 18fd157474 Show incompatible protocol version in F3 2024-08-27 16:02:26 +05:00
s809 4948158fa8 Fix sync on login 2024-08-26 16:54:05 +05:00
s809 e3b972c928 Fix missing mixins in (Neo-)Forge 2024-08-24 12:07:13 +05:00
s809 ad056cb64e Fix compilation 2024-08-24 03:06:29 +05:00
s809 3e22ddead5 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into serverside 2024-08-24 02:59:56 +05:00
s809 5c7e27c52d Fix network compression pool not shutting down 2024-08-23 17:11:37 +05:00
s809 3a5c6f12c0 Add back Forge packet ID in pre-1.20.6 2024-08-23 14:51:09 +05:00
s809 627eee7a6d "Fix" buffer release errors in FullDataPayload 2024-08-23 14:16:35 +05:00
s809 7c4c99089b Use same packet resource for all versions 2024-08-19 17:56:34 +05:00
s809 00ec14d319 Add logging of request group lifecycle 2024-08-15 15:47:13 +05:00
s809 56188bc7d2 Fix colors in verifyall.ps1 2024-08-14 13:29:32 +05:00
s809 9b2429d388 Fix compilation 2024-08-11 21:21:15 +05:00
s809 2aa68ec41d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into serverside 2024-08-11 20:59:39 +05:00
s809 13c9f95750 Fix compilation 2024-08-11 00:53:12 +05:00
s809 b0549cecff Do not clear keyed level on close event 2024-08-10 23:53:33 +05:00
s809 95fb4a0e6a Make encode/decode error handling work correctly 2024-08-10 23:26:09 +05:00
s809 2a3aadc2fa Make error handling somewhat work 2024-08-10 19:49:40 +05:00
s809 52bddca0df Merge branch 'serverside-experimental/prevent-disconnects' into serverside 2024-08-07 22:20:39 +05:00
s809 606dede9ef Fix real-time updates 2024-08-06 23:12:18 +05:00
s809 e8c9d8391a Fix Neoforge not being able to connect to vanilla servers 2024-08-05 14:51:32 +05:00
s809 88ca223bbc Fix dimension switching (untested) 2024-08-03 15:43:19 +05:00
s809 4a51bbc796 [skip ci] Prevent disconnects on encode/decode/handle errors 2024-08-01 22:19:21 +05:00
s809 94ca0e2729 Increase defaults for network compression threads 2024-07-30 10:52:32 +05:00
s809 5befdbcddc Use FullDataPayload instead of reusing messages 2024-07-29 13:10:11 +05:00
s809 3e02d7f9dc Add build number on F3 screen 2024-07-28 20:19:41 +05:00
s809 48b38d9285 Fix compilation 2024-07-28 19:58:35 +05:00
s809 8c7c787a8f Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into serverside 2024-07-28 19:44:46 +05:00
s809 fc0cf56b48 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into serverside 2024-07-28 19:01:35 +05:00
s809 32c63ae15b Reapply "Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into serverside"
This reverts commit a2d5e8cdb3.
2024-07-28 17:06:36 +05:00
s809 bbf62f7ee3 Add verifyall.ps1 2024-07-27 23:09:46 +05:00
s809 6211542708 Update core 2024-07-27 23:08:45 +05:00
s809 a2d5e8cdb3 Revert "Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into serverside"
This reverts commit 692b304898, reversing
changes made to 0ca93e311c.
2024-07-27 23:07:43 +05:00
s809 692b304898 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into serverside 2024-07-27 21:43:54 +05:00
s809 0ca93e311c Fix handler registration 2024-07-20 23:56:34 +05:00
s809 c7aab012ae Update core 2024-07-17 00:02:22 +05:00
s809 80ccab21da Fix level handling for real time updates 2024-07-12 23:11:40 +05:00
s809 663ce3cde6 Add cache for ignoring responses for cancelled requests 2024-07-11 23:06:26 +05:00
s809 43fee18ae4 Clean up a bit 2024-07-11 22:08:21 +05:00
s809 014310631e Fix player tracking on server 2024-07-10 23:51:49 +05:00
s809 4f7e934c98 Add missing semaphore release 2024-07-09 18:06:20 +05:00
s809 563dcd7de6 Prevent request cancellation deadlock 2024-07-09 14:47:49 +05:00
s809 0a5cc734de Use dedicated thread pool for data compression 2024-07-08 23:08:04 +05:00
s809 0da158fecc Disable parent update propagation 2024-07-07 19:46:52 +05:00
s809 a7e8bbaf6a Reset state of level detection on world exit 2024-07-07 01:49:47 +05:00
s809 80732943c8 Repoint core to main repo 2024-07-01 14:20:34 +05:00
s809 994c86d5ba Make data source encoding lazy and move it off server thread 2024-07-01 00:16:00 +05:00
s809 18ccbbbb8e Move fixing the dimension name into even more correct place 2024-06-28 23:18:34 +05:00
s809 31c3fb9a1e Move fixing the dimension name into correct place 2024-06-28 19:28:40 +05:00
s809 8bdb383b2e Fix paths unable to be created on Windows 2024-06-28 17:25:18 +05:00
s809 d13ec687ed Fix test compilation failing 2024-06-28 15:52:51 +05:00
s809 43069703cd Update core 2024-06-28 15:44:06 +05:00
s809 6d76ace604 Use level's ResourceLocation instead of dimension type's 2024-06-28 15:35:28 +05:00
s809 9b139575e7 Clean up package structure 2024-06-26 23:57:50 +05:00
s809 efb9129edf Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into refactor/remove-tcp-connection 2024-06-26 15:13:22 +05:00
s809 6a380f6a7b Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into refactor/remove-tcp-connection 2024-06-26 14:55:39 +05:00
s809 0798ca01c5 Force GradleVanilla version 2024-06-21 13:49:18 +05:00
s809 8bfc1430c8 Put messages received before player joining into queue 2024-06-16 00:45:23 +05:00
s809 bd6621183d Avoid reloading levels when unnecessary 2024-06-14 16:25:25 +05:00
s809 ccc8076c66 Use level keys 2024-06-13 16:44:43 +05:00
s809 004103551f Prevent disconnection on decode failure 2024-06-10 23:55:33 +05:00
s809 ea47e11ecf Show dimension names 2024-06-10 23:40:01 +05:00
s809 8a3837b04b Better error on invalid dimension 2024-06-09 22:01:32 +05:00
s809 edfeaa618b Restore old cache key 2024-06-09 21:35:05 +05:00
s809 961cdbe868 Fix indent 2024-06-09 21:21:26 +05:00
s809 ff6ab67b69 Change job name 2024-06-09 21:19:39 +05:00
s809 c01fb4a716 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into refactor/remove-tcp-connection 2024-06-09 21:18:18 +05:00
s809 8bd524791f Use message wrapper in forge 2024-06-09 14:31:15 +05:00
s809 26059d5656 Fix logging errors 2024-06-08 00:07:33 +05:00
s809 3f23281e8d Add toString to messages & fix incorrect call 2024-06-06 21:25:32 +05:00
s809 fb25423deb Fix compilation for older versions 2 2024-06-05 21:17:21 +05:00
s809 6928c8dc28 Fix compilation for older versions 2024-06-04 23:33:44 +05:00
s809 7dfe0e4c50 Fix compilation 2024-06-02 20:00:16 +05:00
s809 1429ae5434 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into refactor/remove-tcp-connection 2024-06-02 19:59:34 +05:00
s809 3fb4d5a233 Increase section reload delay 2024-06-01 19:49:27 +05:00
s809 872226e5c5 Fix requests breaking on rejoining 2024-06-01 12:17:08 +05:00
s809 fb46820b1f Kinda works, rejoining is broken 2024-05-29 23:36:38 +05:00
s809 a786678bcb [skip ci] Incomplete 2024-05-21 22:55:06 +05:00
s809 0d35a3ea8e Move overrides in LAN to config 2024-05-18 22:14:01 +05:00
s809 6f87e22048 Fix forge config loading too late 2024-05-17 23:02:36 +05:00
s809 7c07c1e5bd Fix awt dependency error 2024-05-12 17:35:01 +05:00
s809 4ddb9659f5 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into feature/2.0.4 2024-05-11 19:17:13 +05:00
s809 e74b8c89ba Fix levels not unloading on forge 2024-05-11 18:38:25 +05:00
s809 1b536e4aef Fix compilation 2024-05-11 17:51:00 +05:00
s809 335f11acd3 Fix dimension switching (at cost of breaking immersive portals) 2024-05-10 23:56:15 +05:00
s809 b55b560cce Update core 2024-05-10 21:15:46 +05:00
s809 d87a152052 Fix generated sections not appearing 2024-05-10 21:15:02 +05:00
s809 db5a9c7c84 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons into feature/2.0.4 2024-05-05 19:51:32 +05:00
s809 2508efdd91 Fix updates 2024-05-05 16:55:20 +05:00
s809 4852720e14 Generation works, updates don't 2024-05-03 22:56:07 +05:00
s809 f39d156b11 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-05-02 21:47:42 +05:00
s809 e21eb61335 Fix 1.16.5 and 1.17.1 builds 2024-04-17 21:02:19 +05:00
s809 c49f385e3c Update core 2024-04-16 22:00:10 +05:00
s809 0584b0e593 Fix integer overflows 2024-04-12 23:15:02 +05:00
s809 220ac89ad8 Fix Neoforge 2024-04-12 22:38:21 +05:00
s809 e8e56b66a3 Merge branch 'feature/plugin-channel' 2024-04-02 22:35:28 +05:00
s809 634d8a5b52 Remove localhost from check 2024-04-02 22:27:44 +05:00
s809 b621c9fb8d Some small changes 2024-04-02 21:55:59 +05:00
s809 696f84a064 Fix compilation 2024-04-01 21:52:25 +05:00
s809 5c13ff8960 Fix errors when on vanilla server 2024-04-01 00:55:23 +05:00
s809 e102cd78cd Fix reconnection logic 2024-03-30 23:40:17 +05:00
s809 c5a782acba Fix broken mod compat on server 💀 2024-03-28 09:24:57 +05:00
s809 2008ea2b0c Incomplete 2024-03-26 00:31:13 +05:00
s809 0f349461d9 Fix Forge 2024-03-18 21:38:08 +05:00
s809 baf464aa02 Add thread pool task buildup limiter 2024-03-16 12:28:42 +05:00
s809 51d83d803a [no ci] Incomplete fix forge 2024-03-16 11:22:52 +05:00
s809 2b3244159b Server side plugin networking
Untested port for Forge
2024-03-14 21:46:33 +05:00
s809 9255c22d0e Fix world setting 2024-03-10 21:11:04 +05:00
s809 4d573c4aea Initial buggy plugin channel support 2024-03-05 22:10:05 +05:00
s809 a59f359133 Do not wait for world gen tasks to stop while shutting down queue 2024-02-25 18:05:50 +05:00
s809 c83d02c30c Always print git info 2024-02-25 13:11:37 +05:00
s809 d01573b03e Show server side messages in F3 on disconnect 2024-02-25 00:40:31 +05:00
s809 b1fb74539f Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-02-22 23:06:40 +05:00
s809 40962ec9ba Use separate build caches 2024-02-15 19:22:29 +00:00
s809 0515ac2919 Fix immersive portals 2024-02-15 23:15:11 +05:00
s809 8072695391 Fix connection exception handling 2024-02-13 22:26:24 +05:00
s809 2c140bf7d7 Fix compilation 2024-02-12 21:39:52 +05:00
s809 d3e88b40f4 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-02-12 21:39:04 +05:00
s809 5e0e15777c Add another config option
Fix rate limiting issues (kinda)
2024-02-11 19:39:42 +05:00
s809 b57fc5c9aa Fix compilation 2024-02-08 20:44:46 +05:00
s809 91ea68075e Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-02-08 20:39:21 +05:00
s809 0840ec8b00 Update core 2024-02-07 21:03:48 +05:00
s809 d9f37ad7d6 Fix compilation 2024-02-07 21:03:37 +05:00
s809 992a7129e5 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-02-07 20:50:06 +05:00
s809 1d5ea329de Remove unused packets 2024-02-04 21:58:01 +05:00
s809 00d0a0d2fc Fix queue not filled when generation is toggled 2024-02-04 21:00:06 +05:00
s809 95d4314982 Merge remote-tracking branch 'origin/main' 2024-02-04 02:36:31 +05:00
s809 b588b937ea Update core 2024-02-04 02:35:30 +05:00
s809 f524ad027e Fix editorconfig 2024-02-03 22:38:27 +05:00
s809 b3111b9548 Update core 2024-02-02 05:57:32 +00:00
s809 6c38cb3dee Limit rate+concurrency instead of only concurrency
Rename post-relog update to Login sync
2024-01-29 22:36:21 +05:00
s809 d75b2dfc1c Update core 2024-01-28 22:40:43 +05:00
s809 a5b44d65c6 Change retry a bit 2024-01-28 22:40:36 +05:00
s809 7a1c61405c Retry failed jobs 2024-01-27 19:48:58 +05:00
s809 bcb8794d30 Post-relog updates 2024-01-27 19:45:38 +05:00
s809 f9775b115e Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-01-21 17:20:55 +05:00
s809 a56a2c2ba3 Fix compilation on <1.18.2 2024-01-16 20:28:48 +05:00
s809 b2efb33a5b Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-01-16 20:20:31 +05:00
s809 5928cfe4b4 Fix compilation 2024-01-16 20:18:32 +05:00
s809 234204590f Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-01-16 20:17:48 +05:00
s809 e3838c560a Fix Neoforge compilation 2024-01-13 20:36:12 +05:00
s809 6cbc9db1d8 Disable API and pages compilation 2024-01-13 20:32:25 +05:00
s809 127dcfcb46 Fix generation 2024-01-13 19:44:54 +05:00
s809 d1abdd822d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-01-13 16:53:04 +05:00
s809 85b7ccb38e Fix crash when changing config while disconnected 2024-01-13 16:11:08 +05:00
s809 fc157b738e Remove Netty from jar and use one from MC instead 2024-01-13 16:11:08 +05:00
s809 977afffe98 Merge branch 'main' of https://gitlab.com/s809/minecraft-lod-mod 2024-01-11 23:34:21 +05:00
s809 180b22f21a Fix cast exception on changing dimensions
(I missed the fact that there's a method for obtaining level without weird hoops 💀)
2024-01-11 23:32:34 +05:00
s809 d0330ad62f Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2024-01-08 17:50:10 +05:00
s809 4d22b18f3c Refactor initializer code 2024-01-07 20:25:34 +05:00
s809 df797b240e Fix 1.16.5 and 1.17.1 builds 2024-01-05 22:37:32 +05:00
s809 a50ef86302 Update core 2024-01-05 22:08:50 +05:00
s809 4aede27d75 Forge versions are functional 2024-01-04 17:36:27 +05:00
s809 e616c63ebe [skip ci] Remove unnecessary build line 2024-01-02 21:03:03 +05:00
s809 03ec333a26 Fix forge builds
Server side is not functional yet
2024-01-02 20:47:11 +05:00
s809 27446965db Make 1.16.5 build
Make Netty version specific for each MC version
2023-12-30 21:57:03 +05:00
s809 c6d7313225 Fix fix 2023-12-29 18:42:10 +00:00
s809 160912a17a Fix 1.19.2 build 2023-12-29 21:13:17 +05:00
s809 d408aacbc8 Fix 1.19.2 build 2023-12-29 21:11:19 +05:00
s809 4889287e69 Start porting to previous versions 2023-12-29 20:31:07 +05:00
s809 6acdfabb7f Update core 2023-12-28 18:59:49 +05:00
s809 3c01d00772 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2023-12-28 18:59:15 +05:00
s809 736bb022d2 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2023-12-24 19:16:16 +05:00
s809 e92130d6cc Merge branch 'main' of https://gitlab.com/s809/minecraft-lod-mod 2023-12-21 19:29:38 +05:00
s809 a44dfa92a6 Update core 2023-12-21 19:29:17 +05:00
s809 4c8ee862e5 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2023-12-21 12:25:02 +05:00
s809 73b89fe573 Disable not working versions 2023-12-19 18:37:14 +00:00
s809 fed2600dbe Add protection against hang on shutdown 2023-12-19 23:20:30 +05:00
s809 1d7d94cfec Update core 2023-12-18 23:15:44 +05:00
s809 5577261774 Update wipe script
Update core
2023-12-18 23:11:47 +05:00
s809 bf0f3131a0 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2023-12-18 19:27:24 +05:00
s809 1b98ea59d7 Remove current post-relog update feature 2023-12-18 19:14:05 +05:00
s809 c38efd9d6b Fix 1.20.1 compilation 2023-12-15 22:31:58 +05:00
s809 4889119061 Merge branch 'main' of https://gitlab.com/s809/minecraft-lod-mod 2023-12-15 21:00:54 +05:00
s809 accb2d6af3 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2023-12-15 20:31:50 +05:00
s809 24b426a17b Disable building of forge jars 2023-12-06 17:24:32 +00:00
s809 8c1bccb430 Update core 2023-12-06 22:07:06 +05:00
s809 3cb2a70f4d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2023-12-06 21:17:16 +05:00
s809 a313cb3db1 Fix Double missing from console command argument types 2023-11-29 22:39:16 +05:00
s809 c29c6d1870 Fix configs loading too late on server 2023-11-29 22:25:38 +05:00
s809 b4a64b0c3d Update core 2023-11-28 00:06:48 +05:00
s809 1439ca5c08 Remove unnecessary log 2023-11-26 21:34:07 +05:00
s809 97ad3bc78f Update core 2023-11-25 18:05:02 +05:00
s809 b59d8cff8d Fix command response not displayed in chat 2023-11-25 18:04:53 +05:00
s809 0e93aa4aea Basic chat commands 2023-11-25 17:44:52 +05:00
s809 28f8099777 Dummy chat command 2023-11-23 20:58:47 +05:00
s809 c83b0ae533 Sync core 2023-11-20 17:43:09 +05:00
s809 5ceeebe567 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons 2023-11-19 22:57:14 +05:00
s809 e8db9803be Bandaid fix to prevent duplicate section requests 2023-11-12 17:18:39 +05:00
s809 f009fd41ab Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-11-11 19:20:50 +05:00
s809 9faa3b0a54 Do not update client light on a dedicated server 2023-11-04 16:39:23 +05:00
s809 0e70478dd3 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-11-03 21:23:37 +05:00
s809 309b6c6013 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-10-30 15:26:43 +05:00
s809 f20af18b62 Make post-relog update independent from generation toggle 2023-10-23 23:18:57 +05:00
Steveplays28 7d3329fd98 chore: Add missing language entries for the server networking config 2023-10-20 14:07:59 +02:00
Steveplays28 9a880c3ab1 style: Rename renderDistance to renderDistanceRadius to stay in sync with the main config 2023-10-20 14:03:28 +02:00
Steveplays28 0b247f04b4 fix: Fix getting LOD render distance radius from the config
This config option was renamed recently, to fix LODs not rendering out to the LOD render distance border. Also removed an unused import.
2023-10-20 13:50:03 +02:00
Steveplays28 7f1d664731 Merge branch 'main-upstream'
# Conflicts:
#	coreSubProjects
2023-10-20 13:41:50 +02:00
s809 a2288d740b Fix compilation 2023-10-14 22:13:22 +05:00
s809 958f0347a3 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-10-14 22:09:31 +05:00
s809 859bb2e34e Fix compilation 2023-09-28 23:28:23 +05:00
s809 a2acd08e0d Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-09-28 22:54:51 +05:00
Steveplays28 b986583fc4 Merge branch 'main-upstream'
# Conflicts:
#	coreSubProjects
#	fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java
2023-09-27 14:10:44 +02:00
s809 c6355f96a6 Improve management of frequent real time updates 2023-09-26 22:03:17 +05:00
s809 723d171746 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-09-26 11:40:59 +05:00
s809 63098d8519 Fix unloaded file check 2023-09-24 18:48:18 +05:00
Steveplays28 44b743267b fix: Fix compiling after merge 2023-09-24 11:34:04 +02:00
Steveplays28 720155c408 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	coreSubProjects
2023-09-24 11:28:43 +02:00
Steveplays28 334b487e23 Merge branch 'main-upstream'
# Conflicts:
#	coreSubProjects
#	fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java
2023-09-24 11:26:12 +02:00
s809 6e674f3732 Add gen task rate display 2023-09-24 14:24:38 +05:00
Steveplays28 d130a602d6 Merge remote-tracking branch 'origin/main' 2023-09-23 16:34:08 +02:00
Steveplays28 8d1ff02937 feat: Add config option for server port 2023-09-23 16:33:42 +02:00
s809 15b1603e35 Fix compiling
Remove unused config category
Use pooling when receiving sections
Fix use of real time update config
Fix debug renderer not unregistered on queue close
2023-09-23 15:32:37 +05:00
s809 4ad0a22db7 Update core 2023-09-21 21:05:31 +05:00
s809 35bc1df32c Add config for a few slow features 2023-09-21 21:00:35 +05:00
s809 bb2a1158c2 Move context levels to requests 2023-09-21 10:16:42 +05:00
s809 76f6f6f746 Allow selecting specific IDebugRenderable's for rendering 2023-09-19 21:33:05 +05:00
s809 3b771b5300 Validate response types 2023-09-19 20:19:31 +05:00
s809 9497918e06 Fix chunk updates sent to incomplete connections
Hide useless warns, for cases when listener is not configured yet
2023-09-19 18:58:16 +05:00
s809 e52c5d5c67 Fix chunk updates sent to incomplete connections
Hide useless warns, for cases when listener is not configured yet
2023-09-19 18:57:55 +05:00
s809 1ce4750dfc Fix future id collisions between c<->s
(cause of occasional hangs on disconnection)
Add packet trace logging
2023-09-19 17:28:49 +05:00
s809 2b371340ff Fix compiling 2023-09-18 13:44:25 +05:00
s809 e8d906b407 Update core 2023-09-18 13:25:06 +05:00
s809 572973c69a Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-09-18 13:24:48 +05:00
Steveplays28 9f2d6b9c78 Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	coreSubProjects
2023-09-12 17:35:49 +02:00
s809 54277040e9 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-09-10 12:03:44 +05:00
Steveplays28 bbe333fab7 fix: Fix missing IServerKeyedClientLevel import 2023-09-09 21:03:40 +02:00
Steveplays28 37fed5a924 Merge branch 'main-upstream'
# Conflicts:
#	coreSubProjects
#	forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java
2023-09-09 20:54:59 +02:00
Steveplays28 5fc29334cd Merge branch 'main-upstream'
# Conflicts:
#	coreSubProjects
2023-09-09 14:47:18 +02:00
Steveplays28 9d32e92e0a Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	coreSubProjects
2023-09-08 19:55:04 +02:00
s809 b08ee76a00 Fix compiling 2023-09-07 21:07:20 +05:00
s809 2a4cc6e63d Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-09-07 20:07:42 +05:00
s809 6b2560f98b Add post-rejoin updates 2023-09-02 01:30:54 +05:00
s809 08111d8874 Fix compilation 2023-08-27 19:56:32 +05:00
s809 80f48cd5a4 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-08-27 19:43:13 +05:00
s809 40cd6c1386 Fix loading ClientLevel on server 2023-08-27 18:42:07 +05:00
s809 e9a13dffb8 Update core 2023-08-26 21:34:46 +05:00
s809 22680baad7 Merge branch 'feat/server-updates' 2023-08-24 01:01:48 +05:00
s809 cca480e5d8 Merge branch 'main' of https://gitlab.com/s809/minecraft-lod-mod 2023-08-24 00:03:55 +05:00
s809 249c3423d9 Update core 2023-08-24 00:02:53 +05:00
s809 15cb6468d9 Update core 2023-08-23 23:55:48 +05:00
s809 f24019d648 Update core 2023-08-22 20:42:06 +05:00
s809 733d03c630 test 2023-08-22 20:41:42 +05:00
s809 c3e84648f1 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod into feat/server-updates 2023-08-22 19:12:56 +05:00
Steveplays28 76c33b6b58 fix: Add null check to config GUI when adding a screen change listener 2023-08-22 10:52:18 +02:00
s809 26a947ea13 Incomplete 2023-08-21 22:09:16 +05:00
Steveplays28 91334c0e5c feat: Update rendering block ignores
Barrier blocks, structure void blocks, light blocks, and air blocks now share 2 `HashMap`s that define blocks that should be ignored by the LOD builder.
2023-08-21 03:41:26 +02:00
s809 172b05aeac Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-08-19 23:45:16 +05:00
s809 b84e5ca265 Fix hang when near completion of loading from server
Replace total value with sum of pending+finished requests
2023-08-19 22:21:27 +05:00
s809 20ef5a10fc Fix hang when near completion of loading from server
Replace total value with sum of pending+finished requests
2023-08-19 22:21:01 +05:00
s809 33640fd35d Fix prioritization not working properly 2023-08-19 21:24:40 +05:00
s809 e5f7c5728f Fix prioritization not working properly 2023-08-19 21:22:51 +05:00
Steveplays28 5a9bbf9829 Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	coreSubProjects
2023-08-19 11:42:09 +02:00
Steveplays28 23ca022ee9 Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	coreSubProjects
#	fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java
#	fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java
#	fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/mods/sodium/MixinSodiumRenderer.java
2023-08-18 15:11:59 +02:00
Steveplays28 6c80165523 chore: Remove username from Fabric build script 2023-08-18 15:08:48 +02:00
s809 d598061fa7 Add missing level wrapper argument (and a bunch of null checks) 2023-08-18 15:04:49 +02:00
Steveplays28 02498aa189 fix: Fix index out of bounds errors and LOD pillars
The `BiomeWrapper#equals` and `BlockStateWrapper#equals` methods didn't use the right `LevelWrapper` for serializing the object to compare to, this is now fixed.
2023-08-16 13:25:23 +02:00
Steveplays28 d535f6aa57 fix: Comment out leftover Immersive Portals compat
A bit I didn't notice while making the previous commit.
2023-08-16 11:42:02 +02:00
Steveplays28 933753a38a fix: Comment out Immersive Portals compat
The renderer compat was commented out in upstream, but the rest of the compat wasn't commented out, or lost in a merge.
2023-08-16 11:40:46 +02:00
Steveplays28 5483cdbc51 refactor: Update to Sodium 0.5.1
This reverts commits 815aed53 and 21144a7c.
2023-08-15 16:18:05 +02:00
Steveplays28 1ea62fd5ec Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java
#	coreSubProjects
#	fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java
#	forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java
2023-08-15 15:55:33 +02:00
Steveplays28 aaf0361c50 fix: Fix BlockStateWrapper and Biome serializing to empty strings 2023-08-15 00:03:12 +02:00
Steveplays28 a08feebde0 fix: Fix server trying to access client instance 2023-08-14 19:23:57 +02:00
Steveplays28 f7131fd2ca fix: Fix 1.20.1 compilation 2023-08-14 15:44:45 +02:00
Steveplays28 2100f4a6fe Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java
#	coreSubProjects
2023-08-14 15:40:31 +02:00
Steveplays28 996f097b9d refactor: Re-add old serialization method
This is used by some override methods that don't have access to the level.
These old serialization methods have `FIXME`s so they're easy to find in the future.
2023-08-13 23:18:52 +02:00
Steveplays28 2e1d737268 Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java
#	coreSubProjects
2023-08-13 22:34:07 +02:00
s809 d374870fb7 Generation task prioritization (loaded > unloaded > ungenerated) 2023-08-13 18:59:42 +05:00
s809 5c303df32c Update core 2023-08-13 01:53:45 +05:00
s809 dfc4b51e89 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-08-13 01:53:22 +05:00
s809 765202d582 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-08-08 20:58:21 +05:00
s809 0d2e5adbed Skip version if step failed in buildAll 2023-08-08 20:30:19 +05:00
s809 68e9d64779 Fix compiling (except 1.16.5 & 1.17.1) 2023-08-08 20:25:07 +05:00
s809 b64b44f301 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-08-08 12:48:37 +05:00
s809 8c07bb37f3 Update core 2023-08-05 22:30:50 +05:00
s809 c1f6c2dbbd Split fabric run folder into server and client 2023-08-05 22:30:02 +05:00
s809 2eb1c16837 Add Fabric run configurations 2023-08-05 22:29:09 +05:00
s809 e5fb8477d3 Update core 2023-08-04 22:12:28 +05:00
s809 428cacd262 Update core 2023-08-04 21:52:26 +05:00
s809 76926d38db Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-08-04 21:11:03 +05:00
s809 9fec679b03 Attempt to fix dimension switching 2023-08-01 17:04:40 +05:00
s809 853a1d1490 Update core 2023-08-01 12:55:53 +05:00
s809 01273e31bc Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-07-31 17:43:45 +05:00
s809 ebb4808bdc Avoid losing requests due to concurrency 2023-07-31 17:42:59 +05:00
s809 fd09adb1a7 World generation 2023-07-31 15:24:33 +05:00
s809 82b7b439a4 Update core 2023-07-24 19:16:21 +05:00
s809 f1b3ae120b something 2023-07-24 19:16:05 +05:00
s809 70ee20e817 Implement transferring of missing full data source types 2023-07-24 14:15:03 +05:00
s809 f713d65f9c Update core 2023-07-24 11:01:20 +05:00
s809 c2b98ef694 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-07-24 10:48:28 +05:00
s809 140c9f6a50 Update core 2023-07-24 10:48:14 +05:00
s809 c704d61d03 Update core 2023-07-24 01:46:31 +05:00
s809 aae484fbdf Update core 2023-07-23 23:48:58 +05:00
s809 a546a97e34 Got chunks to generate on server 2023-07-23 20:34:40 +05:00
s809 3ca9d98c05 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-07-23 11:09:07 +05:00
s809 460b73e35c Update core 2023-07-19 22:29:49 +05:00
Steveplays28 8901a191d9 feat: Implement syncing of DhSectionPos for chunk requests/responses 2023-07-19 16:49:31 +02:00
s809 1bbe35c9f1 Update core 2023-07-19 17:41:06 +05:00
s809 f92e957826 Update core 2023-07-19 15:54:45 +05:00
s809 636e6736a3 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-07-19 12:21:35 +05:00
s809 8e29f65815 Update core 2023-07-19 12:19:54 +05:00
s809 a9309078f3 Merge branch 'main' of https://gitlab.com/jeseibel/minecraft-lod-mod 2023-07-16 12:48:39 +05:00
s809 9692e978de Update core 2023-07-16 12:38:49 +05:00
s809 914372b858 Repoint back to fork 2023-07-15 23:12:30 +05:00
227 changed files with 2871 additions and 7476 deletions
+3 -2
View File
@@ -5,6 +5,7 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
end_of_line = crlf
indent_size = 4 indent_size = 4
indent_style = space indent_style = space
insert_final_newline = false insert_final_newline = false
@@ -537,7 +538,7 @@ ij_groovy_wrap_chain_calls_after_dot = false
ij_groovy_wrap_long_lines = false ij_groovy_wrap_long_lines = false
[{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}] [{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}]
indent_size = 4 indent_size = 2
ij_json_array_wrapping = split_into_lines ij_json_array_wrapping = split_into_lines
ij_json_keep_blank_lines_in_code = 0 ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false ij_json_keep_indents_on_empty_lines = false
@@ -687,7 +688,7 @@ ij_markdown_wrap_text_inside_blockquotes = true
ij_toml_keep_indents_on_empty_lines = false ij_toml_keep_indents_on_empty_lines = false
[{*.yaml,*.yml}] [{*.yaml,*.yml}]
indent_size = 4 indent_size = 2
ij_yaml_align_values_properties = do_not_align ij_yaml_align_values_properties = do_not_align
ij_yaml_autoinsert_sequence_marker = true ij_yaml_autoinsert_sequence_marker = true
ij_yaml_block_mapping_on_new_line = false ij_yaml_block_mapping_on_new_line = false
-4
View File
@@ -26,10 +26,6 @@ Merged/
# Folder created by the buildAll scripts # Folder created by the buildAll scripts
buildAllJars/ buildAllJars/
relocate_natives/.venv/
relocate_natives/__pycache__/
relocate_natives/apple-codesign/
# file from notepad++ # file from notepad++
*.bak *.bak
+27 -14
View File
@@ -35,27 +35,40 @@ build:
stage: build stage: build
parallel: parallel:
matrix: matrix:
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21.1", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.8"] - MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21.1"]
script: script:
# this both runs the unit tests and assembles the code # this both runs the unit tests and assembles the code
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
- ./gradlew build -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew build -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
- ./gradlew mergeJars -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew mergeJars -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/merged/* . || true
artifacts: artifacts:
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}" name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths: paths:
- ./*.jar - Merged/*.jar
- quilt/build/libs/*.jar
- fabric/build/libs/*.jar
- forge/build/libs/*.jar
- neoforge/build/libs/*.jar
exclude: exclude:
- ./*-all.jar # TODO: There is a lot of duplicate stuff here, try to maybe make it smaller
- ./*-dev.jar - fabric/build/libs/*-all.jar
- ./*-sources.jar - fabric/build/libs/*-dev.jar
- fabric/build/libs/*-sources.jar
- quilt/build/libs/*-all.jar
- quilt/build/libs/*-dev.jar
- quilt/build/libs/*-sources.jar
- forge/build/libs/*-all.jar
- forge/build/libs/*-dev.jar
- forge/build/libs/*-sources.jar
- neoforge/build/libs/*-all.jar
- neoforge/build/libs/*-dev.jar
- neoforge/build/libs/*-sources.jar
expire_in: 14 days expire_in: 14 days
when: always when: always
extends: .build_java extends: .build_java
api: .api:
stage: api stage: api
needs: [] needs: []
script: script:
@@ -64,22 +77,22 @@ api:
# this also runs unit tests # this also runs unit tests
- ./gradlew api:build --gradle-user-home cache/; - ./gradlew api:build --gradle-user-home cache/;
- ./gradlew api:addSourcesToCompiledJar --gradle-user-home cache/; - ./gradlew api:addSourcesToCompiledJar --gradle-user-home cache/;
- cp ./coreSubProjects/api/build/libs/merged/* .
artifacts: artifacts:
name: "NightlyBuild_Api-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}" name: "Api_NightlyBuild-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths: paths:
- ./*.jar - coreSubProjects/api/build/libs/merged/*.jar
# can be uncommented if we don't want a jar with the source code
# - coreSubProjects/api/build/libs/*.jar
exclude: exclude:
- ./*-all.jar - coreSubProjects/api/build/libs/merged/*-all.jar
- ./*-dev.jar - coreSubProjects/api/build/libs/merged/*-sources.jar
- ./*-sources.jar
expire_in: 1 day expire_in: 1 day
when: always when: always
extends: .build_java extends: .build_java
# generate and publish API javadocs # generate and publish API javadocs
pages: .pages:
stage: pages stage: pages
needs: [] needs: []
script: script:
+3 -3
View File
@@ -6,13 +6,13 @@ Or click the checkbox once the issue has been created.
--> -->
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution: 1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
[Problems-and-solutions](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions) [Problems-and-solutions](https://gitlab.com/jeseibel/distant-horizons/-/wikis/2-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
2. [ ] Make sure you are not using any mods on the incompatible list: 2. [ ] Make sure you are not using any mods on the incompatible list:
[Mod support FAQ](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/4-mod-support/Mod-Support) [Mod support FAQ](https://gitlab.com/jeseibel/distant-horizons/-/wikis/2-frequently-asked-questions/4-mod-support/Mod-Support)
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted: 3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
[Issues](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues) [Issues](https://gitlab.com/jeseibel/distant-horizons/-/issues/)
4. [ ] Upload Minecraft's crash report and/or log. \ 4. [ ] Upload Minecraft's crash report and/or log. \
Minecraft crash reports are located in: `.minecraft/crash-reports` \ Minecraft crash reports are located in: `.minecraft/crash-reports` \
+1 -1
View File
@@ -1,4 +1,4 @@
- [ ] Check the existing [feature requests](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues?sort=updated_desc&state=opened&label_name%5B%5D=Feature) to verify that your feature hasn't already been suggested. - [ ] Check the existing [feature requests](https://gitlab.com/jeseibel/distant-horizons/-/issues/?sort=updated_desc&state=opened&label_name%5B%5D=Feature) to verify that your feature hasn't already been suggested.
1. **Describe the feature**: 1. **Describe the feature**:
@@ -1,3 +1,3 @@
1. Check the existing [improvement requests](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues?sort=updated_desc&state=all&label_name%5B%5D=Improvement) to verify that your improvement hasn't already been suggested. 1. Check the existing [improvement requests](https://gitlab.com/jeseibel/distant-horizons/-/issues/?sort=updated_desc&state=all&label_name%5B%5D=Improvement) to verify that your improvement hasn't already been suggested.
2. **Describe the improvement**: 2. **Describe the improvement**:
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [build]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="build" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [clean]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="clean" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [core:build]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="core:build" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [fabric:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="fabric:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [forge:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="forge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [mergeJars]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="mergeJars" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [neoforge:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="neoforge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [test]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="test" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-1
View File
@@ -1 +0,0 @@
Distant Horizons logos © 2024 by Pankakes are licensed under CC BY-SA 4.0
+3 -3
View File
@@ -1,4 +1,4 @@
# <img src="https://gitlab.com/distant-horizons-team/distant-horizons-core/-/raw/main/_Misc%20Files/logo%20files/new/SVG/Distant-Horizons.svg" height="128px"> # <img src="https://gitlab.com/jeseibel/distant-horizons-core/-/raw/main/_Misc%20Files/logo%20files/LOD%20logo%20flat%20-%20with%20boarder.png" width="32"> Distant Horizons
_See farther without turning your game into a slide show._ _See farther without turning your game into a slide show._
<br> <br>
@@ -131,14 +131,14 @@ Prerequisites:
From the File Explorer: From the File Explorer:
1. Download and extract the project zip 1. Download and extract the project zip
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects` 2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `coreSubProjects`
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar) 3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows) 4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
5. Merge the jars with `./gradlew mergeJars` 5. Merge the jars with `./gradlew mergeJars`
6. The compiled jar file will be in the folder `Merged` 6. The compiled jar file will be in the folder `Merged`
From the command line: From the command line:
1. `git clone --recurse-submodules https://gitlab.com/distant-horizons-team/distant-horizons.git` 1. `git clone --recurse-submodules https://gitlab.com/jeseibel/distant-horizons.git`
2. `cd distant-horizons` 2. `cd distant-horizons`
3. `./gradlew assemble` 3. `./gradlew assemble`
4. `./gradlew mergeJars` 4. `./gradlew mergeJars`
+46 -102
View File
@@ -1,11 +1,3 @@
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import org.apache.tools.zip.ZipEntry
import javax.annotation.Nonnull
import org.apache.tools.zip.ZipOutputStream
plugins { plugins {
id "java" id "java"
@@ -13,13 +5,13 @@ plugins {
id "com.github.johnrengelman.shadow" version '8.1.1' apply false id "com.github.johnrengelman.shadow" version '8.1.1' apply false
// Plugin to create merged jars // Plugin to create merged jars
id "io.github.pacifistmc.forgix" version "1.3.4" id "io.github.pacifistmc.forgix" version "1.2.9"
// Manifold preprocessor // Manifold preprocessor
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha" id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
// Architectury is used here only as a replacement for forge's own loom // Architectury is used here only as a replacement for forge's own loom
id "dev.architectury.loom" version "1.10-SNAPSHOT" apply false id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
} }
@@ -67,64 +59,38 @@ project.gradle.ext.getProperties().each { prop ->
// Sets up manifold stuff // Sets up manifold stuff
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex) writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
// Sets up the version string (the name we use for our jar) // Sets up the version string (the name we use for our jar)
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm") rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
// Forgix settings (used for merging jars)
forgix {
group = "com.seibel.distanthorizons"
mergedJarName = "DistantHorizons-${rootProject.versionStr}.jar"
class NativeTransformer implements Transformer { if (findProject(":forge"))
private final HashMap<String, String> replacements = new HashMap() forge {
private final HashMap<String, byte[]> rewrittenFiles = new HashMap() jarLocation = "build/libs/DistantHorizons-forge-${rootProject.versionStr}.jar"
private var nativeRelocator
public File rootDir
void relocateNative(String target, String replacement) {
if (replacement.length() > target.length()) {
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
} }
replacements.put(target, replacement) if (findProject(":neoforge"))
} custom {
projectName = "neoforge"
@Override jarLocation = "build/libs/DistantHorizons-neoforge-${rootProject.versionStr}.jar"
boolean canTransformResource(@Nonnull FileTreeElement element) {
return replacements.keySet().stream().anyMatch {
element.name.startsWith(it as String)
}
}
@Override
void transform(@Nonnull TransformerContext context) {
byte[] content = context.is.readAllBytes()
if (nativeRelocator == null) {
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
} }
try { if (findProject(":fabric"))
Map.Entry<String, String> pathReplacement = replacements.entrySet().stream().filter { fabric {
context.path.startsWith(it.key as String) jarLocation = "build/libs/DistantHorizons-fabric-${rootProject.versionStr}.jar"
}.findFirst().orElseThrow()
String path = context.path.replace(pathReplacement.key as String, pathReplacement.value as String)
content = nativeRelocator.processBinary(path, content, replacements)
rewrittenFiles.put(path, content)
} }
catch (Throwable e) {
throw new GradleException("Failed to relocate", e)
}
}
@Override if (findProject(":quilt"))
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() } quilt {
jarLocation = "build/libs/DistantHorizons-quilt-${rootProject.versionStr}.jar"
@Override
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
os.putNextEntry(new ZipEntry(rewrittenFile.key))
os.write(rewrittenFile.value)
} }
}
removeDuplicate "com.seibel.distanthorizons"
} }
subprojects { p -> subprojects { p ->
@@ -193,7 +159,6 @@ subprojects { p ->
if (findProject(":neoforge")) if (findProject(":neoforge"))
developmentNeoForge.extendsFrom coreProjects developmentNeoForge.extendsFrom coreProjects
// TODO remove unused fabricLike
if (findProject(":fabricLike") && p != project(":fabricLike")) { if (findProject(":fabricLike") && p != project(":fabricLike")) {
// Shadow fabricLike // Shadow fabricLike
fabricLike fabricLike
@@ -216,19 +181,10 @@ subprojects { p ->
} }
// Log4j // Log4j
if (p == project(":core")) // TODO: Change to shadowMe later to work in the standalone jar
{ // We cannot do this now as it would break Quilt
// the standalone core jar needs logging shaded otherwise it won't run implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
forgeShadowMe("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}") implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
forgeShadowMe("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
}
else
{
// When running in MC, MC already includes logging
implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
}
// JOML // JOML
if (project.hasProperty("embed_joml") && embed_joml == "true") if (project.hasProperty("embed_joml") && embed_joml == "true")
@@ -246,8 +202,6 @@ subprojects { p ->
// We cannot relocate this library since we call some MC classes that reference it // We cannot relocate this library since we call some MC classes that reference it
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}") implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
//forgeShadowMe("com.github.luben:zstd-jni:1.5.7-3")
//forgeShadowMe("org.apache.commons:commons-compress:1.27.1")
// Compression // Compression
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4 forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
@@ -337,23 +291,9 @@ subprojects { p ->
// Compression (LZ4) // Compression (LZ4)
relocate "net.jpountz", "${librariesLocation}.jpountz" relocate "net.jpountz", "${librariesLocation}.jpountz"
// Logging
relocate "org.slf4j", "${librariesLocation}.slf4j"
// Sqlite Database // Sqlite Database
// librariesLocation isn't used because it's too long for replacing paths in native libraries //At the moment, there is a bug in this library which doesnt allow it to be relocated
// Allowing strings larger than the original string would require shifting the entire binary's contents // relocate "org.sqlite", "${librariesLocation}.sqlite"
relocate "org.sqlite", "dh_sqlite", {
exclude "org/sqlite/native/**"
}
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
transform(NativeTransformer) {
rootDir = project.rootDir
relocateNative "org/sqlite", "dh_sqlite"
relocateNative "org_sqlite", "dh_1sqlite"
}
// JOML // JOML
if (project.hasProperty("embed_joml") && embed_joml == "true") if (project.hasProperty("embed_joml") && embed_joml == "true")
@@ -389,7 +329,7 @@ subprojects { p ->
"META-INF/neoforge.mods.toml", "META-INF/neoforge.mods.toml",
// The mixins for each of the loaders // The mixins for each of the loaders
"DistantHorizons."+ p.name +".fabricLike.mixins.json" "DistantHorizons." + p.name + ".fabricLike.mixins.json"
] ]
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
@@ -446,9 +386,7 @@ subprojects { p ->
info_build_source : infoBuildSource, info_build_source : infoBuildSource,
fabric_incompatibility_list : fabric_incompatibility_list, fabric_incompatibility_list : fabric_incompatibility_list,
fabric_recommend_list : fabric_recommend_list, fabric_recommend_list : fabric_recommend_list,
neoforge_version_range : neoforge_version_range,
] ]
// replace any properties in the sub-projects with the values defined here // replace any properties in the sub-projects with the values defined here
@@ -496,8 +434,7 @@ subprojects { p ->
attributes( attributes(
'Implementation-Title': rootProject.mod_name, 'Implementation-Title': rootProject.mod_name,
'Implementation-Version': rootProject.mod_version, 'Implementation-Version': rootProject.mod_version,
'Multi-Release': true, // needed for logging in the standalone core jar 'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain', // When changing the main of the jar change this line
) )
} }
} }
@@ -529,9 +466,8 @@ allprojects { p ->
apply plugin: "java" apply plugin: "java"
apply plugin: "maven-publish" apply plugin: "maven-publish"
// Sets the name of the jar, the version will contain the name of the project if it isn't the root project
archivesBaseName = rootProject.mod_name archivesBaseName = rootProject.mod_name
version = (project == rootProject ? "" : project.name + "-") + rootProject.versionStr version = project.name + "-" + rootProject.versionStr
group = rootProject.maven_group group = rootProject.maven_group
// this is the text that appears at the top of the overview (home) page // this is the text that appears at the top of the overview (home) page
@@ -553,9 +489,6 @@ allprojects { p ->
repositories { repositories {
// Mojang overrides (added to fix downloading the wrong LWJGL libs on M1 Mac's and potentially other arm64 based machines)
maven { url "https://libraries.minecraft.net/" }
// The central repo // The central repo
mavenCentral() mavenCentral()
@@ -563,7 +496,6 @@ allprojects { p ->
maven { url "https://repo.enonic.com/public/" } maven { url "https://repo.enonic.com/public/" }
// For parchment mappings // For parchment mappings
// versions can be found here: https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/
maven { url "https://maven.parchmentmc.org" } maven { url "https://maven.parchmentmc.org" }
// For Architectury API // For Architectury API
@@ -685,6 +617,7 @@ allprojects { p ->
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
if (isMinecraftSubProject) { if (isMinecraftSubProject) {
options.release = rootProject.java_version as Integer options.release = rootProject.java_version as Integer
options.compilerArgs += ["-Xplugin:Manifold"]
} else { } else {
options.release = 8; // Core & Api should use Java 8 no matter what options.release = 8; // Core & Api should use Java 8 no matter what
//options.release = rootProject.java_version as Integer // But if you want to test some stuff, then this can be enabled //options.release = rootProject.java_version as Integer // But if you want to test some stuff, then this can be enabled
@@ -696,3 +629,14 @@ allprojects { p ->
withSourcesJar() withSourcesJar()
} }
} }
// Delete the merged folder when running clean
task cleanMergedJars() {
def mergedFolder = file("Merged")
if (mergedFolder.exists()) {
delete(mergedFolder)
}
}
// add cleanMergedJars to the end of the "clean" task
tasks["clean"].finalizedBy(cleanMergedJars)
+1 -1
View File
@@ -24,5 +24,5 @@ for d in versionProperties/*; do
if [ $? != 0 ]; then continue; fi if [ $? != 0 ]; then continue; fi
echo "==================== Moving jar ====================" echo "==================== Moving jar ===================="
mv build/merged/*.jar buildAllJars/ mv Merged/*.jar buildAllJars/
done done
+6 -10
View File
@@ -5,7 +5,6 @@
echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ==================== echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ====================
mkdir buildAllJars mkdir buildAllJars
del buildAllJars/*
@rem Loop trough everything in the version properties folder @rem Loop trough everything in the version properties folder
for %%f in (versionProperties\*) do ( for %%f in (versionProperties\*) do (
@@ -14,16 +13,13 @@ for %%f in (versionProperties\*) do (
@rem Clean out the folders, build it, and merge it @rem Clean out the folders, build it, and merge it
echo ==================== Cleaning workspace to build !version! ==================== echo ==================== Cleaning workspace to build !version! ====================
call .\gradlew.bat clean call .\gradlew.bat clean -PmcVer="!version!" --no-daemon
echo ==================== Building !version! ====================
echo ==================== Building !version! ==================== call .\gradlew.bat build -PmcVer="!version!" --no-daemon
call .\gradlew.bat build -PmcVer="!version!" echo ==================== Merging !version! ====================
call .\gradlew.bat mergeJars -PmcVer="!version!" --no-daemon
echo ==================== Merging !version! ====================
call .\gradlew.bat mergeJars -PmcVer="!version!"
echo ==================== Moving jar ==================== echo ==================== Moving jar ====================
move build\merged\*.jar buildAllJars\ move Merged\*.jar buildAllJars\
) )
endlocal endlocal
-211
View File
@@ -1,211 +0,0 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
class NativeRelocator
{
private final Path rootDirectory;
private final Path cacheRoot;
/**
* Initializes the NativeRelocator by preparing the environment if necessary.
* Executes the appropriate preparation script based on the OS.
*/
NativeRelocator(Path rootDirectory)
{
this.rootDirectory = rootDirectory;
this.cacheRoot = this.rootDirectory.resolve("cache");
}
private void prepare() throws Exception
{
if (this.rootDirectory.resolve(".venv").toFile().exists())
{
return;
}
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(this.rootDirectory.toFile());
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win"))
{
processBuilder.command("powershell", "-ExecutionPolicy", "Bypass", "./prepare.ps1");
}
else if (os.contains("nix") || os.contains("nux") || os.contains("mac"))
{
processBuilder.command("./prepare.sh");
}
else
{
throw new IllegalStateException("Unsupported operating system: " + os);
}
Process process = processBuilder.start();
CompletableFuture<Void> outputFuture = readOutputStreams(process);
int exitCode = process.waitFor();
outputFuture.get();
if (exitCode != 0)
{
throw new Exception("Prepare failed: " + exitCode);
}
}
/**
* Reads and prints the output and error streams of a process asynchronously.
*
* @param process The process whose streams should be read.
* @return A CompletableFuture that completes once all output has been processed.
*/
private static CompletableFuture<Void> readOutputStreams(Process process)
{
return CompletableFuture.runAsync(() -> {
try
{
while (process.isAlive() || process.getInputStream().available() > 0 || process.getErrorStream().available() > 0)
{
if (process.getInputStream().available() > 0)
{
byte[] data = new byte[process.getInputStream().available()];
//noinspection ResultOfMethodCallIgnored
process.getInputStream().read(data);
System.out.write(data);
}
if (process.getErrorStream().available() > 0)
{
byte[] data = new byte[process.getErrorStream().available()];
//noinspection ResultOfMethodCallIgnored
process.getErrorStream().read(data);
System.err.write(data);
}
//noinspection BusyWait
Thread.sleep(100);
}
}
catch (Throwable ignored)
{
}
});
}
/**
* Replaces occurrences of a target string in a byte array, ensuring null termination.
*
* @param byteArray The byte array where replacements should occur.
* @param target The string to replace.
* @param replacement The replacement string (must not be longer than the target).
* @throws IllegalArgumentException if the replacement is longer than the target.
*/
private void replaceInNullTerminatedStrings(byte[] byteArray, String target, String replacement)
{
if (target.length() < replacement.length())
{
throw new IllegalArgumentException("Replacement must be the same length or shorter than the target.");
}
byte[] targetBytes = target.getBytes(StandardCharsets.US_ASCII);
byte[] replacementBytes = replacement.getBytes(StandardCharsets.US_ASCII);
byte nullByte = 0;
for (int endPos = 0; endPos < byteArray.length - targetBytes.length - 1; endPos++)
{
int startPos = endPos;
int targetPos = 0;
while (targetPos < targetBytes.length && byteArray[endPos] == targetBytes[targetPos])
{
targetPos++;
endPos++;
}
if (targetPos == targetBytes.length)
{
System.arraycopy(replacementBytes, 0, byteArray, startPos, replacementBytes.length);
startPos = startPos + replacementBytes.length;
while (byteArray[endPos] != nullByte)
{
byteArray[startPos] = byteArray[endPos];
endPos++;
startPos++;
}
byteArray[startPos] = nullByte;
}
}
}
/**
* Runs an external script to fix a modified binary and returns the processed content.
*
* @param outputFilePath Path to store the processed binary.
* @param content The original binary content.
* @return The modified binary content.
* @throws Exception if the process execution fails.
*/
public byte[] fixModifiedBinary(Path outputFilePath, byte[] content) throws Exception
{
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(this.rootDirectory.toFile());
processBuilder.command(
this.rootDirectory.resolve(".venv/Scripts").toFile().exists()
? this.rootDirectory.resolve(".venv/Scripts/python.exe").toString()
: this.rootDirectory.resolve(".venv/bin/python").toString(),
"./fix_modified_binary.py",
outputFilePath.toString()
);
Process process = processBuilder.start();
CompletableFuture<Void> outputFuture = readOutputStreams(process);
process.getOutputStream().write(content);
process.getOutputStream().close();
int exitCode = process.waitFor();
outputFuture.get();
if (exitCode != 0)
{
throw new Exception("Process failed: " + exitCode);
}
return Files.readAllBytes(outputFilePath);
}
/**
* Processes a binary file, applying string replacements and fixing modifications.
*
* @param outputPath The output file path relative to the cache directory.
* @param content The binary content to process.
* @param replacements A map of string replacements to apply.
* @return The modified binary content.
* @throws Exception if processing fails.
*/
public byte[] processBinary(String outputPath, byte[] content, Map<String, String> replacements) throws Exception
{
Path outputFilePath = this.cacheRoot.resolve(outputPath);
//noinspection ResultOfMethodCallIgnored
outputFilePath.getParent().toFile().mkdirs();
if (outputFilePath.toFile().exists())
{
return Files.readAllBytes(outputFilePath);
}
System.out.println("Relocating to " + outputPath + "...");
this.prepare();
for (Map.Entry<String, String> replacement : replacements.entrySet())
{
this.replaceInNullTerminatedStrings(content, replacement.getKey(), replacement.getValue());
}
return this.fixModifiedBinary(outputFilePath, content);
}
}
+7 -3
View File
@@ -1,11 +1,16 @@
buildscript {
configurations.configureEach {
resolutionStrategy {
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
}
}
}
// temporary fix for broken spongepowered version // temporary fix for broken spongepowered version
buildscript { buildscript {
configurations.configureEach { configurations.configureEach {
resolutionStrategy { resolutionStrategy {
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82' force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
// newer versions can be found by going to the link:
// https://repo.spongepowered.org/#browse/browse:maven-public:org%2Fspongepowered%2Fvanillagradle%2F0.2.1-SNAPSHOT
} }
} }
} }
@@ -38,4 +43,3 @@ publishing {
// Add repositories to publish to here. // Add repositories to publish to here.
} }
} }
@@ -1,21 +1,30 @@
package com.seibel.distanthorizons.common; package com.seibel.distanthorizons.common;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
import com.seibel.distanthorizons.common.commands.CommandInitializer;
import com.seibel.distanthorizons.common.wrappers.DependencySetup; import com.seibel.distanthorizons.common.wrappers.DependencySetup;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase; import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler; import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
import com.seibel.distanthorizons.core.config.types.AbstractConfigType;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.ModJarInfo; import com.seibel.distanthorizons.core.jar.ModJarInfo;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
import com.seibel.distanthorizons.core.util.objects.Pair;
import com.seibel.distanthorizons.core.world.DhServerWorld;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
@@ -26,9 +35,25 @@ import net.minecraft.server.dedicated.DedicatedServer;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.util.HashMap;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_ENABLE_CODEC_CRASH_MESSAGE;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
#if MC_VER >= MC_1_19_2
import net.minecraft.network.chat.Component;
#else // < 1.19.2
import net.minecraft.network.chat.TranslatableComponent;
#endif
/** /**
* Base for all mod loader initializers * Base for all mod loader initializers
* and handles most setup. * and handles most setup.
@@ -37,7 +62,7 @@ public abstract class AbstractModInitializer
{ {
protected static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); protected static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
private CommandInitializer commandInitializer; private CommandDispatcher<CommandSourceStack> commandDispatcher;
@@ -66,22 +91,22 @@ public abstract class AbstractModInitializer
{ {
DependencySetup.createClientBindings(); DependencySetup.createClientBindings();
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " client, firing DhApiBeforeDhInitEvent..."); LOGGER.info("Initializing " + ModInfo.READABLE_NAME);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
this.startup(); this.startup();
this.logBuildInfo(); this.printModInfo();
this.createClientProxy().registerEvents(); this.createClientProxy().registerEvents();
this.createServerProxy(false).registerEvents(); this.createServerProxy(false).registerEvents();
this.initializeModCompat(); this.initializeModCompat();
LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
// Client uses config for auto-updater, so it's initialized here instead of post-init stage // Client uses config for auto-updater, so it's initialized here instead of post-init stage
this.initConfig(); this.initConfig();
logModIncompatibilityWarnings(); // needs to be called after config loading
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
this.subscribeClientStartedEvent(this::postInit); this.subscribeClientStartedEvent(this::postInit);
} }
@@ -90,11 +115,11 @@ public abstract class AbstractModInitializer
{ {
DependencySetup.createServerBindings(); DependencySetup.createServerBindings();
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " server, firing DhApiBeforeDhInitEvent event..."); LOGGER.info("Initializing " + ModInfo.READABLE_NAME);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
this.startup(); this.startup();
this.logBuildInfo(); this.printModInfo();
// This prevents returning uninitialized Config values, // This prevents returning uninitialized Config values,
// resulting from a circular reference mid-initialization in a static class // resulting from a circular reference mid-initialization in a static class
@@ -105,21 +130,20 @@ public abstract class AbstractModInitializer
this.initializeModCompat(); this.initializeModCompat();
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers..."); LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer = new CommandInitializer(dispatcher); }); this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandDispatcher = dispatcher; });
this.subscribeServerStartingEvent(server -> this.subscribeServerStartingEvent(server ->
{ {
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server; MinecraftDedicatedServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
this.initConfig(); this.initConfig();
this.postInit(); this.postInit();
this.commandInitializer.initCommands(); this.initCommands();
this.checkForUpdates(); LOGGER.info("Dedicated server initialized at " + server.getServerDirectory());
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + server.getServerDirectory());
}); });
} }
@@ -136,17 +160,14 @@ public abstract class AbstractModInitializer
this.createInitialBindings(); this.createInitialBindings();
} }
private void logBuildInfo() private void printModInfo()
{ {
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION); LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
// if the build is stable the branch/commit/etc shouldn't be needed // Useful for dev builds
if (ModInfo.IS_DEV_BUILD) LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
{ LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch); LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
}
} }
protected <T extends IModAccessor> void tryCreateModCompatAccessor(String modId, Class<? super T> accessorClass, Supplier<T> accessorConstructor) protected <T extends IModAccessor> void tryCreateModCompatAccessor(String modId, Class<? super T> accessorClass, Supplier<T> accessorConstructor)
@@ -161,128 +182,146 @@ public abstract class AbstractModInitializer
private void initConfig() private void initConfig()
{ {
ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class, ModInfo.CONFIG_FILE_VERSION); ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class, 2);
Config.completeDelayedSetup(); Config.completeDelayedSetup();
} }
private void checkForUpdates()
{
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get())
{
if (Config.Client.Advanced.AutoUpdater.enableSilentUpdates.get())
{
LOGGER.info("Silent updates are not allowed for dedicated servers; force disabling.");
Config.Client.Advanced.AutoUpdater.enableSilentUpdates.set(false);
}
SelfUpdater.onStart();
}
}
private void postInit() private void postInit()
{ {
LOGGER.info("Running Delayed setup..."); LOGGER.info("Post-Initializing Mod");
this.runDelayedSetup(); this.runDelayedSetup();
LOGGER.info("Delayed setup complete, firing DhApiAfterDhInitEvent event..."); LOGGER.info("Mod Post-Initialized");
// should be fired after all delayed setup so singletons and config can be accessed
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
} }
@SuppressWarnings({"rawtypes", "unchecked"})
private void initCommands()
//==================================//
// mod partial compatibility checks //
//==================================//
/**
* Some mods will work with a few tweaks
* or will partially work but have some known issues we can't solve.
* This method will log (and display to chat if enabled)
* these warnings and potential fixes.
*/
private static void logModIncompatibilityWarnings()
{ {
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get(); LiteralArgumentBuilder<CommandSourceStack> builder = literal("dhconfig")
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class); .requires(source -> source.hasPermission(4));
String startingString = "Partially Incompatible Distant Horizons mod detected: "; for (AbstractConfigType<?, ?> type : ConfigBase.INSTANCE.entries)
// Alex's caves
if (modChecker.isModLoaded("alexscaves"))
{ {
// There've been a few reports about this mod breaking DH at a few different points in time if (!(type instanceof ConfigEntry))
// the fixes for said breakage changes depending on the version so unfortunately
// all we can do is log a warning so the user can handle it.
if (showChatWarnings)
{ {
String message = continue;
// orange text }
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" + //noinspection PatternVariableCanBeUsed
"You may have to change Alex's config for DH to render. "; ConfigEntry configEntry = (ConfigEntry) type;
ClientApi.INSTANCE.showChatMessageNextFrame(message); if (configEntry.getServersideShortName() == null)
{
continue;
} }
LOGGER.warn(startingString + "[Alex's Caves] may require some config changes in order to render Distant Horizons correctly."); Function<
} Function<CommandContext<CommandSourceStack>, Object>,
Command<CommandSourceStack>
> makeConfigUpdater = getter -> c -> {
Object value = getter.apply(c);
// William Wythers' Overhauled Overworld (WWOO) c.getSource().sendSuccess(
if (modChecker.isModLoaded("wwoo")) #if MC_VER >= MC_1_20_1
{ () -> Component.literal("Changed the value of "+configEntry.getServersideShortName()+" to "+value),
// WWOO has a bug with it's world gen that can't be fixed by DH or WWOO #elif MC_VER >= MC_1_19_2
// (at least that is what James learned after talking with WWOO) Component.literal("Changed the value of "+configEntry.getServersideShortName()+" to "+value),
// WWOO will cause grid lines to appear in the world when DH generates the chunks #else
// this might be due to how WWOO uses features for everything when generating new TranslatableComponent("Changed the value of "+configEntry.getServersideShortName()+" to "+value),
// and said features don't always get to the edge of said chunks. #endif
true);
configEntry.set(value);
return 1;
};
String wwooWarning = "LODs generated by DH may have grid lines between sections. Disabling either WWOO or DH's distant generator will fix the problem."; LiteralArgumentBuilder<CommandSourceStack> subcommand = literal(configEntry.getServersideShortName())
.executes(c -> {
#if MC_VER >= MC_1_20_1
c.getSource().sendSuccess(() -> Component.literal("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true);
#elif MC_VER >= MC_1_19_2
c.getSource().sendSuccess(Component.literal("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true);
#else // < 1.19.2
c.getSource().sendSuccess(new TranslatableComponent("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true);
#endif
return 1;
});
if (showChatWarnings) if (Enum.class.isAssignableFrom(configEntry.getType()))
{ {
String message = for (Object choice : configEntry.getType().getEnumConstants())
// orange text {
"\u00A76" + "Distant Horizons: WWOO detected." + "\u00A7r\n" + subcommand.then(
wwooWarning; literal(choice.toString())
ClientApi.INSTANCE.showChatMessageNextFrame(message); .executes(makeConfigUpdater.apply(c -> choice))
);
}
}
else
{
boolean setterAdded = false;
for (java.util.Map.Entry<Class<?>, Pair<Supplier<ArgumentType<?>>, BiFunction<CommandContext<?>, String, ?>>> pair : new HashMap<
Class<?>,
Pair<
Supplier<ArgumentType<?>>,
BiFunction<CommandContext<?>, String, ?>>
>() {{
this.put(Integer.class, new Pair<>(() -> integer((int) configEntry.getMin(), (int) configEntry.getMax()), IntegerArgumentType::getInteger));
this.put(Double.class, new Pair<>(() -> doubleArg((double) configEntry.getMin(), (double) configEntry.getMax()), DoubleArgumentType::getDouble));
this.put(Boolean.class, new Pair<>(BoolArgumentType::bool, BoolArgumentType::getBool));
this.put(String.class, new Pair<>(StringArgumentType::string, StringArgumentType::getString));
}}.entrySet())
{
if (!pair.getKey().isAssignableFrom(configEntry.getType()))
{
continue;
}
subcommand.then(argument("value", pair.getValue().first.get())
.executes(makeConfigUpdater.apply(c -> pair.getValue().second.apply(c, "value"))));
setterAdded = true;
break;
}
if (!setterAdded)
{
throw new RuntimeException("Config type of "+type.getName()+" is not supported: "+configEntry.getType().getSimpleName());
}
} }
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning); builder.then(subcommand);
} }
// Chunky this.commandDispatcher.register(builder);
boolean chunkyPresent = false;
try if (DEBUG_ENABLE_CODEC_CRASH_MESSAGE)
{ {
Class.forName("org.popcraft.chunky.api.ChunkyAPI"); LiteralArgumentBuilder<CommandSourceStack> dhcrash = literal("dhcrash")
chunkyPresent = true; .requires(source -> source.hasPermission(4))
.then(literal("encode")
.executes(c -> {
assert SharedApi.getIDhServerWorld() != null;
((DhServerWorld) SharedApi.getIDhServerWorld()).remotePlayerConnectionHandler
#if MC_VER >= MC_1_19_2
.getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayer())))
#else
.getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayerOrException())))
#endif
.session.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
return 1;
}))
.then(literal("decode")
.executes(c -> {
assert SharedApi.getIDhServerWorld() != null;
((DhServerWorld) SharedApi.getIDhServerWorld()).remotePlayerConnectionHandler
#if MC_VER >= MC_1_19_2
.getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayer())))
#else
.getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayerOrException())))
#endif
.session.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
return 1;
}));
this.commandDispatcher.register(dhcrash);
} }
catch (ClassNotFoundException ignore) { }
if (chunkyPresent)
{
// Chunky can generate chunks faster than DH can process them,
// causing holes in the LODs.
// Generally it's better and faster to use DH's world generator.
String chunkyWarning = "Chunky can cause DH LODs to have holes " +
"since Chunky can generate chunks faster than DH can process them. \n" +
"Using DH's distant generator instead of chunky or increasing DH's CPU thread count can resolve the issue.";
if (showChatWarnings)
{
String message =
// orange text
"\u00A76" + "Distant Horizons: Chunky detected." + "\u00A7r\n" +
chunkyWarning;
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
LOGGER.warn(startingString + "[Chunky] "+ chunkyWarning);
}
} }
@@ -1,12 +1,11 @@
package com.seibel.distanthorizons.common; package com.seibel.distanthorizons.common;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent; import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageEvent;
import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent; import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorEvent;
import com.seibel.distanthorizons.core.network.messages.MessageRegistry; import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage; import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
@@ -16,6 +15,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
@@ -23,7 +23,7 @@ import java.util.Objects;
public abstract class AbstractPluginPacketSender implements IPluginPacketSender public abstract class AbstractPluginPacketSender implements IPluginPacketSender
{ {
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(), private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Common.Logging.logNetworkEvent.get()); () -> Config.Client.Advanced.Logging.logNetworkEvent.get());
#if MC_VER >= MC_1_21_1 #if MC_VER >= MC_1_21_1
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH); public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
@@ -31,39 +31,30 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH); public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
#endif #endif
// "Forge byte" is an unused packet ID. We have our own system which works with all mod loaders,
// so we're just accounting for it by reading the protocol version as a byte instead of a short in Forge, to keep cross-loader compatibility
private final boolean forgeByteInProtocolVersion;
@Override
public AbstractPluginPacketSender() { this(false); } public final void sendPluginPacketServer(IServerPlayerWrapper serverPlayer, NetworkMessage message)
public AbstractPluginPacketSender(boolean forgeByteInProtocolVersion)
{ {
this.forgeByteInProtocolVersion = forgeByteInProtocolVersion; this.sendPluginPacketServer((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
} }
@Override @Override
public final void sendToClient(IServerPlayerWrapper serverPlayer, AbstractNetworkMessage message) public abstract void sendPluginPacketClient(NetworkMessage message);
{ public abstract void sendPluginPacketServer(ServerPlayer serverPlayer, NetworkMessage message);
this.sendToClient((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
}
public abstract void sendToClient(ServerPlayer serverPlayer, AbstractNetworkMessage message);
@Override @Nullable
public abstract void sendToServer(AbstractNetworkMessage message); public static NetworkMessage decodeMessage(FriendlyByteBuf in)
public AbstractNetworkMessage decodeMessage(FriendlyByteBuf in)
{ {
AbstractNetworkMessage message = null; NetworkMessage message = null;
try try
{ {
in.markReaderIndex(); in.markReaderIndex();
int protocolVersion = this.forgeByteInProtocolVersion ? in.readByte() : in.readShort(); int protocolVersion = in.readShort();
if (protocolVersion != ModInfo.PROTOCOL_VERSION) if (protocolVersion != ModInfo.PROTOCOL_VERSION)
{ {
return new IncompatibleMessageInternalEvent(protocolVersion); return new IncompatibleMessageEvent(protocolVersion);
} }
message = MessageRegistry.INSTANCE.createMessage(in.readUnsignedShort()); message = MessageRegistry.INSTANCE.createMessage(in.readUnsignedShort());
@@ -81,10 +72,10 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
in.resetReaderIndex(); in.resetReaderIndex();
LOGGER.error("Failed to decode message", e); LOGGER.error("Failed to decode message", e);
LOGGER.error("Buffer: ["+in+"]"); LOGGER.error("Buffer: {}", in);
LOGGER.error("Buffer contents: ["+ByteBufUtil.hexDump(in)+"]"); LOGGER.error("Buffer contents: [{}]", ByteBufUtil.hexDump(in));
return new ProtocolErrorInternalEvent(e, message, true); return new ProtocolErrorEvent(e, message, true);
} }
finally finally
{ {
@@ -93,19 +84,11 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
} }
} }
public void encodeMessage(FriendlyByteBuf out, AbstractNetworkMessage message) public static void encodeMessage(FriendlyByteBuf out, NetworkMessage message)
{ {
// This is intentionally unhandled, because errors related to this are unlikely to appear in wild // This is intentionally unhandled, because errors related to this are unlikely to appear in wild
Objects.requireNonNull(message); Objects.requireNonNull(message);
out.writeShort(ModInfo.PROTOCOL_VERSION);
if (this.forgeByteInProtocolVersion)
{
out.writeByte(ModInfo.PROTOCOL_VERSION);
}
else
{
out.writeShort(ModInfo.PROTOCOL_VERSION);
}
try try
{ {
@@ -116,9 +99,9 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
catch (Exception e) catch (Exception e)
{ {
LOGGER.error("Failed to encode message", e); LOGGER.error("Failed to encode message", e);
LOGGER.error("Message: ["+message+"]"); LOGGER.error("Message: {}", message);
message.getSession().tryHandleMessage(new ProtocolErrorInternalEvent(e, message, false)); message.getSession().tryHandleMessage(new ProtocolErrorEvent(e, message, false));
// Encode close reason message instead // Encode close reason message instead
out.resetWriterIndex(); out.resetWriterIndex();
@@ -2,23 +2,25 @@ package com.seibel.distanthorizons.common;
#if MC_VER >= MC_1_20_6 #if MC_VER >= MC_1_20_6
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public record CommonPacketPayload(@Nullable AbstractNetworkMessage message) implements CustomPacketPayload public record CommonPacketPayload(
@Nullable NetworkMessage message
) implements CustomPacketPayload
{ {
public static final Type<CommonPacketPayload> TYPE = new Type<>(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE); public static final Type<CommonPacketPayload> TYPE = new Type<>(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE);
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
@NotNull @NotNull
@Override @Override
public Type<? extends CustomPacketPayload> type() { return TYPE; } public Type<? extends CustomPacketPayload> type()
{
return TYPE;
}
public static class Codec implements StreamCodec<FriendlyByteBuf, CommonPacketPayload> public static class Codec implements StreamCodec<FriendlyByteBuf, CommonPacketPayload>
@@ -26,11 +28,15 @@ public record CommonPacketPayload(@Nullable AbstractNetworkMessage message) impl
@NotNull @NotNull
@Override @Override
public CommonPacketPayload decode(@NotNull FriendlyByteBuf in) public CommonPacketPayload decode(@NotNull FriendlyByteBuf in)
{ return new CommonPacketPayload(PACKET_SENDER.decodeMessage(in)); } {
return new CommonPacketPayload(AbstractPluginPacketSender.decodeMessage(in));
}
@Override @Override
public void encode(@NotNull FriendlyByteBuf out, CommonPacketPayload payload) public void encode(@NotNull FriendlyByteBuf out, CommonPacketPayload payload)
{ PACKET_SENDER.encodeMessage(out, payload.message()); } {
AbstractPluginPacketSender.encodeMessage(out, payload.message());
}
} }
@@ -1,102 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import net.minecraft.commands.CommandSourceStack;
#if MC_VER >= MC_1_19_2
import net.minecraft.network.chat.Component;
import java.util.Objects;
#else // < 1.19.2
import net.minecraft.network.chat.TranslatableComponent;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
#endif
/**
* Abstract class providing common functionality for DH's commands.
*/
public abstract class AbstractCommand
{
public abstract LiteralArgumentBuilder<CommandSourceStack> buildCommand();
/**
* Sends a success response to the player with the given text.
*
* @param commandContext The command context to send the response to.
* @param text The text to display in the success message.
* @return 1, indicating that the command was successful.
*/
protected int sendSuccessResponse(CommandContext<CommandSourceStack> commandContext, String text, boolean notifyAdmins)
{
#if MC_VER >= MC_1_20_1
commandContext.getSource().sendSuccess(() -> Component.literal(text), notifyAdmins);
#elif MC_VER >= MC_1_19_2
commandContext.getSource().sendSuccess(Component.literal(text), notifyAdmins);
#else
commandContext.getSource().sendSuccess(new TranslatableComponent(text), notifyAdmins);
#endif
return 1;
}
/**
* Sends a failure response to the player with the given text.
*
* @param commandContext The command context to send the response to.
* @param text The text to display in the failure message.
* @return 1, indicating that the command was successful.
*/
protected int sendFailureResponse(CommandContext<CommandSourceStack> commandContext, String text)
{
#if MC_VER >= MC_1_20_1
commandContext.getSource().sendFailure(Component.literal(text));
#elif MC_VER >= MC_1_19_2
commandContext.getSource().sendFailure(Component.literal(text));
#else
commandContext.getSource().sendFailure(new TranslatableComponent(text));
#endif
return 1;
}
/**
* Gets the server player from a command context.
*
* @param commandContext The command context to get the server player from.
* @return The server player wrapper for the player who sent the command.
*/
protected IServerPlayerWrapper getSourcePlayer(CommandContext<CommandSourceStack> commandContext) #if MC_VER < MC_1_19_2 throws CommandSyntaxException #endif
{
#if MC_VER >= MC_1_19_2
return ServerPlayerWrapper.getWrapper(Objects.requireNonNull(commandContext.getSource().getPlayer()));
#else
return ServerPlayerWrapper.getWrapper(commandContext.getSource().getPlayerOrException());
#endif
}
/**
* Checks if the source of a command is a player.
*
* @param source The source of the command to check.
* @return True if the source is a player, false otherwise.
*/
protected boolean isPlayerSource(CommandSourceStack source)
{
#if MC_VER >= MC_1_19_2
return source.isPlayer();
#else
try
{
source.getPlayerOrException();
return true;
}
catch (CommandSyntaxException e)
{
return false;
}
#endif
}
}
@@ -1,49 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
import static net.minecraft.commands.Commands.literal;
/**
* Initializes commands of the mod.
*/
public class CommandInitializer
{
private final CommandDispatcher<CommandSourceStack> commandDispatcher;
/**
* Constructs a new instance of this class.
*
* @param commandDispatcher The dispatcher to use for registering commands.
*/
public CommandInitializer(CommandDispatcher<CommandSourceStack> commandDispatcher)
{
this.commandDispatcher = commandDispatcher;
}
/**
* Initializes all available commands.
*/
public void initCommands()
{
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
.requires(source -> source.hasPermission(4));
builder.then(new ConfigCommand().buildCommand());
builder.then(new DebugCommand().buildCommand());
builder.then(new PregenCommand().buildCommand());
if (DEBUG_CODEC_CRASH_MESSAGE)
{
builder.then(new CrashCommand().buildCommand());
}
this.commandDispatcher.register(builder);
}
}
@@ -1,154 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.types.AbstractConfigType;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
import net.minecraft.commands.CommandSourceStack;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToIntBiFunction;
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
/**
* Command for managing config.
*/
public class ConfigCommand extends AbstractCommand
{
private static final List<CommandArgumentData<?>> commandArguments = Arrays.asList(
new CommandArgumentData<>(Integer.class, configEntry -> integer(configEntry.getMin(), configEntry.getMax()), IntegerArgumentType::getInteger),
new CommandArgumentData<>(Double.class, configEntry -> doubleArg(configEntry.getMin(), configEntry.getMax()), DoubleArgumentType::getDouble),
new CommandArgumentData<>(Boolean.class, BoolArgumentType::bool, BoolArgumentType::getBool),
new CommandArgumentData<>(String.class, StringArgumentType::string, StringArgumentType::getString)
);
/**
* Builds a command tree.
*/
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
LiteralArgumentBuilder<CommandSourceStack> builder = literal("config");
HashSet<String> addedCommands = new HashSet<>();
for (AbstractConfigType<?, ?> type : ConfigBase.INSTANCE.entries)
{
// Skip non-config entries
if (!(type instanceof ConfigEntry))
{
continue;
}
//noinspection PatternVariableCanBeUsed
ConfigEntry configEntry = (ConfigEntry) type;
if (configEntry.getChatCommandName() == null)
{
continue;
}
if (!addedCommands.add(configEntry.getChatCommandName()))
{
throw new IllegalStateException("Duplicate command name: " + configEntry.getChatCommandName());
}
LiteralArgumentBuilder<CommandSourceStack> subcommand = literal(configEntry.getChatCommandName())
.executes(commandContext -> this.sendSuccessResponse(commandContext,
"\n" +
"Description of §l" + configEntry.getChatCommandName() + "§r:\n" +
"§o" + configEntry.getComment().trim() + "§r\n" +
"§7Config file name: §f" + configEntry.name + "§7, category: §f" + configEntry.category + "\n" +
"\n" +
"Current value of " + configEntry.getChatCommandName() + " is §n" + configEntry.get() + "§r",
false
));
ToIntBiFunction<CommandContext<CommandSourceStack>, Object> updateConfigValue = (commandContext, value) -> {
configEntry.set(value);
return this.sendSuccessResponse(commandContext, "Changed the value of [" + configEntry.getChatCommandName() + "] to [" + value + "]", true);
};
// Enum type needs a special case since enums aren't represented by existing argument type
// and need literals for each individual value
if (Enum.class.isAssignableFrom(configEntry.getType()))
{
for (Object choice : configEntry.getType().getEnumConstants())
{
subcommand.then(
literal(choice.toString())
.executes(c -> updateConfigValue.applyAsInt(c, choice))
);
}
}
else
{
boolean setterAdded = false;
for (CommandArgumentData<?> commandArgumentData : commandArguments)
{
if (!commandArgumentData.argumentClass.isAssignableFrom(configEntry.getType()))
{
continue;
}
subcommand.then(argument("value", commandArgumentData.getArgumentType(configEntry))
.executes(c -> updateConfigValue.applyAsInt(c, commandArgumentData.getValue(c, "value"))));
setterAdded = true;
break;
}
if (!setterAdded)
{
throw new RuntimeException("Config type of " + type.getName() + " is not supported: " + configEntry.getType().getSimpleName());
}
}
builder.then(subcommand);
}
return builder;
}
private static class CommandArgumentData<T>
{
public final Class<T> argumentClass;
public final Function<ConfigEntry<T>, ArgumentType<T>> argumentTypeFunction;
private final BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter;
public CommandArgumentData(Class<T> argumentClass, Supplier<ArgumentType<T>> argumentTypeSupplier, BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter)
{
this(argumentClass, configEntry -> argumentTypeSupplier.get(), valueGetter);
}
public CommandArgumentData(Class<T> argumentClass, Function<ConfigEntry<T>, ArgumentType<T>> argumentTypeFunction, BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter)
{
this.argumentClass = argumentClass;
this.argumentTypeFunction = argumentTypeFunction;
this.valueGetter = valueGetter;
}
public ArgumentType<T> getArgumentType(ConfigEntry<T> configEntry)
{
return this.argumentTypeFunction.apply(configEntry);
}
public T getValue(CommandContext<CommandSourceStack> commandContext, String argumentName)
{
return this.valueGetter.apply(commandContext, argumentName);
}
}
}
@@ -1,44 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
import net.minecraft.commands.CommandSourceStack;
import static net.minecraft.commands.Commands.literal;
public class CrashCommand extends AbstractCommand
{
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
return literal("crash")
.requires(this::isPlayerSource)
.then(literal("encode")
.executes(c -> {
assert SharedApi.getIDhServerWorld() != null;
ServerPlayerState serverPlayerState = SharedApi.getIDhServerWorld().getServerPlayerStateManager()
.getConnectedPlayer(this.getSourcePlayer(c));
if (serverPlayerState != null)
{
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
}
return 1;
}))
.then(literal("decode")
.executes(c -> {
assert SharedApi.getIDhServerWorld() != null;
ServerPlayerState serverPlayerState = SharedApi.getIDhServerWorld().getServerPlayerStateManager()
.getConnectedPlayer(this.getSourcePlayer(c));
if (serverPlayerState != null)
{
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
}
return 1;
}));
}
}
@@ -1,25 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import net.minecraft.commands.CommandSourceStack;
import java.util.ArrayList;
import java.util.List;
import static net.minecraft.commands.Commands.literal;
public class DebugCommand extends AbstractCommand
{
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
return literal("debug")
.executes(c -> {
List<String> lines = new ArrayList<>();
F3Screen.addStringToDisplay(lines);
return this.sendSuccessResponse(c, String.join("\n", lines), false);
});
}
}
@@ -1,107 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.generation.PregenManager;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.DimensionArgument;
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
import net.minecraft.server.level.ColumnPos;
import net.minecraft.server.level.ServerLevel;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
public class PregenCommand extends AbstractCommand
{
private final PregenManager pregenManager = new PregenManager();
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
LiteralArgumentBuilder<CommandSourceStack> statusCommand = literal("status")
.executes(this::pregenStatus);
LiteralArgumentBuilder<CommandSourceStack> startCommand = literal("start")
.then(argument("dimension", DimensionArgument.dimension())
.then(argument("origin", ColumnPosArgument.columnPos())
.then(argument("chunkRadius", integer(32))
.executes(this::pregenStart))));
LiteralArgumentBuilder<CommandSourceStack> stopCommand = literal("stop")
.executes(this::pregenStop);
return literal("pregen")
.then(statusCommand)
.then(startCommand)
.then(stopCommand);
}
private int pregenStatus(CommandContext<CommandSourceStack> c)
{
String statusString = this.pregenManager.getStatusString();
//noinspection ReplaceNullCheck
if (statusString != null)
{
return this.sendSuccessResponse(c, statusString, false);
}
else
{
return this.sendSuccessResponse(c, "Pregen is not running", false);
}
}
private int pregenStart(CommandContext<CommandSourceStack> c) throws CommandSyntaxException
{
this.sendSuccessResponse(c, "Starting pregen. Progress will be in the server console.", true);
ServerLevel level = DimensionArgument.getDimension(c, "dimension");
ColumnPos origin = ColumnPosArgument.getColumnPos(c, "origin");
int chunkRadius = getInteger(c, "chunkRadius");
CompletableFuture<Void> future = this.pregenManager.startPregen(
ServerLevelWrapper.getWrapper(level),
new DhBlockPos2D(#if MC_VER >= MC_1_19_2 origin.x(), origin.z() #else origin.x, origin.z #endif),
chunkRadius
);
future.whenComplete((result, throwable) -> {
if (throwable instanceof CancellationException)
{
this.sendSuccessResponse(c, "Pregen is cancelled", true);
return;
}
else if (throwable != null)
{
this.sendFailureResponse(c, "Pregen failed: " + throwable.getMessage() + "\n Check the logs for more details.");
return;
}
this.sendSuccessResponse(c, "Pregen is complete", true);
});
return 1;
}
private int pregenStop(CommandContext<CommandSourceStack> c)
{
CompletableFuture<Void> runningPregen = this.pregenManager.getRunningPregen();
if (runningPregen == null)
{
return this.sendFailureResponse(c, "Pregen is not running");
}
runningPregen.cancel(true);
return 1;
}
}
@@ -77,7 +77,7 @@ public class MixinChunkMapCommon
// submit the update event // submit the update event
ServerApi.INSTANCE.serverChunkSaveEvent( ServerApi.INSTANCE.serverChunkSaveEvent(
new ChunkWrapper(chunk, ServerLevelWrapper.getWrapper(level)), new ChunkWrapper(chunk, level, ServerLevelWrapper.getWrapper(level)),
ServerLevelWrapper.getWrapper(level) ServerLevelWrapper.getWrapper(level)
); );
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -22,8 +22,7 @@ package com.seibel.distanthorizons.common.wrappers;
import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI; import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI;
import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper; import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper;
import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager; import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui; import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
@@ -33,7 +32,6 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
@@ -62,7 +60,7 @@ public class DependencySetup
//@Environment(EnvType.SERVER) //@Environment(EnvType.SERVER)
public static void createServerBindings() public static void createServerBindings()
{ {
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftServerWrapper.INSTANCE); SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftDedicatedServerWrapper.INSTANCE);
} }
//@Environment(EnvType.CLIENT) //@Environment(EnvType.CLIENT)
@@ -71,7 +69,6 @@ public class DependencySetup
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE); SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE); SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE); SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IMinecraftGLWrapper.class, MinecraftGLWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE); SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -25,12 +25,7 @@ public class DependencySetupDoneCheck
{ {
// TODO move to DependencySetup // TODO move to DependencySetup
public static boolean isDone = false; public static boolean isDone = false;
/** // TODO why is this here and what is its purpose?
* This is used so we can override some MC logic when running
* in DH's world generator.
* Specifically so we can redirect threads to run on DH threads instead
* of MC threads.
*/
public static Supplier<Boolean> getIsCurrentThreadDistantGeneratorThread = (() -> { return false; }); public static Supplier<Boolean> getIsCurrentThreadDistantGeneratorThread = (() -> { return false; });
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -49,9 +49,7 @@ public class McObjectConverter
@Deprecated @Deprecated
public static Mat4f Convert( public static Mat4f Convert(
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f #if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f #else org.joml.Matrix4f #endif
#else org.joml.Matrix4fc
#endif
mcMatrix) mcMatrix)
{ {
FloatBuffer buffer = FloatBuffer.allocate(16); FloatBuffer buffer = FloatBuffer.allocate(16);
@@ -65,9 +63,7 @@ public class McObjectConverter
/** Taken from Minecraft's com.mojang.math.Matrix4f class from 1.18.2 */ /** Taken from Minecraft's com.mojang.math.Matrix4f class from 1.18.2 */
private static void storeMatrix( private static void storeMatrix(
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f #if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f #else org.joml.Matrix4f #endif
#else org.joml.Matrix4fc
#endif
matrix, matrix,
FloatBuffer buffer) FloatBuffer buffer)
{ {
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -20,6 +20,8 @@
package com.seibel.distanthorizons.common.wrappers; package com.seibel.distanthorizons.common.wrappers;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
/** /**
* @author James Seibel * @author James Seibel
@@ -36,52 +38,32 @@ public class VersionConstants implements IVersionConstants
} }
@Override
public int getMinimumWorldHeight()
{
return 0;
}
@Override
public int getWorldGenerationCountPerThread()
{
return 1;
}
@Override
public boolean isVanillaRenderedChunkSquare()
{
return false;
}
@Override @Override
public String getMinecraftVersion() public String getMinecraftVersion()
{ {
// these values are hard-coded to prevent an issue with Forge (specifically 1.18.2) where #if MC_VER < MC_1_19_2
// it can't load client classes when running as a dedicated server, return Minecraft.getInstance().getGame().getVersion().getId();
// which was how we were dynamically accessing the MC version string
#if MC_VER == MC_1_16_5
return "1.16.5";
#elif MC_VER == MC_1_17_1
return "1.17.1";
#elif MC_VER == MC_1_18_2
return "1.18.2";
#elif MC_VER == MC_1_19_2
return "1.19.2";
#elif MC_VER == MC_1_19_4
return "1.19.4";
#elif MC_VER == MC_1_20_1
return "1.20.1";
#elif MC_VER == MC_1_20_2
return "1.20.2";
#elif MC_VER == MC_1_20_4
return "1.20.4";
#elif MC_VER == MC_1_20_6
return "1.20.6";
#elif MC_VER == MC_1_21_1
return "1.21.1";
#elif MC_VER == MC_1_21_3
return "1.21.3";
#elif MC_VER == MC_1_21_4
return "1.21.4";
#elif MC_VER == MC_1_21_5
return "1.21.5";
#elif MC_VER == MC_1_21_6
return "1.21.6";
#elif MC_VER == MC_1_21_8
return "1.21.8";
#else #else
ERROR MC version constant missing return SharedConstants.getCurrentVersion().getId();
#endif #endif
} }
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -174,6 +174,8 @@ public class WrapperFactory implements IWrapperFactory
} }
// the level is needed for the DH level wrapper... // the level is needed for the DH level wrapper...
Level level = (Level) objectArray[1]; Level level = (Level) objectArray[1];
// ...the LevelReader is needed for chunk lighting
LevelReader lightSource = level;
// level wrapper // level wrapper
@@ -182,7 +184,7 @@ public class WrapperFactory implements IWrapperFactory
: ServerLevelWrapper.getWrapper((ServerLevel)level); : ServerLevelWrapper.getWrapper((ServerLevel)level);
return new ChunkWrapper(chunk, levelWrapper); return new ChunkWrapper(chunk, lightSource, levelWrapper);
} }
// incorrect number of parameters from the API // incorrect number of parameters from the API
else else
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -22,7 +22,6 @@ package com.seibel.distanthorizons.common.wrappers.block;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@@ -47,7 +46,6 @@ import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.biome.Biomes;
#endif #endif
@@ -131,6 +129,14 @@ public class BiomeWrapper implements IBiomeWrapper
//LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]"); //LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
} }
/** should only be used to create {@link BiomeWrapper#EMPTY_WRAPPER} */
private BiomeWrapper()
{
this.biome = null;
this.serialString = EMPTY_BIOME_STRING;
this.hashCode = Objects.hash(this.serialString);
}
//=========// //=========//
@@ -220,10 +226,8 @@ public class BiomeWrapper implements IBiomeWrapper
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome); resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2 #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value()); resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
#elif MC_VER < MC_1_21_3
resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
#else #else
resourceLocation = registryAccess.lookupOrThrow(Registries.BIOME).getKey(this.biome.value()); resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
#endif #endif
if (resourceLocation == null) if (resourceLocation == null)
@@ -279,16 +283,50 @@ public class BiomeWrapper implements IBiomeWrapper
BiomeWrapper foundWrapper = EMPTY_WRAPPER; BiomeWrapper foundWrapper = EMPTY_WRAPPER;
try try
{ {
// parse the resource location
int separatorIndex = resourceLocationString.indexOf(":");
if (separatorIndex == -1)
{
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
}
ResourceLocation resourceLocation;
try
{
#if MC_VER < MC_1_21_1
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#else
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#endif
}
catch (Exception e)
{
throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
}
try try
{ {
Level level = (Level) levelWrapper.getWrappedMcObject(); Level level = (Level) levelWrapper.getWrappedMcObject();
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
BiomeDeserializeResult deserializeResult = deserializeBiome(resourceLocationString, registryAccess); boolean success;
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (biome != null);
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#else
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#endif
if (!deserializeResult.success) if (!success)
{ {
if (!brokenResourceLocationStrings.contains(resourceLocationString)) if (!brokenResourceLocationStrings.contains(resourceLocationString))
{ {
@@ -299,7 +337,7 @@ public class BiomeWrapper implements IBiomeWrapper
} }
foundWrapper = (BiomeWrapper) getBiomeWrapper(deserializeResult.biome, levelWrapper); foundWrapper = (BiomeWrapper) getBiomeWrapper(biome, levelWrapper);
return foundWrapper; return foundWrapper;
} }
catch (Exception e) catch (Exception e)
@@ -313,82 +351,4 @@ public class BiomeWrapper implements IBiomeWrapper
} }
} }
public static BiomeDeserializeResult deserializeBiome(String resourceLocationString, net.minecraft.core.RegistryAccess registryAccess) throws IOException
{
// parse the resource location
int separatorIndex = resourceLocationString.indexOf(":");
if (separatorIndex == -1)
{
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
}
ResourceLocation resourceLocation;
try
{
#if MC_VER < MC_1_21_1
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#else
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#endif
}
catch (Exception e)
{
throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
}
boolean success;
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (biome != null);
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#elif MC_VER < MC_1_21_3
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#else
Holder<Biome> biome;
Optional<Holder.Reference<Biome>> optionalBiomeHolder = registryAccess.lookupOrThrow(Registries.BIOME).get(resourceLocation);
if (optionalBiomeHolder.isPresent())
{
Biome unwrappedBiome = optionalBiomeHolder.get().value();
success = (unwrappedBiome != null);
biome = new Holder.Direct<>(unwrappedBiome);
}
else
{
success = false;
biome = null;
}
#endif
return new BiomeDeserializeResult(success, biome);
}
//================//
// helper classes //
//================//
public static class BiomeDeserializeResult
{
public final boolean success;
#if MC_VER < MC_1_18_2
public final Biome biome;
#else
public final Holder<Biome> biome;
#endif
public BiomeDeserializeResult(boolean success, #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome)
{
this.success = success;
this.biome = biome;
}
}
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -43,8 +43,6 @@ import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.Nullable;
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@@ -60,7 +58,6 @@ import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.core.Holder;
#endif #endif
public class BlockStateWrapper implements IBlockStateWrapper public class BlockStateWrapper implements IBlockStateWrapper
@@ -86,25 +83,26 @@ public class BlockStateWrapper implements IBlockStateWrapper
public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null; public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
/** keep track of broken blocks so we don't log every time */ /** keep track of broken blocks so we don't log every time */
private static final HashSet<ResourceLocation> BROKEN_RESOURCE_LOCATIONS = new HashSet<>(); private static final HashSet<ResourceLocation> BrokenResourceLocations = new HashSet<>();
// properties // // properties //
@Nullable
public final BlockState blockState; public final BlockState blockState;
/** technically final, but since it requires a method call to generate it can't be marked as such */ /** technically final, but since it requires a method call to generate it can't be marked as such */
private String serialString; private String serialString;
private final int hashCode; private final int hashCode;
/** Should be between {@link LodUtil#BLOCK_FULLY_OPAQUE} and {@link LodUtil#BLOCK_FULLY_OPAQUE} */ /**
private final int opacity; * Cached opacity value, -1 if not populated. <br>
* Should be between {@link LodUtil#BLOCK_FULLY_OPAQUE} and {@link LodUtil#BLOCK_FULLY_OPAQUE}
*/
private int opacity = -1;
/** used by the Iris shader mod to determine how each LOD should be rendered */ /** used by the Iris shader mod to determine how each LOD should be rendered */
private byte blockMaterialId = 0; private byte blockMaterialId = 0;
private final boolean isBeaconBlock; private final boolean isBeaconBlock;
private final boolean isBeaconBaseBlock; private final boolean isBeaconBaseBlock;
private final boolean allowsBeaconBeamPassage;
/** null if this block can't tint beacons */ /** null if this block can't tint beacons */
private final Color beaconTintColor; private final Color beaconTintColor;
private final Color mapColor; private final Color mapColor;
@@ -135,38 +133,15 @@ public class BlockStateWrapper implements IBlockStateWrapper
} }
} }
/**
* Can be faster than {@link BlockStateWrapper#fromBlockState(BlockState, ILevelWrapper)}
* in cases where the same block state is expected to be referenced multiple times.
*/
public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper, IBlockStateWrapper guess)
{
BlockState guessBlockState = (guess == null || guess.isAir()) ? null : (BlockState) guess.getWrappedMcObject();
BlockState inputBlockState = (blockState == null || blockState.isAir()) ? null : blockState;
if (guess instanceof BlockStateWrapper
&& guessBlockState == inputBlockState)
{
return (BlockStateWrapper) guess;
}
else
{
return fromBlockState(blockState, levelWrapper);
}
}
private BlockStateWrapper(BlockState blockState, ILevelWrapper levelWrapper) private BlockStateWrapper(BlockState blockState, ILevelWrapper levelWrapper)
{ {
this.blockState = blockState; this.blockState = blockState;
this.serialString = this.serialize(levelWrapper); this.serialString = this.serialize(levelWrapper);
this.hashCode = Objects.hash(this.serialString); this.hashCode = Objects.hash(this.serialString);
this.blockMaterialId = this.calculateEDhApiBlockMaterialId().index; this.blockMaterialId = this.calculateEDhApiBlockMaterialId().index;
this.opacity = this.calculateOpacity();
String lowercaseSerial = this.serialString.toLowerCase();
// beacon blocks // beacon blocks
String lowercaseSerial = this.serialString.toLowerCase();
boolean isBeaconBaseBlock = false; boolean isBeaconBaseBlock = false;
for (int i = 0; i < LodUtil.BEACON_BASE_BLOCK_NAME_LIST.size(); i++) for (int i = 0; i < LodUtil.BEACON_BASE_BLOCK_NAME_LIST.size(); i++)
{ {
@@ -202,39 +177,6 @@ public class BlockStateWrapper implements IBlockStateWrapper
this.beaconTintColor = beaconTintColor; this.beaconTintColor = beaconTintColor;
// allow/deny beacon beam passage
boolean allowsBeaconBeamPassage;
if (this.blockState != null)
{
// get block properties (defaults to the values used by air)
boolean canOcclude = this.getCanOcclude();
boolean propagatesSkyLightDown = this.getPropagatesSkyLightDown();
if (lowercaseSerial.contains("minecraft:bedrock"))
{
// bedrock is a special case fully opaque block that does allow beacons through
allowsBeaconBeamPassage = true;
}
else if (propagatesSkyLightDown || !canOcclude)
{
// stairs, cake, fences, etc.
allowsBeaconBeamPassage = true;
}
else
{
// non-opaque blocks (glass, mob spawners, etc.)
// all allow beacons through
allowsBeaconBeamPassage = (this.opacity != LodUtil.BLOCK_FULLY_OPAQUE);
}
}
else
{
// air allows beacons through
allowsBeaconBeamPassage = true;
}
this.allowsBeaconBeamPassage = allowsBeaconBeamPassage;
int mcColor = 0; int mcColor = 0;
if (this.blockState != null) if (this.blockState != null)
{ {
@@ -273,7 +215,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
HashSet<String> baseIgnoredBlock = new HashSet<>(); HashSet<String> baseIgnoredBlock = new HashSet<>();
baseIgnoredBlock.add(AIR_STRING); baseIgnoredBlock.add(AIR_STRING);
rendererIgnoredBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper); rendererIgnoredBlocks = getBlockWrappers(Config.Client.Advanced.LodBuilding.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
return rendererIgnoredBlocks; return rendererIgnoredBlocks;
} }
/** /**
@@ -290,7 +232,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
HashSet<String> baseIgnoredBlock = new HashSet<>(); HashSet<String> baseIgnoredBlock = new HashSet<>();
baseIgnoredBlock.add(AIR_STRING); baseIgnoredBlock.add(AIR_STRING);
rendererIgnoredCaveBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper); rendererIgnoredCaveBlocks = getBlockWrappers(Config.Client.Advanced.LodBuilding.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
return rendererIgnoredCaveBlocks; return rendererIgnoredCaveBlocks;
} }
@@ -378,13 +320,13 @@ public class BlockStateWrapper implements IBlockStateWrapper
//=================// //=================//
@Override @Override
public int getOpacity() { return this.opacity; } public int getOpacity()
private int calculateOpacity()
{ {
// get block properties (defaults to the values used by air) // use the cached opacity value if possible
boolean canOcclude = this.getCanOcclude(); if (this.opacity != -1)
boolean propagatesSkyLightDown = this.getPropagatesSkyLightDown(); {
return this.opacity;
}
// this method isn't perfect, but works well enough for our use case // this method isn't perfect, but works well enough for our use case
@@ -393,20 +335,15 @@ public class BlockStateWrapper implements IBlockStateWrapper
{ {
opacity = LodUtil.BLOCK_FULLY_TRANSPARENT; opacity = LodUtil.BLOCK_FULLY_TRANSPARENT;
} }
else if (this.isLiquid() && !canOcclude) else if (this.isLiquid() && !this.blockState.canOcclude())
{ {
// probably not a waterlogged block (which should block light entirely) // probably not a waterlogged block (which should block light entirely)
// +1 to indicate that the block is translucent (in between transparent and opaque) // +1 to indicate that the block is translucent (in between transparent and opaque)
opacity = LodUtil.BLOCK_FULLY_TRANSPARENT + 1; opacity = LodUtil.BLOCK_FULLY_TRANSPARENT + 1;
} }
else if (propagatesSkyLightDown && !canOcclude) else if (this.blockState.propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO))
{ {
// probably glass or some other fully transparent block
// !canOcclude is required to ignore stairs and slabs since
// propagateSkyLightDown is true for them, but they're solid and don't actually let light through
opacity = LodUtil.BLOCK_FULLY_TRANSPARENT; opacity = LodUtil.BLOCK_FULLY_TRANSPARENT;
} }
else else
@@ -416,37 +353,9 @@ public class BlockStateWrapper implements IBlockStateWrapper
} }
return opacity; this.opacity = opacity;
return this.opacity;
} }
private boolean getCanOcclude()
{
// defaults to the value used by air
boolean canOcclude = false;
if (this.blockState != null)
{
canOcclude = this.blockState.canOcclude();
}
return canOcclude;
}
private boolean getPropagatesSkyLightDown()
{
// defaults to the value used by air
boolean propagatesSkyLightDown = true;
if (this.blockState != null)
{
#if MC_VER < MC_1_21_3
propagatesSkyLightDown = this.blockState.propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
#else
propagatesSkyLightDown = this.blockState.propagatesSkylightDown();
#endif
}
return propagatesSkyLightDown;
}
@Override @Override
public int getLightEmission() { return (this.blockState != null) ? this.blockState.getLightEmission() : 0; } public int getLightEmission() { return (this.blockState != null) ? this.blockState.getLightEmission() : 0; }
@@ -486,11 +395,6 @@ public class BlockStateWrapper implements IBlockStateWrapper
@Override @Override
public boolean isSolid() public boolean isSolid()
{ {
if (this.isAir())
{
return false;
}
#if MC_VER < MC_1_20_1 #if MC_VER < MC_1_20_1
return this.blockState.getMaterial().isSolid(); return this.blockState.getMaterial().isSolid();
#else #else
@@ -519,8 +423,6 @@ public class BlockStateWrapper implements IBlockStateWrapper
public boolean isBeaconBaseBlock() { return this.isBeaconBaseBlock; } public boolean isBeaconBaseBlock() { return this.isBeaconBaseBlock; }
@Override @Override
public boolean isBeaconTintBlock() { return this.beaconTintColor != null; } public boolean isBeaconTintBlock() { return this.beaconTintColor != null; }
@Override
public boolean allowsBeaconBeamPassage() { return this.allowsBeaconBeamPassage; }
@Override @Override
public Color getMapColor() { return this.mapColor; } public Color getMapColor() { return this.mapColor; }
@@ -559,10 +461,8 @@ public class BlockStateWrapper implements IBlockStateWrapper
resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock()); resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock());
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2 #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock()); resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock());
#elif MC_VER < MC_1_21_3
resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock());
#else #else
resourceLocation = registryAccess.lookupOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock()); resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock());
#endif #endif
@@ -641,8 +541,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
{ {
#if MC_VER > MC_1_17_1 #if MC_VER > MC_1_17_1
LodUtil.assertTrue(levelWrapper != null && levelWrapper.getWrappedMcObject() != null); Level level = (Level)Objects.requireNonNull(levelWrapper.getWrappedMcObject());
Level level = (Level)levelWrapper.getWrappedMcObject();
#endif #endif
Block block; Block block;
@@ -651,22 +550,18 @@ public class BlockStateWrapper implements IBlockStateWrapper
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2 #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation); block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation);
#elif MC_VER < MC_1_21_3
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation);
#else #else
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
Optional<Holder.Reference<Block>> optionalBlockHolder = registryAccess.lookupOrThrow(Registries.BLOCK).get(resourceLocation); block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation);
block = optionalBlockHolder.isPresent() ? optionalBlockHolder.get().value() : null;
#endif #endif
if (block == null) if (block == null)
{ {
// shouldn't normally happen, but here to make the compiler happy // shouldn't normally happen, but here to make the compiler happy
if (!BROKEN_RESOURCE_LOCATIONS.contains(resourceLocation)) if (!BrokenResourceLocations.contains(resourceLocation))
{ {
BROKEN_RESOURCE_LOCATIONS.add(resourceLocation); BrokenResourceLocations.add(resourceLocation);
LOGGER.warn("Unable to find BlockState with the resourceLocation [" + resourceLocation + "] and properties: [" + blockStatePropertiesString + "]. Air will be used instead, some data may be lost."); LOGGER.warn("Unable to find BlockState with the resourceLocation [" + resourceLocation + "] and properties: [" + blockStatePropertiesString + "]. Air will be used instead, some data may be lost.");
} }
@@ -696,9 +591,9 @@ public class BlockStateWrapper implements IBlockStateWrapper
if (blockStatePropertiesString != null) if (blockStatePropertiesString != null)
{ {
// we should have found a blockstate, but didn't // we should have found a blockstate, but didn't
if (!BROKEN_RESOURCE_LOCATIONS.contains(resourceLocation)) if (!BrokenResourceLocations.contains(resourceLocation))
{ {
BROKEN_RESOURCE_LOCATIONS.add(resourceLocation); BrokenResourceLocations.add(resourceLocation);
LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state."); LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state.");
} }
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -40,18 +40,11 @@ import java.util.Random;
#endif #endif
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
#if MC_VER < MC_1_21_5
#else
import net.minecraft.client.renderer.block.model.BlockModelPart;
#endif
/** /**
* This stores and calculates the colors * This stores and calculates the colors
* the given {@link BlockState} should have based * the given {@link BlockState} should have based
@@ -91,7 +84,7 @@ public class ClientBlockStateColorCache
private static final RandomSource RANDOM = RandomSource.create(); private static final RandomSource RANDOM = RandomSource.create();
#endif #endif
private final IClientLevelWrapper clientLevelWrapper; private final IClientLevelWrapper levelWrapper;
private final BlockState blockState; private final BlockState blockState;
private final LevelReader level; private final LevelReader level;
@@ -174,7 +167,7 @@ public class ClientBlockStateColorCache
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel) public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel)
{ {
this.blockState = blockState; this.blockState = blockState;
this.clientLevelWrapper = samplingLevel; this.levelWrapper = samplingLevel;
this.level = (LevelReader) samplingLevel.getWrappedMcObject(); this.level = (LevelReader) samplingLevel.getWrappedMcObject();
this.resolveColors(); this.resolveColors();
} }
@@ -203,7 +196,9 @@ public class ClientBlockStateColorCache
List<BakedQuad> quads = null; List<BakedQuad> quads = null;
for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER) for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER)
{ {
quads = this.getQuadsForDirection(direction); quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM);
if (quads != null && !quads.isEmpty() if (quads != null && !quads.isEmpty()
&& !( && !(
this.blockState.getBlock() instanceof RotatedPillarBlock this.blockState.getBlock() instanceof RotatedPillarBlock
@@ -217,37 +212,19 @@ public class ClientBlockStateColorCache
if (quads == null || quads.isEmpty()) if (quads == null || quads.isEmpty())
{ {
quads = this.getUnculledQuads(); quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(this.blockState).getQuads(this.blockState, null, RANDOM);
} }
if (quads != null if (quads != null && !quads.isEmpty())
&& !quads.isEmpty()
&& quads.get(0) != null)
{ {
BakedQuad firstQuad = quads.get(0); this.needPostTinting = quads.get(0).isTinted();
this.needShade = quads.get(0).isShade();
this.needPostTinting = firstQuad.isTinted(); this.tintIndex = quads.get(0).getTintIndex();
#if MC_VER <= MC_1_21_4
this.needShade = firstQuad.isShade();
this.tintIndex = firstQuad.getTintIndex();
#else
this.needShade = firstQuad.shade();
this.tintIndex = firstQuad.tintIndex();
#endif
#if MC_VER < MC_1_17_1
this.baseColor = calculateColorFromTexture( this.baseColor = calculateColorFromTexture(
firstQuad.sprite, #if MC_VER < MC_1_17_1 quads.get(0).sprite,
ColorMode.getColorMode(this.blockState.getBlock())); #else quads.get(0).getSprite(), #endif
#elif MC_VER < MC_1_21_5 ColorMode.getColorMode(this.blockState.getBlock()));
this.baseColor = calculateColorFromTexture(
firstQuad.getSprite(),
ColorMode.getColorMode(this.blockState.getBlock()));
#else
this.baseColor = calculateColorFromTexture(
firstQuad.sprite(),
ColorMode.getColorMode(this.blockState.getBlock()));
#endif
} }
else else
{ {
@@ -255,7 +232,8 @@ public class ClientBlockStateColorCache
this.needPostTinting = false; this.needPostTinting = false;
this.needShade = false; this.needShade = false;
this.tintIndex = 0; this.tintIndex = 0;
this.baseColor = this.getParticleIconColor(); this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
ColorMode.getColorMode(this.blockState.getBlock()));
} }
} }
else else
@@ -264,7 +242,8 @@ public class ClientBlockStateColorCache
this.needPostTinting = true; this.needPostTinting = true;
this.needShade = false; this.needShade = false;
this.tintIndex = 0; this.tintIndex = 0;
this.baseColor = this.getParticleIconColor(); this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
ColorMode.getColorMode(this.blockState.getBlock()));
} }
this.isColorResolved = true; this.isColorResolved = true;
@@ -274,35 +253,6 @@ public class ClientBlockStateColorCache
RESOLVE_LOCK.unlock(); RESOLVE_LOCK.unlock();
} }
} }
@Nullable
private List<BakedQuad> getUnculledQuads() { return this.getQuadsForDirection(null); }
@Nullable
private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction)
{
List<BakedQuad> quads = null;
#if MC_VER < MC_1_21_5
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM);
#else
List<BlockModelPart> blockModelPartList = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(this.blockState).collectParts(RANDOM);
quads = new ArrayList<>();
if (blockModelPartList != null)
{
for (int i = 0; i < blockModelPartList.size(); i++)
{
// if direction is null this will return the unculled quads
quads.addAll(blockModelPartList.get(i).getQuads(direction));
}
}
#endif
return quads;
}
//TODO: Perhaps make this not just use the first frame? //TODO: Perhaps make this not just use the first frame?
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode)
{ {
@@ -374,12 +324,12 @@ public class ClientBlockStateColorCache
if (count == 0) if (count == 0)
{ {
// this block is entirely transparent // this block is entirely transparent
tempColor = ColorUtil.argbToInt(0, 255, 255, 255); tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
} }
else else
{ {
// determine the average color // determine the average color
tempColor = ColorUtil.argbToInt( tempColor = ColorUtil.rgbToInt(
alpha / count, alpha / count,
linearToSrgb((float) (red / (double) alpha)), linearToSrgb((float) (red / (double) alpha)),
linearToSrgb((float) (green / (double) alpha)), linearToSrgb((float) (green / (double) alpha)),
@@ -387,10 +337,10 @@ public class ClientBlockStateColorCache
} }
//check if not missing texture //check if not missing texture
if (tempColor == ColorUtil.argbToInt(255, 182, 0, 182)) if (tempColor == ColorUtil.rgbToInt(255, 182, 0, 182))
{ {
//make it not render at all //make it not render at all
tempColor = ColorUtil.argbToInt(0, 255, 255, 255); tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
} }
return tempColor; return tempColor;
} }
@@ -433,13 +383,6 @@ public class ClientBlockStateColorCache
return (bias + (scale * t)) >>> 16; return (bias + (scale * t)) >>> 16;
} }
private int getParticleIconColor()
{
return calculateColorFromTexture(
Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
ColorMode.getColorMode(this.blockState.getBlock()));
}
//===============// //===============//
@@ -471,7 +414,7 @@ public class ClientBlockStateColorCache
try try
{ {
tintColor = Minecraft.getInstance().getBlockColors() tintColor = Minecraft.getInstance().getBlockColors()
.getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.clientLevelWrapper), McObjectConverter.Convert(pos), this.tintIndex); .getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.levelWrapper), McObjectConverter.Convert(pos), this.tintIndex);
} }
catch (UnsupportedOperationException e) catch (UnsupportedOperationException e)
{ {
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -19,14 +19,8 @@
package com.seibel.distanthorizons.common.wrappers.block; package com.seibel.distanthorizons.common.wrappers.block;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
#if MC_VER < MC_1_17_1 import net.minecraft.client.renderer.texture.TextureAtlasSprite;
#elif MC_VER < MC_1_21_3
#else
import com.seibel.distanthorizons.core.util.ColorUtil;
import net.minecraft.client.renderer.texture.SpriteContents;
#endif
/** /**
* For wrapping/utilizing around TextureAtlasSprite * For wrapping/utilizing around TextureAtlasSprite
@@ -35,6 +29,15 @@ import net.minecraft.client.renderer.texture.SpriteContents;
*/ */
public class TextureAtlasSpriteWrapper public class TextureAtlasSpriteWrapper
{ {
/**
* This code is from Minecraft Forge
* Which is licensed under the terms of GNU Lesser General Public License
* as published by the Free Software Foundation version 2.1
* of the License.
*
* The code has been modified to use TextureAtlasSprite
*/
public static int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y) public static int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y)
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
@@ -48,29 +51,13 @@ public class TextureAtlasSpriteWrapper
y += sprite.animatedTexture.getFrameY(frameIndex) * sprite.height; y += sprite.animatedTexture.getFrameY(frameIndex) * sprite.height;
} }
return sprite.mainImage[0].getPixelRGBA(x, y); return sprite.mainImage[0].getPixelRGBA(x, y);
#elif MC_VER < MC_1_21_3 #else
if (sprite.contents().animatedTexture != null) if (sprite.contents().animatedTexture != null)
{ {
x += sprite.contents().animatedTexture.getFrameX(frameIndex) * sprite.contents().width(); x += sprite.contents().animatedTexture.getFrameX(frameIndex) * sprite.contents().width();
y += sprite.contents().animatedTexture.getFrameY(frameIndex) * sprite.contents().width(); y += sprite.contents().animatedTexture.getFrameY(frameIndex) * sprite.contents().width();
} }
return sprite.contents().originalImage.getPixelRGBA(x, y); return sprite.contents().originalImage.getPixelRGBA(x, y);
#else
SpriteContents content = sprite.contents(); // don't close, otherwise MC will be corrupted and you won't be able to re-access the texture
if (content.animatedTexture != null)
{
x += content.animatedTexture.getFrameX(frameIndex) * content.width();
y += content.animatedTexture.getFrameY(frameIndex) * content.width();
}
int abgr = content.originalImage.getPixel(x, y);
// re-pack the color so we can access it normally
int a = (abgr & 0xFF000000) >>> 24;
int b = (abgr & 0x00FF0000) >>> 16;
int g = (abgr & 0x0000FF00) >>> 8;
int r = (abgr & 0x000000FF);
return ColorUtil.argbToInt(a, r, g, b);
#endif #endif
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -42,24 +42,15 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
{ {
LevelReader parent; LevelReader parent;
public TintGetterOverrideFast(LevelReader parent)
{
//=============// this.parent = parent;
// constructor // }
//=============//
public TintGetterOverrideFast(LevelReader parent) { this.parent = parent; }
//=========//
// methods //
//=========//
private Biome _getBiome(BlockPos pos) private Biome _getBiome(BlockPos pos)
{ {
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
return this.parent.getBiome(pos).value(); return parent.getBiome(pos).value();
#else #else
return parent.getBiome(pos); return parent.getBiome(pos);
#endif #endif
@@ -72,123 +63,169 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); } public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
@Override @Override
public LevelLightEngine getLightEngine() { return this.parent.getLightEngine(); } public LevelLightEngine getLightEngine()
{
return parent.getLightEngine();
}
@Override @Override
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { return this.parent.getBrightness(lightLayer, blockPos); } public int getBrightness(LightLayer lightLayer, BlockPos blockPos)
{
return parent.getBrightness(lightLayer, blockPos);
}
@Override @Override
public int getRawBrightness(BlockPos blockPos, int i) { return this.parent.getRawBrightness(blockPos, i); } public int getRawBrightness(BlockPos blockPos, int i)
{
return parent.getRawBrightness(blockPos, i);
}
@Override @Override
public boolean canSeeSky(BlockPos blockPos) { return this.parent.canSeeSky(blockPos); } public boolean canSeeSky(BlockPos blockPos)
{
return parent.canSeeSky(blockPos);
}
@Override @Override
@Nullable @Nullable
public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); } public BlockEntity getBlockEntity(BlockPos blockPos)
{
return parent.getBlockEntity(blockPos);
}
@Override @Override
public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); } public BlockState getBlockState(BlockPos blockPos)
{
return parent.getBlockState(blockPos);
}
@Override @Override
public FluidState getFluidState(BlockPos blockPos) { return this.parent.getFluidState(blockPos); } public FluidState getFluidState(BlockPos blockPos)
{
return parent.getFluidState(blockPos);
}
@Override @Override
public int getLightEmission(BlockPos blockPos) { return this.parent.getLightEmission(blockPos); } public int getLightEmission(BlockPos blockPos)
{
return parent.getLightEmission(blockPos);
}
#if MC_VER < MC_1_21_3
@Override @Override
public int getMaxLightLevel() { return parent.getMaxLightLevel(); } public int getMaxLightLevel()
#else {
#endif return parent.getMaxLightLevel();
}
@Override @Override
public Stream<BlockState> getBlockStates(AABB aABB) public Stream<BlockState> getBlockStates(AABB aABB)
{ return this.parent.getBlockStates(aABB); } {
return parent.getBlockStates(aABB);
}
@Override @Override
public BlockHitResult clip(ClipContext clipContext) public BlockHitResult clip(ClipContext clipContext)
{ return this.parent.clip(clipContext); } {
return parent.clip(clipContext);
}
@Override @Override
@Nullable @Nullable
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState) public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
{ return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState); } {
return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
}
@Override @Override
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier)
{ return this.parent.getBlockFloorHeight(voxelShape, supplier); } {
return parent.getBlockFloorHeight(voxelShape, supplier);
}
@Override @Override
public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); } public double getBlockFloorHeight(BlockPos blockPos)
{
return parent.getBlockFloorHeight(blockPos);
}
#if MC_VER < MC_1_21_3
@Override @Override
public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); } public int getMaxBuildHeight()
#else {
@Override return parent.getMaxBuildHeight();
public int getMaxY() { return this.parent.getMaxY(); } }
#endif
//==============//
// post MC 1.17 //
//==============//
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
@Override @Override
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType)
{ return this.parent.getBlockEntity(blockPos, blockEntityType); } {
return parent.getBlockEntity(blockPos, blockEntityType);
}
@Override @Override
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext)
{ return this.parent.isBlockInLine(clipBlockStateContext); } {
return parent.isBlockInLine(clipBlockStateContext);
}
@Override @Override
public int getHeight() { return this.parent.getHeight(); } public int getHeight()
{
#if MC_VER < MC_1_21_3 return parent.getHeight();
@Override }
public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); }
#else
@Override
public int getMinY() { return this.parent.getMinY(); }
#endif
@Override @Override
public int getSectionsCount() { return this.parent.getSectionsCount(); } public int getMinBuildHeight()
{
#if MC_VER < MC_1_21_3 return parent.getMinBuildHeight();
@Override }
public int getMinSection() { return this.parent.getMinSection(); }
#else
@Override
public int getMinSectionY() { return BlockAndTintGetter.super.getMinSectionY(); }
#endif
#if MC_VER < MC_1_21_3
@Override
public int getMaxSection() { return this.parent.getMaxSection(); }
#else
@Override
public int getMaxSectionY() { return this.parent.getMaxSectionY(); }
#endif
@Override @Override
public boolean isOutsideBuildHeight(BlockPos blockPos) { return this.parent.isOutsideBuildHeight(blockPos); } public int getSectionsCount()
{
return parent.getSectionsCount();
}
@Override @Override
public boolean isOutsideBuildHeight(int i) { return this.parent.isOutsideBuildHeight(i); } public int getMinSection()
{
return parent.getMinSection();
}
@Override @Override
public int getSectionIndex(int i) { return this.parent.getSectionIndex(i); } public int getMaxSection()
{
return parent.getMaxSection();
}
@Override @Override
public int getSectionIndexFromSectionY(int i) { return this.parent.getSectionIndexFromSectionY(i); } public boolean isOutsideBuildHeight(BlockPos blockPos)
{
return parent.isOutsideBuildHeight(blockPos);
}
@Override @Override
public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); } public boolean isOutsideBuildHeight(int i)
{
return parent.isOutsideBuildHeight(i);
}
@Override
public int getSectionIndex(int i)
{
return parent.getSectionIndex(i);
}
@Override
public int getSectionIndexFromSectionY(int i)
{
return parent.getSectionIndexFromSectionY(i);
}
@Override
public int getSectionYFromSectionIndex(int i)
{
return parent.getSectionYFromSectionIndex(i);
}
#endif #endif
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -19,7 +19,6 @@
package com.seibel.distanthorizons.common.wrappers.block; package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.util.LodUtil;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Cursor3D; import net.minecraft.core.Cursor3D;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
@@ -45,28 +44,16 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter
LevelReader parent; LevelReader parent;
public int smoothingRange; public int smoothingRange;
//=============//
// constructor //
//=============//
public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange) public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange)
{ {
this.parent = parent; this.parent = parent;
this.smoothingRange = smoothingRange; this.smoothingRange = smoothingRange;
} }
//=========//
// methods //
//=========//
private Biome _getBiome(BlockPos pos) private Biome _getBiome(BlockPos pos)
{ {
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
return this.parent.getBiome(pos).value(); return parent.getBiome(pos).value();
#else #else
return parent.getBiome(pos); return parent.getBiome(pos);
#endif #endif
@@ -126,11 +113,8 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter
@Override @Override
public int getLightEmission(BlockPos blockPos) { return this.parent.getLightEmission(blockPos); } public int getLightEmission(BlockPos blockPos) { return this.parent.getLightEmission(blockPos); }
#if MC_VER < MC_1_21_3
@Override @Override
public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); } public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); }
#else
#endif
@Override @Override
public Stream<BlockState> getBlockStates(AABB aABB) { return this.parent.getBlockStates(aABB); } public Stream<BlockState> getBlockStates(AABB aABB) { return this.parent.getBlockStates(aABB); }
@@ -151,13 +135,8 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter
@Override @Override
public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); } public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); }
#if MC_VER < MC_1_21_3
@Override @Override
public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); } public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); }
#else
@Override
public int getMaxY() { return this.parent.getMaxY(); }
#endif
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
@Override @Override
@@ -169,32 +148,17 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter
@Override @Override
public int getHeight() { return this.parent.getHeight(); } public int getHeight() { return this.parent.getHeight(); }
#if MC_VER < MC_1_21_3
@Override @Override
public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); } public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); }
#else
@Override
public int getMinY() { return this.parent.getMinY(); }
#endif
@Override @Override
public int getSectionsCount() { return this.parent.getSectionsCount(); } public int getSectionsCount() { return this.parent.getSectionsCount(); }
#if MC_VER < MC_1_21_3
@Override @Override
public int getMinSection() { return this.parent.getMinSection(); } public int getMinSection() { return this.parent.getMinSection(); }
#else
@Override
public int getMinSectionY() { return BlockAndTintGetter.super.getMinSectionY(); }
#endif
#if MC_VER < MC_1_21_3
@Override @Override
public int getMaxSection() { return this.parent.getMaxSection(); } public int getMaxSection() { return this.parent.getMaxSection(); }
#else
@Override
public int getMaxSectionY() { return this.parent.getMaxSectionY(); }
#endif
@Override @Override
public boolean isOutsideBuildHeight(BlockPos blockPos) { return this.parent.isOutsideBuildHeight(blockPos); } public boolean isOutsideBuildHeight(BlockPos blockPos) { return this.parent.isOutsideBuildHeight(blockPos); }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -20,13 +20,13 @@
package com.seibel.distanthorizons.common.wrappers.block; package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.*; import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
@@ -39,54 +39,55 @@ import org.jetbrains.annotations.Nullable;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
#endif #endif
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class TintWithoutLevelOverrider implements BlockAndTintGetter public class TintWithoutLevelOverrider implements BlockAndTintGetter
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); /**
* This will only ever be null if there was an issue with {@link IClientLevelWrapper#getPlainsBiomeWrapper()}
#if MC_VER < MC_1_18_2 * but {@link Nullable} is there just in case.
public static final ConcurrentMap<String, Biome> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>(); */
#else @Nullable
public static final ConcurrentMap<String, Holder<Biome>> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>(); private final Biome biome;
#endif
@NotNull
private final BiomeWrapper biomeWrapper;
//=============// public TintWithoutLevelOverrider(BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper)
// constructor // {
//=============// // try to get the wrapped biome
Biome unwrappedBiome = null;
if (biomeWrapper.biome != null)
{
unwrappedBiome = unwrap(biomeWrapper.biome);
}
public TintWithoutLevelOverrider(@NotNull BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper) if(unwrappedBiome == null)
{ this.biomeWrapper = biomeWrapper; } {
// we are looking at the empty biome wrapper, try using plains as a backup
BiomeWrapper plainsBiomeWrapper = ((BiomeWrapper) clientLevelWrapper.getPlainsBiomeWrapper());
if (plainsBiomeWrapper != null)
{
unwrappedBiome = unwrap(plainsBiomeWrapper.biome);
}
}
this.biome = unwrappedBiome;
}
//=========//
// methods //
//=========//
@Override @Override
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver) public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
{ {
String biomeString = this.biomeWrapper.getSerialString(); if (this.biome != null)
if (biomeString == null
|| biomeString.isEmpty()
|| biomeString.equals(BiomeWrapper.EMPTY_BIOME_STRING))
{ {
// default to "plains" for empty/invalid biomes return colorResolver.getColor(this.biome, blockPos.getX(), blockPos.getZ());
biomeString = "minecraft:plains"; }
else
{
// hopefully unneeded debug color
return ColorUtil.CYAN;
} }
return colorResolver.getColor(unwrap(getClientBiome(biomeString)), blockPos.getX(), blockPos.getZ());
} }
private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome) private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
{ {
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
@@ -96,88 +97,6 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter
#endif #endif
} }
/**
* <p>Previously, this class might have immediately unwrapped the Holder like this:</p>
* <pre>{@code
* // Inside constructor (OLD WAY - PROBLEMATIC):
* Holder<Biome> biomeHolder = getTheHolderFromSomewhere();
* this.biome = biomeHolder.value(); // <-- PROBLEM HERE
* }</pre>
*
* <p>This approach is problematic because the {@link net.minecraft.core.Holder} system,
* particularly {@code Holder.Reference}, is designed for <strong>late binding</strong>. Here's why storing
* the Holder itself is now necessary:</p>
* <ol>
* <li>A {@code Holder.Reference<Biome>} might be created initially just with a
* {@link net.minecraft.resources.ResourceKey} (like {@code minecraft:plains}), but its actual
* {@link net.minecraft.core.Holder#value() value()} (the {@code Biome} object itself) might be {@code null}
* at construction time.</li>
* <li>Later, during game loading, registry population, or potentially due to modifications by other mods
* (e.g., Polytone), the system calls internal binding methods (like {@code bindValue(Biome)})
* on the {@code Holder} instance. This sets or <strong>updates</strong> the internal reference to the
* actual {@code Biome} object.</li>
* <li>Crucially, the binding process might assign a completely <strong>new</strong> {@code Biome} object
* instance to the {@code Holder} reference, replacing any previous one.</li>
* </ol>
*
* <p>If we unwrapped the {@code Holder} using {@code .value()} within the constructor (the old way),
* our class's internal {@code biome} field would permanently store a reference to whatever {@code Biome}
* object the {@code Holder} pointed to *at that exact moment*. It would have no link back to the
* {@code Holder} and would be unaware if the {@code Holder} was later updated to point to a different
* (or the initially missing) {@code Biome} object. This would lead to using stale or even {@code null} data.</p>
*
* <p>By storing the {@code Holder<Biome>} itself, this class can call {@link net.minecraft.core.Holder#value()}
* whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome}
* instance associated with the holder at that time.</p>
*/
private static #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif getClientBiome(String biomeResourceString)
{
// cache the client biomes so we don't have to re-parse the resource location every time
return BIOME_BY_RESOURCE_STRING.compute(biomeResourceString,
(resourceString, existingBiome) ->
{
if (existingBiome != null)
{
return existingBiome;
}
ClientLevel clientLevel = Minecraft.getInstance().level;
if (clientLevel == null)
{
// shouldn't happen, but just in case
throw new IllegalStateException("Attempted to get client biome when no client level was loaded.");
}
BiomeWrapper.BiomeDeserializeResult result;
try
{
result = BiomeWrapper.deserializeBiome(resourceString, clientLevel.registryAccess());
}
catch (Exception e)
{
LOGGER.warn("Unable to deserialize client biome ["+resourceString+"], using fallback...");
try
{
result = BiomeWrapper.deserializeBiome("minecraft:plains", clientLevel.registryAccess());
}
catch (IOException ex)
{
// should never happen, if it does this log will explode, but just in case
LOGGER.error("Unable to deserialize fallback client biome [minecraft:plains], returning NULL.");
return null;
}
}
if (result.success)
{
existingBiome = result.biome;
}
return existingBiome;
});
}
//================// //================//
@@ -213,27 +132,17 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter
} }
//==============//
// post MC 1.17 //
//==============//
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
@Override @Override
public int getHeight() public int getHeight()
{ throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only."); } {
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
#if MC_VER < MC_1_21_3 }
@Override @Override
public int getMinBuildHeight() public int getMinBuildHeight()
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only."); } {
#else throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
@Override }
public int getMinY()
{ throw new UnsupportedOperationException("ERROR: getMinY() called on TintWithoutLevelOverrider. Object is for tinting only."); }
#endif
#endif #endif
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -39,24 +39,11 @@ public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
final BiomeWrapper biome; final BiomeWrapper biome;
public int smoothingRange; public int smoothingRange;
//=============//
// constructor //
//=============//
public TintWithoutLevelSmoothOverrider(BiomeWrapper biome, int smoothingRange) public TintWithoutLevelSmoothOverrider(BiomeWrapper biome, int smoothingRange)
{ {
this.biome = biome; this.biome = biome;
this.smoothingRange = smoothingRange; this.smoothingRange = smoothingRange;
} }
//=========//
// methods //
//=========//
@Override @Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
{ {
@@ -70,7 +57,7 @@ public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
return biome; return biome;
#endif #endif
} }
//
// public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver) // public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
// { // {
// int i = smoothingRange; // int i = smoothingRange;
@@ -102,43 +89,44 @@ public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
@Override @Override
public float getShade(Direction direction, boolean shade) public float getShade(Direction direction, boolean shade)
{ throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); } {
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override @Override
public LevelLightEngine getLightEngine() public LevelLightEngine getLightEngine()
{ throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); } {
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Nullable @Nullable
@Override @Override
public BlockEntity getBlockEntity(BlockPos pos) public BlockEntity getBlockEntity(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); } {
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override @Override
public BlockState getBlockState(BlockPos pos) public BlockState getBlockState(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); } {
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override @Override
public FluidState getFluidState(BlockPos pos) public FluidState getFluidState(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); } {
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
//==============//
// post MC 1.17 //
//==============//
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
@Override @Override
public int getHeight() public int getHeight()
{ throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); } {
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
#if MC_VER < MC_1_21_3 }
@Override @Override
public int getMinBuildHeight() public int getMinBuildHeight()
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); } {
#else throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
@Override }
public int getMinY()
{ throw new UnsupportedOperationException("ERROR: getMinY() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
#endif
#endif #endif
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -16,31 +16,37 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.seibel.distanthorizons.common.wrappers.chunk; package com.seibel.distanthorizons.common.wrappers.chunk;
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.world.EWorldEnvironment;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.client.multiplayer.ClientChunkCache;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
import net.minecraft.core.QuartPos; import net.minecraft.core.QuartPos;
@@ -64,6 +70,8 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
#if MC_VER >= MC_1_20_1 #if MC_VER >= MC_1_20_1
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.core.SectionPos;
#endif #endif
#if MC_VER <= MC_1_20_4 #if MC_VER <= MC_1_20_4
@@ -79,28 +87,41 @@ public class ChunkWrapper implements IChunkWrapper
/** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */ /** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos()); private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
private static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper());
private final ChunkAccess chunk; private final ChunkAccess chunk;
private final DhChunkPos chunkPos; private final DhChunkPos chunkPos;
private final LevelReader lightSource;
private final ILevelWrapper wrappedLevel; private final ILevelWrapper wrappedLevel;
private boolean isDhBlockLightCorrect = false; private boolean isDhLightCorrect = false;
private boolean isDhSkyLightCorrect = false; /** only used when connected to a dedicated server */
private boolean isMcClientLightingCorrect = false;
private ChunkLightStorage blockLightStorage; private ChunkLightStorage blockLightStorage;
private ChunkLightStorage skyLightStorage; private ChunkLightStorage skyLightStorage;
private ArrayList<DhBlockPos> blockLightPosList = null; private ArrayList<DhBlockPos> blockLightPosList = null;
private boolean useDhLighting;
private int minNonEmptyHeight = Integer.MIN_VALUE; private int minNonEmptyHeight = Integer.MIN_VALUE;
private int maxNonEmptyHeight = Integer.MAX_VALUE; private int maxNonEmptyHeight = Integer.MAX_VALUE;
/** will be null if we are using MC heightmaps */ private int blockBiomeHashCode = 0;
private final int[][] solidHeightMap;
/** will be null if we are using MC heightmaps */ /**
private final int[][] lightBlockingHeightMap; * Due to vanilla `isClientLightReady()` not being designed for use by a non-render thread, it may return 'true'
* before the light engine has ticked, (right after all light changes is marked by the engine to be processed).
* To fix this, on client-only mode, we mixin-redirect the `isClientLightReady()` so that after the call, it will
* trigger a synchronous update of this flag here on all chunks that are wrapped. <br><br>
*
* Note: Using a static weak hash map to store the chunks that need to be updated, as instance of chunk wrapper
* can be duplicated, with same chunk instance. And the data stored here are all temporary, and thus will not be
* visible when a chunk is re-wrapped later. <br>
* (Also, thread safety done via a reader writer lock)
*/
private static final ConcurrentLinkedQueue<ChunkWrapper> chunksNeedingClientLightUpdating = new ConcurrentLinkedQueue<>();
@@ -108,25 +129,22 @@ public class ChunkWrapper implements IChunkWrapper
// constructor // // constructor //
//=============// //=============//
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel) public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource, ILevelWrapper wrappedLevel)
{ {
this.chunk = chunk; this.chunk = chunk;
this.lightSource = lightSource;
this.wrappedLevel = wrappedLevel; this.wrappedLevel = wrappedLevel;
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z); this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
// use DH heightmaps if requested // TODO is this the best way to differentiate between when we are generating chunks and when MC gave us a chunk?
if (Config.Common.LodBuilding.recalculateChunkHeightmaps.get()) boolean isDhGeneratedChunk = (this.lightSource.getClass() == DhLitWorldGenRegion.class);
{ // MC loaded chunks should get their lighting from MC, DH generated chunks should get their lighting from DH
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH]; this.useDhLighting = isDhGeneratedChunk;
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
this.recalculateDhHeightMapsIfNeeded(); // FIXME +1 is to handle the fact that LodDataBuilder adds +1 to all block lighting calculations, also done in the relative position validator
}
else if (SharedApi.getEnvironment() != EWorldEnvironment.Server_Only)
{ chunksNeedingClientLightUpdating.add(this);
this.solidHeightMap = null;
this.lightBlockingHeightMap = null;
}
} }
@@ -147,29 +165,19 @@ public class ChunkWrapper implements IChunkWrapper
} }
@Override @Override
public int getInclusiveMinBuildHeight() { return getInclusiveMinBuildHeight(this.chunk); } public int getMinBuildHeight() { return getMinBuildHeight(this.chunk); }
public static int getInclusiveMinBuildHeight(ChunkAccess chunk) public static int getMinBuildHeight(ChunkAccess chunk)
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
return 0; return 0;
#elif MC_VER < MC_1_21_3
return chunk.getMinBuildHeight();
#else #else
return chunk.getMinY(); return chunk.getMinBuildHeight();
#endif #endif
} }
@Override @Override
public int getExclusiveMaxBuildHeight() { return getExclusiveMaxBuildHeight(this.chunk); } public int getMaxBuildHeight() { return getMaxBuildHeight(this.chunk); }
public static int getExclusiveMaxBuildHeight(ChunkAccess chunk) public static int getMaxBuildHeight(ChunkAccess chunk) { return chunk.getMaxBuildHeight(); }
{
#if MC_VER < MC_1_21_3
return chunk.getMaxBuildHeight();
#else
// +1 since Minecraft made the max value inclusive
return chunk.getMaxY() + 1;
#endif
}
@Override @Override
public int getMinNonEmptyHeight() public int getMinNonEmptyHeight()
@@ -181,7 +189,7 @@ public class ChunkWrapper implements IChunkWrapper
// default if every section is empty or missing // default if every section is empty or missing
this.minNonEmptyHeight = this.getInclusiveMinBuildHeight(); this.minNonEmptyHeight = this.getMinBuildHeight();
// determine the lowest empty section (bottom up) // determine the lowest empty section (bottom up)
LevelChunkSection[] sections = this.chunk.getSections(); LevelChunkSection[] sections = this.chunk.getSections();
@@ -213,7 +221,7 @@ public class ChunkWrapper implements IChunkWrapper
// default if every section is empty or missing // default if every section is empty or missing
this.maxNonEmptyHeight = this.getExclusiveMaxBuildHeight(); this.maxNonEmptyHeight = this.getMaxBuildHeight();
// determine the highest empty section (top down) // determine the highest empty section (top down)
LevelChunkSection[] sections = this.chunk.getSections(); LevelChunkSection[] sections = this.chunk.getSections();
@@ -246,92 +254,14 @@ public class ChunkWrapper implements IChunkWrapper
return section.hasOnlyAir(); return section.hasOnlyAir();
#endif #endif
} }
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); } private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getMinBuildHeight(); }
/** Will only run if the config says the MC heightmaps shouldn't be trusted. */
public void recalculateDhHeightMapsIfNeeded()
{
// re-calculate the min/max heights for consistency (during world gen these may be wrong)
this.minNonEmptyHeight = Integer.MIN_VALUE;
this.maxNonEmptyHeight = Integer.MAX_VALUE;
// recalculate heightmaps if needed
if (this.solidHeightMap != null)
{
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
{
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
{
int minInclusiveBuildHeight = this.getMinNonEmptyHeight();
// if no blocks are found the height map will be at the bottom of the world
int solidHeight = minInclusiveBuildHeight;
int lightBlockingHeight = minInclusiveBuildHeight;
int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight();
IBlockStateWrapper block = this.getBlockState(x, y, z);
while (// go down until we reach the minimum build height
y > minInclusiveBuildHeight
// keep going until we find both height map values
&& (solidHeight == minInclusiveBuildHeight || lightBlockingHeight == minInclusiveBuildHeight))
{
// is this block solid?
if (solidHeight == minInclusiveBuildHeight
&& block.isSolid())
{
solidHeight = y;
}
// is this block light blocking?
if (lightBlockingHeight == minInclusiveBuildHeight
&& block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
{
lightBlockingHeight = y;
}
// get the next block down
y--;
block = this.getBlockState(x, y, z);
}
this.solidHeightMap[x][z] = solidHeight;
this.lightBlockingHeightMap[x][z] = lightBlockingHeight;
}
}
}
}
@Override @Override
public int getSolidHeightMapValue(int xRel, int zRel) public int getSolidHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE).getFirstAvailable(xRel, zRel); }
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(xRel, zRel);
// will be null if we want to use MC heightmaps
if (this.solidHeightMap == null)
{
return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE).getFirstAvailable(xRel, zRel);
}
else
{
return this.solidHeightMap[xRel][zRel];
}
}
@Override @Override
public int getLightBlockingHeightMapValue(int xRel, int zRel) public int getLightBlockingHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel); }
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(xRel, zRel);
if (this.lightBlockingHeightMap == null)
{
return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel);
}
else
{
return this.lightBlockingHeightMap[xRel][zRel];
}
}
@Override @Override
@@ -368,130 +298,14 @@ public class ChunkWrapper implements IChunkWrapper
blockPos.setY(relY); blockPos.setY(relY);
blockPos.setZ(relZ); blockPos.setZ(relZ);
// TODO copy into pooled array, this isn't thread safe and can cause MC to throw errors if the chunk is loaded
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel); return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
} }
@Override
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ, IMutableBlockPosWrapper mcBlockPos, IBlockStateWrapper guess)
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
BlockPos.MutableBlockPos pos = (BlockPos.MutableBlockPos)mcBlockPos.getWrappedMcObject();
pos.setX(relX);
pos.setY(relY);
pos.setZ(relZ);
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(pos), this.wrappedLevel, guess);
}
/**
// Commented out experimental LevelChunkSection cloning logic to fix extremely rare concurrency modification issue
// James has only ever seen a report relating to LevelSection concurrent modification once,
// the issue can cause DH lighting/LOD building to fail due to the chunk being modified on the server.
// James has only heard of this issue once, so it isn't a high priority issue.
// And from James' quick look at a few different MC versions it appears the LevelChunkSection object changes quite drastically between MC versions,
// meaning any cloning logic would have to either be a new wrapper or very MC version dependent, either way a lot of additional work.
// Due to the large time cost and extremely rare nature of the issue, this logic is commented out unless this issue pops up again in the future.
// instance variable to hold the cloned sections
private final LevelChunkSection[] levelChunkSections;
// new constructor logic to clone the sections
public constructor(...)
{
// other constructor logic //
LevelChunkSection[] sections = this.chunk.getSections();
this.levelChunkSections = new LevelChunkSection[sections.length];
for (int i = 0; i < sections.length; i++)
{
LevelChunkSection section = sections[i];
if (section != null)
{
// TODO implement section cloning for older MC versions, only 1.21.4 MC (and maybe other semi recent versions) have a clean way to handle this
// TODO we probably want a wrapper object instead
#if MC_VER < MC_1_21_4
this.levelChunkSections[i] = section;
#else
this.levelChunkSections[i] = section.copy();
#endif
}
}
}
// replacement getters
@Override
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ)
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
return this.getBlockStateInternal(relX, relY, relZ, null);
}
@Override
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ, IMutableBlockPosWrapper mcBlockPos, IBlockStateWrapper guess)
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
return this.getBlockStateInternal(relX, relY, relZ, guess);
}
// internal getter logic
private IBlockStateWrapper getBlockStateInternal(int relX, int y, int relZ, @Nullable IBlockStateWrapper guess)
{
try
{
// attempt to get the section for this position
int i = (y - this.getInclusiveMinBuildHeight()) / 16;
if (i >= 0 && i < this.levelChunkSections.length)
{
LevelChunkSection section = this.levelChunkSections[i];
if (!section.hasOnlyAir())
{
if (guess != null)
{
return BlockStateWrapper.fromBlockState(section.getBlockState(relX & 15, y & 15, relZ & 15), this.wrappedLevel, guess);
}
else
{
return BlockStateWrapper.fromBlockState(section.getBlockState(relX & 15, y & 15, relZ & 15), this.wrappedLevel);
}
}
}
return BlockStateWrapper.AIR;
}
catch (Exception e)
{
return BlockStateWrapper.AIR;
}
}
*/
@Override
public IMutableBlockPosWrapper getMutableBlockPosWrapper() { return MUTABLE_BLOCK_POS_WRAPPER_REF.get(); }
@Override @Override
public DhChunkPos getChunkPos() { return this.chunkPos; } public DhChunkPos getChunkPos() { return this.chunkPos; }
public ChunkAccess getChunk() { return this.chunk; } public ChunkAccess getChunk() { return this.chunk; }
public void trySetStatus(ChunkStatus status) { trySetStatus(this.getChunk(), status); }
/** does nothing if the chunk object doesn't support setting it's status */
public static void trySetStatus(ChunkAccess chunk, ChunkStatus status)
{
if (chunk instanceof ProtoChunk)
{
#if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(status);
#else
((ProtoChunk) chunk).setPersistedStatus(status);
#endif
}
}
public ChunkStatus getStatus() { return getStatus(this.getChunk()); } public ChunkStatus getStatus() { return getStatus(this.getChunk()); }
public static ChunkStatus getStatus(ChunkAccess chunk) public static ChunkStatus getStatus(ChunkAccess chunk)
{ {
@@ -518,14 +332,44 @@ public class ChunkWrapper implements IChunkWrapper
//==========// //==========//
@Override @Override
public void setIsDhSkyLightCorrect(boolean isDhLightCorrect) { this.isDhSkyLightCorrect = isDhLightCorrect; } public void setIsDhLightCorrect(boolean isDhLightCorrect) { this.isDhLightCorrect = isDhLightCorrect; }
@Override
public void setIsDhBlockLightCorrect(boolean isDhLightCorrect) { this.isDhBlockLightCorrect = isDhLightCorrect; }
@Override @Override
public boolean isDhBlockLightingCorrect() { return this.isDhBlockLightCorrect; } public void setUseDhLighting(boolean useDhLighting) { this.useDhLighting = useDhLighting; }
@Override @Override
public boolean isDhSkyLightCorrect() { return this.isDhSkyLightCorrect; } public boolean isLightCorrect()
{
if (this.useDhLighting)
{
return this.isDhLightCorrect;
}
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
return false; // MC's lighting engine doesn't work consistently enough to trust for 1.16 or 1.17
#else
if (this.chunk instanceof LevelChunk)
{
LevelChunk levelChunk = (LevelChunk) this.chunk;
if (levelChunk.getLevel().isClientSide())
{
// connected to a server
return this.isMcClientLightingCorrect;
}
else
{
// in a single player world
return this.chunk.isLightCorrect() && levelChunk.loaded;
}
}
else
{
// called when in a single player world and the chunk is a proto chunk (in world gen, and not active)
return this.chunk.isLightCorrect();
}
#endif
}
@Override @Override
@@ -580,6 +424,44 @@ public class ChunkWrapper implements IChunkWrapper
public void setSkyLightStorage(ChunkLightStorage lightStorage) { this.skyLightStorage = lightStorage; } public void setSkyLightStorage(ChunkLightStorage lightStorage) { this.skyLightStorage = lightStorage; }
@Override
public int getBlockLight(int relX, int y, int relZ)
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
// use the full lighting engine when the chunks are within render distance or the config requests it
if (this.useDhLighting)
{
// DH lighting method
return this.getBlockLightStorage().get(relX, y, relZ);
}
else
{
// note: this returns 0 if the chunk is unload
// MC lighting method
return this.lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(relX + this.getMinBlockX(), y, relZ + this.getMinBlockZ()));
}
}
@Override
public int getSkyLight(int relX, int y, int relZ)
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
// use the full lighting engine when the chunks are within render distance or the config requests it
if (this.useDhLighting)
{
// DH lighting method
return this.getSkyLightStorage().get(relX, y, relZ);
}
else
{
// MC lighting method
return this.lightSource.getBrightness(LightLayer.SKY, new BlockPos(relX + this.getMinBlockX(), y, relZ + this.getMinBlockZ()));
}
}
/** /**
* FIXME synchronized is necessary for a rare issue where this method is called from two separate threads at the same time * FIXME synchronized is necessary for a rare issue where this method is called from two separate threads at the same time
* before the list has finished populating. * before the list has finished populating.
@@ -615,12 +497,95 @@ public class ChunkWrapper implements IChunkWrapper
return this.blockLightPosList; return this.blockLightPosList;
} }
public static void syncedUpdateClientLightStatus()
{
#if MC_VER < MC_1_18_2
// TODO: Check what to do in 1.18.1 and older
// since we don't currently handle this list,
// clear it to prevent memory leaks
chunksNeedingClientLightUpdating.clear();
#else
// update the chunks client lighting
ChunkWrapper chunkWrapper = chunksNeedingClientLightUpdating.poll();
while (chunkWrapper != null)
{
chunkWrapper.updateIsClientLightingCorrect();
chunkWrapper = chunksNeedingClientLightUpdating.poll();
}
#endif
}
/** Should be called after client light updates are triggered. */
private void updateIsClientLightingCorrect()
{
if (this.chunk instanceof LevelChunk && ((LevelChunk) this.chunk).getLevel() instanceof ClientLevel)
{
LevelChunk levelChunk = (LevelChunk) this.chunk;
ClientChunkCache clientChunkCache = ((ClientLevel) levelChunk.getLevel()).getChunkSource();
this.isMcClientLightingCorrect = clientChunkCache.getChunkForLighting(this.chunk.getPos().x, this.chunk.getPos().z) != null &&
#if MC_VER <= MC_1_17_1
levelChunk.isLightCorrect();
#elif MC_VER < MC_1_20_1
levelChunk.isClientLightReady();
#else
checkLightSectionsOnChunk(levelChunk, levelChunk.getLevel().getLightEngine());
#endif
}
}
#if MC_VER >= MC_1_20_1
private static boolean checkLightSectionsOnChunk(LevelChunk chunk, LevelLightEngine engine)
{
LevelChunkSection[] sections = chunk.getSections();
int minY = chunk.getMinSection();
int maxY = chunk.getMaxSection();
for (int y = minY; y < maxY; ++y)
{
LevelChunkSection section = sections[chunk.getSectionIndexFromSectionY(y)];
if (section.hasOnlyAir()) continue;
if (!engine.lightOnInSection(SectionPos.of(chunk.getPos(), y)))
{
return false;
}
}
return true;
}
#endif
//===============// //===============//
// other methods // // other methods //
//===============// //===============//
@Override
public boolean doNearbyChunksExist()
{
if (this.lightSource instanceof DhLitWorldGenRegion)
{
return true;
}
for (int dx = -1; dx <= 1; dx++)
{
for (int dz = -1; dz <= 1; dz++)
{
if (dx == 0 && dz == 0)
{
continue;
}
else if (this.lightSource.getChunk(dx + this.chunk.getPos().x, dz + this.chunk.getPos().z, ChunkStatus.BIOMES, false) == null)
{
return false;
}
}
}
return true;
}
@Override @Override
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; } public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
@@ -16,6 +16,7 @@ import java.util.regex.Pattern;
// Logger (for debug stuff) // Logger (for debug stuff)
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui; import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase; import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.types.*; import com.seibel.distanthorizons.core.config.types.*;
@@ -56,20 +57,20 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*; import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.Translatable;
/* /**
* Based upon TinyConfig but is highly modified * Based upon TinyConfig but is highly modified
* https://github.com/Minenash/TinyConfig * https://github.com/Minenash/TinyConfig
* *
* Note: floats don't work with this system, use doubles.
*
* Credits to Motschen * Credits to Motschen
* *
* @author coolGi * @author coolGi
* @version 5-21-2022 * @version 5-21-2022
*/ */
// FLOATS DONT WORK WITH THIS
/** This file is going to be removed sometime soon, please dont hook onto anything within this file until the new UI is compleated */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ClassicConfigGUI public class ClassicConfigGUI
{ {
@@ -118,18 +119,14 @@ public class ClassicConfigGUI
*/ */
private static void textField(AbstractConfigType info, Function<String, Number> func, Pattern pattern, boolean cast) private static void textField(AbstractConfigType info, Function<String, Number> func, Pattern pattern, boolean cast)
{ {
boolean isNumber = pattern != null;
((EntryInfo) info.guiValue).widget = (BiFunction<EditBox, Button, Predicate<String>>) (editBox, button) -> stringValue -> ((EntryInfo) info.guiValue).widget = (BiFunction<EditBox, Button, Predicate<String>>) (editBox, button) -> stringValue ->
{ {
boolean isNumber = (pattern != null);
stringValue = stringValue.trim(); stringValue = stringValue.trim();
if (!(stringValue.isEmpty() || !isNumber || pattern.matcher(stringValue).matches())) if (!(stringValue.isEmpty() || !isNumber || pattern.matcher(stringValue).matches()))
{
return false; return false;
}
Number value = 0;
Number value = info.typeIsFloatingPointNumber() ? 0.0 : 0; // different default values are needed so implicit casting works correctly (if not done casting from 0 (an int) to a double will cause an exception)
((EntryInfo) info.guiValue).error = null; ((EntryInfo) info.guiValue).error = null;
if (isNumber && !stringValue.isEmpty() && !stringValue.equals("-") && !stringValue.equals(".")) if (isNumber && !stringValue.isEmpty() && !stringValue.equals("-") && !stringValue.equals("."))
{ {
@@ -146,22 +143,18 @@ public class ClassicConfigGUI
switch (isValid) switch (isValid)
{ {
case 0: case 0:
((EntryInfo) info.guiValue).error = null; ((EntryInfo) info.guiValue).error = null; break;
break;
case -1: case -1:
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cMinimum length is " + ((ConfigEntry) info).getMin())); ((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cMinimum length is " + ((ConfigEntry) info).getMin())); break;
break;
case 1: case 1:
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cMaximum length is " + ((ConfigEntry) info).getMax())); ((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cMaximum length is " + ((ConfigEntry) info).getMax())); break;
break;
case 2: case 2:
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cValue is invalid")); ((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cValue is invalid")); break;
break;
} }
} }
((EntryInfo) info.guiValue).tempValue = stringValue; ((EntryInfo) info.guiValue).tempValue = stringValue;
editBox.setTextColor(((ConfigEntry) info).isValid(value) == 0 ? 0xFFFFFFFF : 0xFFFF7777); // white and red editBox.setTextColor(((ConfigEntry) info).isValid(value) == 0 ? 0xFFFFFFFF : 0xFFFF7777);
// button.active = entries.stream().allMatch(e -> e.inLimits); // button.active = entries.stream().allMatch(e -> e.inLimits);
@@ -178,7 +171,7 @@ public class ClassicConfigGUI
} }
else else
{ {
((ConfigEntry) info).uiSetWithoutSaving(value != null ? value.intValue() : 0); ((ConfigEntry) info).uiSetWithoutSaving(value.intValue());
} }
} }
@@ -249,7 +242,7 @@ public class ClassicConfigGUI
protected void init() protected void init()
{ {
super.init(); super.init();
if (!this.reload) if (!reload)
{ {
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile(); ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
} }
@@ -276,7 +269,7 @@ public class ClassicConfigGUI
(buttonWidget) -> { (buttonWidget) -> {
ChangelogScreen changelogScreen = new ChangelogScreen(this); ChangelogScreen changelogScreen = new ChangelogScreen(this);
if (changelogScreen.usable) if (changelogScreen.usable)
Objects.requireNonNull(this.minecraft).setScreen(changelogScreen); Objects.requireNonNull(minecraft).setScreen(changelogScreen);
else else
LOGGER.warn("Changelog was not able to open"); LOGGER.warn("Changelog was not able to open");
}, },
@@ -286,17 +279,17 @@ public class ClassicConfigGUI
} }
this.addBtn(MakeBtn(Translatable("distanthorizons.general.cancel"), addBtn(MakeBtn(Translatable("distanthorizons.general.cancel"),
this.width / 2 - 154, this.height - 28, this.width / 2 - 154, this.height - 28,
150, 20, 150, 20,
button -> button ->
{ {
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile(); ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
Objects.requireNonNull(this.minecraft).setScreen(this.parent); Objects.requireNonNull(minecraft).setScreen(parent);
})); }));
this.doneButton = this.addBtn(MakeBtn(Translatable("distanthorizons.general.done"), this.width / 2 + 4, this.height - 28, 150, 20, (button) -> { doneButton = addBtn(MakeBtn(Translatable("distanthorizons.general.done"), this.width / 2 + 4, this.height - 28, 150, 20, (button) -> {
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile(); ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(this.parent); Objects.requireNonNull(minecraft).setScreen(parent);
})); }));
this.list = new ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, 32, 25); this.list = new ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, 32, 25);
@@ -312,18 +305,15 @@ public class ClassicConfigGUI
{ {
try try
{ {
if (info.getCategory().matches(this.category) && info.getAppearance().showInGui) if (info.getCategory().matches(category) && info.getAppearance().showInGui)
this.addMenuItem(info); addMenuItem(info);
} }
catch (Exception e) catch (Exception e)
{ {
String message = "ERROR: Failed to show [\" + info.getNameWCategory() + \"], error: ["+e.getMessage()+"]"; System.out.println("ERROR: Failed to show [" + info.getNameWCategory() + "]");
if (info.get() != null) if (info.get() != null)
{ System.out.print(" with the value [" + info.get() + "] with type [" + info.getType() + "]");
message += " with the value [" + info.get() + "] with type [" + info.getType() + "]"; e.printStackTrace();
}
LOGGER.error(message, e);
} }
} }
@@ -336,7 +326,7 @@ public class ClassicConfigGUI
private void addMenuItem(AbstractConfigType info) private void addMenuItem(AbstractConfigType info)
{ {
initEntry(info, this.translationPrefix); initEntry(info, this.translationPrefix);
Component name = Translatable(this.translationPrefix + info.getNameWCategory()); Component name = Translatable(translationPrefix + info.getNameWCategory());
if (ConfigEntry.class.isAssignableFrom(info.getClass())) if (ConfigEntry.class.isAssignableFrom(info.getClass()))
@@ -345,7 +335,7 @@ public class ClassicConfigGUI
((ConfigEntry) info).uiSetWithoutSaving(((ConfigEntry) info).getDefaultValue()); ((ConfigEntry) info).uiSetWithoutSaving(((ConfigEntry) info).getDefaultValue());
((EntryInfo) info.guiValue).index = 0; ((EntryInfo) info.guiValue).index = 0;
this.reload = true; this.reload = true;
Objects.requireNonNull(this.minecraft).setScreen(this); Objects.requireNonNull(minecraft).setScreen(this);
}; };
int posX = this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth; int posX = this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth;
int posZ = 0; int posZ = 0;
@@ -359,17 +349,17 @@ public class ClassicConfigGUI
Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) ((EntryInfo) info.guiValue).widget; Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) ((EntryInfo) info.guiValue).widget;
if (info.getType().isEnum()) if (info.getType().isEnum())
{ {
widget.setValue(value -> Translatable(this.translationPrefix + "enum." + info.getType().getSimpleName() + "." + info.get().toString())); widget.setValue(value -> Translatable(translationPrefix + "enum." + info.getType().getSimpleName() + "." + info.get().toString()));
} }
this.list.addButton(MakeBtn(widget.getValue().apply(info.get()), this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen, 0, 150, 20, widget.getKey()), resetButton, null, name); this.list.addButton(MakeBtn(widget.getValue().apply(info.get()), this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen, 0, 150, 20, widget.getKey()), resetButton, null, name);
return; return;
} }
else if (((EntryInfo) info.guiValue).widget != null) else if (((EntryInfo) info.guiValue).widget != null)
{ {
EditBox widget = new EditBox(this.font, this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen + 2, 0, 150 - 4, 20, Translatable("")); EditBox widget = new EditBox(font, this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen + 2, 0, 150 - 4, 20, null);
widget.setMaxLength(150); widget.setMaxLength(150);
widget.insertText(String.valueOf(info.get())); widget.insertText(String.valueOf(info.get()));
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) ((EntryInfo) info.guiValue).widget).apply(widget, this.doneButton); Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) ((EntryInfo) info.guiValue).widget).apply(widget, doneButton);
widget.setFilter(processor); widget.setFilter(processor);
this.list.addButton(widget, resetButton, null, name); this.list.addButton(widget, resetButton, null, name);
return; return;
@@ -379,7 +369,7 @@ public class ClassicConfigGUI
{ {
Button widget = MakeBtn(name, this.width / 2 - 100, this.height - 28, 100 * 2, 20, (button -> { Button widget = MakeBtn(name, this.width / 2 - 100, this.height - 28, 100 * 2, 20, (button -> {
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile(); ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(ClassicConfigGUI.getScreen(this.configBase, this, ((ConfigCategory) info).getDestination())); Objects.requireNonNull(minecraft).setScreen(ClassicConfigGUI.getScreen(this.configBase, this, ((ConfigCategory) info).getDestination()));
})); }));
this.list.addButton(widget, null, null, null); this.list.addButton(widget, null, null, null);
return; return;
@@ -397,9 +387,9 @@ public class ClassicConfigGUI
this.list.addButton(null, null, null, name); this.list.addButton(null, null, null, name);
return; return;
} }
if (ConfigUiLinkedEntry.class.isAssignableFrom(info.getClass())) if (ConfigLinkedEntry.class.isAssignableFrom(info.getClass()))
{ {
this.addMenuItem(((ConfigUiLinkedEntry) info).get()); this.addMenuItem(((ConfigLinkedEntry) info).get());
return; return;
} }
@@ -420,34 +410,16 @@ public class ClassicConfigGUI
#endif #endif
this.list.render(matrices, mouseX, mouseY, delta); // Render buttons this.list.render(matrices, mouseX, mouseY, delta); // Render buttons
// Render title DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
this.DhDrawCenteredString(matrices, this.font, this.title, this.width / 2, 15,
#if MC_VER < MC_1_21_6
0xFFFFFF // RGB white
#else
0xFFFFFFFF // ARGB white
#endif);
if (this.configBase.modID.equals("distanthorizons")) if (this.configBase.modID.equals("distanthorizons"))
{ {
// Display version // Display version
this.DhDrawString(matrices, this.font, TextOrLiteral(ModInfo.VERSION), 2, this.height - 10, DhDrawString(matrices, font, TextOrLiteral(ModInfo.VERSION), 2, height - 10, 0xAAAAAA);
#if MC_VER < MC_1_21_6
0xAAAAAA // RGB white
#else
0xFFAAAAAA // ARGB white
#endif);
// If the update is pending, display this message to inform the user that it will apply when the game restarts // If the update is pending, display this message to inform the user that it will apply when the game restarts
if (SelfUpdater.deleteOldJarOnJvmShutdown) if (SelfUpdater.deleteOldJarOnJvmShutdown)
{ DhDrawString(matrices, font, Translatable(configBase.modID + ".updater.waitingForClose"), 4, height - 38, 0xFFFFFF);
this.DhDrawString(matrices, this.font, Translatable(this.configBase.modID + ".updater.waitingForClose"), 4, this.height - 38,
#if MC_VER < MC_1_21_6
0xFFFFFF // RGB white
#else
0xFFFFFFFF // ARGB white
#endif);
}
} }
@@ -466,8 +438,8 @@ public class ClassicConfigGUI
} }
// A quick fix for tooltips on linked entries // A quick fix for tooltips on linked entries
AbstractConfigType newInfo = ConfigUiLinkedEntry.class.isAssignableFrom(info.getClass()) ? AbstractConfigType newInfo = ConfigLinkedEntry.class.isAssignableFrom(info.getClass()) ?
((ConfigUiLinkedEntry) info).get() : ((ConfigLinkedEntry) info).get() :
info; info;
Component name = Translatable(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName()); Component name = Translatable(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName());
@@ -500,47 +472,47 @@ public class ClassicConfigGUI
private static void initEntry(AbstractConfigType configType, String translationPrefix) private static void initEntry(AbstractConfigType info, String translationPrefix)
{ {
configType.guiValue = new EntryInfo(); info.guiValue = new EntryInfo();
Class<?> fieldClass = configType.getType(); Class<?> fieldClass = info.getType();
if (ConfigEntry.class.isAssignableFrom(configType.getClass())) if (ConfigEntry.class.isAssignableFrom(info.getClass()))
{ {
if (fieldClass == Integer.class) if (fieldClass == Integer.class)
{ {
// For int // For int
textField(configType, Integer::parseInt, INTEGER_ONLY_REGEX, true); textField(info, Integer::parseInt, INTEGER_ONLY_REGEX, true);
} }
else if (fieldClass == Double.class) else if (fieldClass == Double.class)
{ {
// For double // For double
textField(configType, Double::parseDouble, DECIMAL_ONLY_REGEX, false); textField(info, Double::parseDouble, DECIMAL_ONLY_REGEX, false);
} }
else if (fieldClass == String.class || fieldClass == List.class) else if (fieldClass == String.class || fieldClass == List.class)
{ {
// For string or list // For string or list
textField(configType, String::length, null, true); textField(info, String::length, null, true);
} }
else if (fieldClass == Boolean.class) else if (fieldClass == Boolean.class)
{ {
// For boolean // For boolean
Function<Object, Component> func = value -> Translatable("distanthorizons.general."+((Boolean) value ? "true" : "false")).withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED); Function<Object, Component> func = value -> Translatable("distanthorizons.general."+((Boolean) value ? "true" : "false")).withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
((EntryInfo) configType.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> { ((EntryInfo) info.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
((ConfigEntry) configType).uiSetWithoutSaving(!(Boolean) configType.get()); ((ConfigEntry) info).uiSetWithoutSaving(!(Boolean) info.get());
button.setMessage(func.apply(configType.get())); button.setMessage(func.apply(info.get()));
}, func); }, func);
} }
else if (fieldClass.isEnum()) else if (fieldClass.isEnum())
{ {
// For enum // For enum
List<?> values = Arrays.asList(configType.getType().getEnumConstants()); List<?> values = Arrays.asList(info.getType().getEnumConstants());
Function<Object, Component> func = value -> Translatable(translationPrefix + "enum." + fieldClass.getSimpleName() + "." + configType.get().toString()); Function<Object, Component> func = value -> Translatable(translationPrefix + "enum." + fieldClass.getSimpleName() + "." + info.get().toString());
((EntryInfo) configType.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> { ((EntryInfo) info.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
// get the currently selected enum and enum index // get the currently selected enum and enum index
int startingIndex = values.indexOf(configType.get()); int startingIndex = values.indexOf(info.get());
Enum<?> enumValue = (Enum<?>) values.get(startingIndex); Enum<?> enumValue = (Enum<?>) values.get(startingIndex);
// search for the next enum that is selectable // search for the next enum that is selectable
@@ -568,12 +540,12 @@ public class ClassicConfigGUI
} }
((ConfigEntry<Enum<?>>) configType).uiSetWithoutSaving(enumValue); ((ConfigEntry<Enum<?>>) info).uiSetWithoutSaving(enumValue);
button.setMessage(func.apply(configType.get())); button.setMessage(func.apply(info.get()));
}, func); }, func);
} }
} }
else if (ConfigCategory.class.isAssignableFrom(configType.getClass())) else if (ConfigCategory.class.isAssignableFrom(info.getClass()))
{ {
// if (!info.info.getName().equals("")) // if (!info.info.getName().equals(""))
// info.name = new TranslatableComponent(info.info.getName()); // info.name = new TranslatableComponent(info.info.getName());
@@ -677,10 +649,8 @@ public class ClassicConfigGUI
if (text != null && (!text.getString().contains("spacer") || button != null)) if (text != null && (!text.getString().contains("spacer") || button != null))
#if MC_VER < MC_1_20_1 #if MC_VER < MC_1_20_1
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF); GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
#elif MC_VER < MC_1_21_6
matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFF);
#else #else
matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFFFF); matrices.drawString(textRenderer, text, 12, y + 5, 0xFFFFFF);
#endif #endif
} }
@@ -52,27 +52,6 @@ public class DhScreen extends Screen
{ {
renderTooltip(guiStack, comp, x, y); renderTooltip(guiStack, comp, x, y);
} }
#elif MC_VER < MC_1_21_6
protected void DhDrawCenteredString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
{
guiStack.drawCenteredString(font, text, x, y, color);
}
protected void DhDrawString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
{
guiStack.drawString(font, text, x, y, color);
}
//protected void DhRenderTooltip(GuiGraphics guiStack, Font font, List<? extends net.minecraft.util.FormattedCharSequence> text, int x, int y)
//{
// guiStack.renderTooltip(font, text, x, y);
//}
protected void DhRenderComponentTooltip(GuiGraphics guiStack, Font font, List<Component> comp, int x, int y)
{
guiStack.renderComponentTooltip(font, comp, x, y);
}
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, Component text, int x, int y)
{
guiStack.renderTooltip(font, text, x, y);
}
#else #else
protected void DhDrawCenteredString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color) protected void DhDrawCenteredString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
{ {
@@ -82,20 +61,17 @@ public class DhScreen extends Screen
{ {
guiStack.drawString(font, text, x, y, color); guiStack.drawString(font, text, x, y, color);
} }
//protected void DhRenderTooltip(GuiGraphics guiStack, Font font, List<? extends net.minecraft.util.FormattedCharSequence> text, int x, int y) protected void DhRenderTooltip(GuiGraphics guiStack, Font font, List<? extends net.minecraft.util.FormattedCharSequence> text, int x, int y)
//{ {
// //guiStack.renderTooltip(font, text, x, y); guiStack.renderTooltip(font, text, x, y);
//} }
protected void DhRenderComponentTooltip(GuiGraphics guiStack, Font font, List<Component> comp, int x, int y) protected void DhRenderComponentTooltip(GuiGraphics guiStack, Font font, List<Component> comp, int x, int y)
{ {
guiStack.setComponentTooltipForNextFrame(font, comp, x, y); guiStack.renderComponentTooltip(font, comp, x, y);
} }
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, Component text, int x, int y) protected void DhRenderTooltip(GuiGraphics guiStack, Font font, Component text, int x, int y)
{ {
guiStack.setTooltipForNextFrame(font, text, x, y); guiStack.renderTooltip(font, text, x, y);
} }
#endif #endif
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -19,41 +19,31 @@
package com.seibel.distanthorizons.common.wrappers.gui; package com.seibel.distanthorizons.common.wrappers.gui;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
#if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.components.Button;
#endif
#if MC_VER < MC_1_17_1
import net.minecraft.client.gui.components.ImageButton;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
#elif MC_VER < MC_1_20_1
import net.minecraft.client.gui.components.ImageButton;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.renderer.GameRenderer;
#elif MC_VER < MC_1_20_2
import net.minecraft.client.gui.components.ImageButton;
import net.minecraft.client.gui.GuiGraphics;
#elif MC_VER < MC_1_21_6
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.RenderType;
#else
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderPipelines;
#endif
/** /**
* Creates a button with a texture on it (and a background) that works with all mc versions * Creates a button with a texture on it (and a background) that works with all mc versions
* *
* @author coolGi * @author coolGi
* @version 2023-10-03 * @version 2023-10-03
*/ */
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.components.AbstractButton;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ImageButton;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
#if MC_VER >= MC_1_17_1
import net.minecraft.client.renderer.GameRenderer;
#endif
#if MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
#else
import net.minecraft.client.gui.GuiGraphics;
#endif
#if MC_VER < MC_1_20_2 #if MC_VER < MC_1_20_2
public class TexturedButtonWidget extends ImageButton public class TexturedButtonWidget extends ImageButton
#else #else
@@ -67,21 +57,20 @@ public class TexturedButtonWidget extends Button
private final int v; private final int v;
private final int hoveredVOffset; private final int hoveredVOffset;
private final ResourceLocation textureResourceLocation; private final ResourceLocation texture;
private final int textureWidth; private final int textureWidth;
private final int textureHeight; private final int textureHeight;
#endif #endif
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text) public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction, Component text) {
{ this(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text, true);
this(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text, true);
} }
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground) public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground)
{ {
#if MC_VER < MC_1_20_2 #if MC_VER < MC_1_20_2
super(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text); super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text);
#else #else
// We don't pass on the text option as otherwise it will render (we normally pass it for narration) // We don't pass on the text option as otherwise it will render (we normally pass it for narration)
// TODO: Find a fix for it // TODO: Find a fix for it
@@ -91,7 +80,7 @@ public class TexturedButtonWidget extends Button
this.v = v; this.v = v;
this.hoveredVOffset = hoveredVOffset; this.hoveredVOffset = hoveredVOffset;
this.textureResourceLocation = textureResourceLocation; this.texture = texture;
this.textureWidth = textureWidth; this.textureWidth = textureWidth;
this.textureHeight = textureHeight; this.textureHeight = textureHeight;
@@ -103,8 +92,7 @@ public class TexturedButtonWidget extends Button
#if MC_VER < MC_1_20_2 #if MC_VER < MC_1_20_2
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
@Override @Override
public void renderButton(PoseStack matrices, int mouseX, int mouseY, float delta) public void renderButton(PoseStack matrices, int mouseX, int mouseY, float delta) {
{
if (this.renderBackground) // Renders the background of the button if (this.renderBackground) // Renders the background of the button
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
@@ -131,7 +119,6 @@ public class TexturedButtonWidget extends Button
super.renderButton(matrices, mouseX, mouseY, delta); super.renderButton(matrices, mouseX, mouseY, delta);
} }
#else #else
#if MC_VER < MC_1_20_1 #if MC_VER < MC_1_20_1
@Override @Override
@@ -167,63 +154,24 @@ public class TexturedButtonWidget extends Button
super.renderWidget(matrices, mouseX, mouseY, delta); super.renderWidget(matrices, mouseX, mouseY, delta);
} }
#endif #endif
#else #else
@Override @Override
public void renderWidget(GuiGraphics matrices, int mouseX, int mouseY, float delta) public void renderWidget(GuiGraphics matrices, int mouseX, int mouseY, float delta)
{ {
if (this.renderBackground) if (this.renderBackground)
{ {
#if MC_VER < MC_1_21_3 //RenderSystem.enableBlend();
//RenderSystem.enableDepthTest();
matrices.blitSprite(SPRITES.get(this.active, this.isHoveredOrFocused()), this.getX(), this.getY(), this.getWidth(), this.getHeight()); matrices.blitSprite(SPRITES.get(this.active, this.isHoveredOrFocused()), this.getX(), this.getY(), this.getWidth(), this.getHeight());
#elif MC_VER < MC_1_21_6
matrices.blitSprite(
RenderType::guiTextured,
SPRITES.get(this.active, this.isHoveredOrFocused()),
this.getX(), this.getY(),
this.getWidth(), this.getHeight());
#else
matrices.blitSprite(
RenderPipelines.GUI_TEXTURED,
SPRITES.get(this.active, this.isHoveredOrFocused()),
this.getX(), this.getY(),
this.getWidth(), this.getHeight());
#endif
} }
// Renders the sprite // Renders the sprite
int i = 0; int i = 0;
if (!this.active) if (!this.active) i = 2;
{ else if (this.isHovered) i = 1;
i = 2;
}
else if (this.isHovered)
{
i = 1;
}
#if MC_VER < MC_1_21_3 matrices.blit(this.texture, this.getX(), this.getY(), this.u, this.v + (this.hoveredVOffset * i), this.width, this.height, this.textureWidth, this.textureHeight);
matrices.blit(this.textureResourceLocation, this.getX(), this.getY(), this.u, this.v + (this.hoveredVOffset * i), this.width, this.height, this.textureWidth, this.textureHeight);
#elif MC_VER < MC_1_21_6
matrices.blit(
RenderType::guiTextured,
this.textureResourceLocation,
this.getX(), this.getY(),
this.u, this.v + (this.hoveredVOffset * i),
this.width, this.height,
this.textureWidth, this.textureHeight);
#else
matrices.blit(
RenderPipelines.GUI_TEXTURED,
this.textureResourceLocation,
this.getX(), this.getY(),
this.u, this.v + (this.hoveredVOffset * i),
this.width, this.height,
this.textureWidth, this.textureHeight);
#endif
} }
#endif #endif
} }
@@ -1,8 +1,8 @@
package com.seibel.distanthorizons.common.wrappers.gui.updater; package com.seibel.distanthorizons.common.wrappers.gui.updater;
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen; import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.jar.installer.MarkdownFormatter; import com.seibel.distanthorizons.core.jar.installer.MarkdownFormatter;
@@ -14,7 +14,6 @@ import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.apache.logging.log4j.Logger;
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.narration.NarratableEntry;
@@ -22,7 +21,6 @@ import net.minecraft.client.gui.narration.NarratableEntry;
#if MC_VER < MC_1_20_1 #if MC_VER < MC_1_20_1
import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.GuiComponent;
import com.mojang.blaze3d.vertex.PoseStack;
#else #else
import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.GuiGraphics;
#endif #endif
@@ -41,9 +39,6 @@ import java.util.*;
// TODO: Make this // TODO: Make this
public class ChangelogScreen extends DhScreen public class ChangelogScreen extends DhScreen
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private Screen parent; private Screen parent;
private String versionID; private String versionID;
private List<String> changelog; private List<String> changelog;
@@ -56,32 +51,24 @@ public class ChangelogScreen extends DhScreen
this(parent, null); this(parent, null);
if (!ModrinthGetter.initted) // Make sure the modrinth stuff is initted if (!ModrinthGetter.initted) // Make sure the modrinth stuff is initted
{
ModrinthGetter.init(); ModrinthGetter.init();
}
if (!ModrinthGetter.initted) // If its not initted, then this isnt usable if (!ModrinthGetter.initted) // If its not initted, then this isnt usable
{
return; return;
}
if (!ModrinthGetter.mcVersions.contains(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion())) if (!ModrinthGetter.mcVersions.contains(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()))
{
return; return;
}
String versionID = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()); String versionID = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
if (versionID == null) if (versionID == null)
{
return; return;
}
try try
{ {
this.setupChangelog(versionID); setupChangelog(versionID);
this.usable = true; usable = true;
} }
catch (Exception e) catch (Exception e)
{ {
LOGGER.error("failed to setup changelog, error: ["+e.getMessage()+"].", e); e.printStackTrace();
} }
} }
@@ -93,13 +80,11 @@ public class ChangelogScreen extends DhScreen
if (versionID == null) if (versionID == null)
{
return; return;
}
try try
{ {
this.setupChangelog(versionID); setupChangelog(versionID);
this.usable = true; usable = true;
} }
catch (Exception e) catch (Exception e)
{ {
@@ -144,10 +129,8 @@ public class ChangelogScreen extends DhScreen
protected void init() protected void init()
{ {
super.init(); super.init();
if (!this.usable) if (!usable)
{
return; return;
}
this.addBtn( // Close this.addBtn( // Close
@@ -158,9 +141,9 @@ public class ChangelogScreen extends DhScreen
this.changelogArea = new TextArea(this.minecraft, this.width * 2, this.height, 32, 32, 10); this.changelogArea = new TextArea(this.minecraft, this.width * 2, this.height, 32, 32, 10);
for (int i = 0; i < this.changelog.size(); i++) for (int i = 0; i < changelog.size(); i++)
{ {
this.changelogArea.addButton(TextOrLiteral(this.changelog.get(i))); this.changelogArea.addButton(TextOrLiteral(changelog.get(i)));
// drawString(matrices, this.font, changelog.get(i), this.width / 2 - 175, this.height / 2 - 100 + i*10, 0xFFFFFF); // drawString(matrices, this.font, changelog.get(i), this.width / 2 - 175, this.height / 2 - 100 + i*10, 0xFFFFFF);
} }
@@ -178,41 +161,29 @@ public class ChangelogScreen extends DhScreen
#else #else
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#endif #endif
if (!this.usable) if (!usable)
{
return; return;
}
int maxScroll;
#if MC_VER <= MC_1_21_3
maxScroll = this.changelogArea.getMaxScroll();
#else
maxScroll = this.changelogArea.maxScrollAmount();
#endif
// Set the scroll position to the mouse height relative to the screen // Set the scroll position to the mouse height relative to the screen
// This is a bit of a hack as we cannot scroll on this area // This is a bit of a hack as we cannot scroll on this area
double scrollAmount = ((double) mouseY) / ((double) this.height) * 1.1 * maxScroll; double scrollAmount = ((double) mouseY) / ((double) this.height) * 1.1 * this.changelogArea.getMaxScroll();
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
this.changelogArea.setScrollAmount(scrollAmount); this.changelogArea.setScrollAmount(scrollAmount);
#elif MC_VER <= MC_1_21_3
this.changelogArea.scrollAmount = scrollAmount;
#else #else
this.changelogArea.setScrollAmount(scrollAmount); this.changelogArea.scrollAmount = scrollAmount;
#endif #endif
// render order matters, otherwise on 1.20.6+ the blurred background will render on top of the text // render order matters, otherwise on 1.20.6+ the blurred background will render on top of the text
super.render(matrices, mouseX, mouseY, delta); // Render the buttons super.render(matrices, mouseX, mouseY, delta); // Render the buttons
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
this.DhDrawCenteredString(matrices, this.font, this.title, this.width / 2, 15, 0xFFFFFF); // Render title DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
} }
@Override @Override
public void onClose() public void onClose()
{ {
Objects.requireNonNull(this.minecraft).setScreen(this.parent); // Goto the parent screen Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
} }
public static class TextArea extends ContainerObjectSelectionList<ButtonEntry> public static class TextArea extends ContainerObjectSelectionList<ButtonEntry>
@@ -227,7 +198,7 @@ public class ChangelogScreen extends DhScreen
super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing); super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing);
#endif #endif
this.centerListVertically = false; this.centerListVertically = false;
this.textRenderer = minecraftClient.font; textRenderer = minecraftClient.font;
} }
public void addButton(Component text) public void addButton(Component text)
@@ -269,20 +240,20 @@ public class ChangelogScreen extends DhScreen
@Override @Override
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
{ {
matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFF); matrices.drawString(textRenderer, text, 12, y + 5, 0xFFFFFF);
} }
#endif #endif
@Override @Override
public List<? extends GuiEventListener> children() public List<? extends GuiEventListener> children()
{ {
return this.children; return children;
} }
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
@Override @Override
public List<? extends NarratableEntry> narratables() public List<? extends NarratableEntry> narratables()
{ {
return this.children; return children;
} }
#endif #endif
} }
@@ -4,7 +4,6 @@ import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen; import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget; import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.distanthorizons.core.jar.ModJarInfo; import com.seibel.distanthorizons.core.jar.ModJarInfo;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter; import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
@@ -16,7 +15,6 @@ import com.mojang.blaze3d.vertex.PoseStack;
#endif #endif
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import org.apache.logging.log4j.Logger;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*; import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
@@ -31,9 +29,6 @@ import java.util.*;
// and also maybe add this suggestion https://discord.com/channels/881614130614767666/1035863487110467625/1035949054485594192 // and also maybe add this suggestion https://discord.com/channels/881614130614767666/1035863487110467625/1035949054485594192
public class UpdateModScreen extends DhScreen public class UpdateModScreen extends DhScreen
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private Screen parent; private Screen parent;
private String newVersionID; private String newVersionID;
@@ -41,7 +36,7 @@ public class UpdateModScreen extends DhScreen
private String nextVer; private String nextVer;
public UpdateModScreen(Screen parent, String newVersionID) throws IllegalArgumentException public UpdateModScreen(Screen parent, String newVersionID)
{ {
super(Translatable(ModInfo.ID + ".updater.title")); super(Translatable(ModInfo.ID + ".updater.title"));
this.parent = parent; this.parent = parent;
@@ -59,13 +54,6 @@ public class UpdateModScreen extends DhScreen
this.currentVer = ModJarInfo.Git_Commit.substring(0,7); this.currentVer = ModJarInfo.Git_Commit.substring(0,7);
this.nextVer = this.newVersionID.substring(0,7); this.nextVer = this.newVersionID.substring(0,7);
} }
// done to prevent trying to update to "null"
// (this can happen if no versions are available to check/download from modrinth/gitlab)
if (this.nextVer == null)
{
throw new IllegalArgumentException("No new version found with the ID ["+newVersionID+"].");
}
} }
@Override @Override
@@ -81,9 +69,9 @@ public class UpdateModScreen extends DhScreen
// Logo image // Logo image
this.addBtn(new TexturedButtonWidget( this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen // Where the button is on the screen
this.width / 2 - 95, this.height / 2 - 110, this.width / 2 - 65, this.height / 2 - 110,
// Width and height of the button // Width and height of the button
195, 65, 130, 65,
// Offset // Offset
0, 0, 0, 0,
// Some textuary stuff // Some textuary stuff
@@ -93,7 +81,7 @@ public class UpdateModScreen extends DhScreen
#else #else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "logo.png"), ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "logo.png"),
#endif #endif
195, 65, 130, 65,
// Create the button and tell it where to go // Create the button and tell it where to go
// For now it goes to the client option by default // For now it goes to the client option by default
(buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti) (buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
@@ -105,7 +93,7 @@ public class UpdateModScreen extends DhScreen
} }
catch (Exception e) catch (Exception e)
{ {
LOGGER.error("Failed to setup update mod screen, error: ["+e.getMessage()+"].", e); e.printStackTrace();
} }
if (!ModInfo.IS_DEV_BUILD) if (!ModInfo.IS_DEV_BUILD)
@@ -169,10 +157,8 @@ public class UpdateModScreen extends DhScreen
{ {
#if MC_VER < MC_1_20_2 #if MC_VER < MC_1_20_2
this.renderBackground(matrices); // Render background this.renderBackground(matrices); // Render background
#elif MC_VER < MC_1_21_6
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#else #else
// background blur is already being rendered, rendering again causes the game to crash this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#endif #endif
// TODO: add the tooltips for the buttons // TODO: add the tooltips for the buttons
@@ -180,30 +166,16 @@ public class UpdateModScreen extends DhScreen
// TODO: Add tooltips // TODO: Add tooltips
// Render the text's // Render the text's
this.DhDrawCenteredString(matrices, this.font, DhDrawCenteredString(matrices, this.font, Translatable(ModInfo.ID + ".updater.text1"), this.width / 2, this.height / 2 - 35, 0xFFFFFF);
Translatable(ModInfo.ID + ".updater.text1"), DhDrawCenteredString(matrices, this.font,
this.width / 2, this.height / 2 - 35, Translatable(ModInfo.ID + ".updater.text2", currentVer, nextVer),
#if MC_VER < MC_1_21_6 this.width / 2, this.height / 2 - 20, 0x52FD52);
0xFFFFFF // RGB
#else
0xFFFFFFFF // ARGB
#endif
);
this.DhDrawCenteredString(matrices, this.font,
Translatable(ModInfo.ID + ".updater.text2", this.currentVer, this.nextVer),
this.width / 2, this.height / 2 - 20,
#if MC_VER < MC_1_21_6
0x52FD52 // RGB
#else
0xFF52FD52 // ARGB
#endif
);
} }
@Override @Override
public void onClose() public void onClose()
{ {
Objects.requireNonNull(this.minecraft).setScreen(this.parent); // Go to the parent screen Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
} }
} }
@@ -13,12 +13,10 @@ public class KeyedClientLevelManager implements IKeyedClientLevelManager
/** This is set and managed by the ClientApi for servers with support for DH. */ /** This is set and managed by the ClientApi for servers with support for DH. */
@Nullable @Nullable
private IServerKeyedClientLevel serverKeyedLevel = null; private IServerKeyedClientLevel serverKeyedLevel = null;
/** Allows to keep level manager enabled between loading different keyed levels */
private boolean enabled = false; private boolean enabled = false;
//=============// //=============//
// constructor // // constructor //
//=============// //=============//
@@ -31,25 +29,39 @@ public class KeyedClientLevelManager implements IKeyedClientLevelManager
// level override logic // // level override logic //
//======================// //======================//
@Override
@Nullable
public IServerKeyedClientLevel getServerKeyedLevel() { return this.serverKeyedLevel; }
@Override @Override
public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String serverKey, String levelKey) @Nullable
public IServerKeyedClientLevel getServerKeyedLevel()
{ {
IServerKeyedClientLevel keyedLevel = new ServerKeyedClientLevel((ClientLevel) clientLevel.getWrappedMcObject(), serverKey, levelKey); return this.serverKeyedLevel;
}
@Override
public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String levelKey)
{
IServerKeyedClientLevel keyedLevel = new ServerKeyedClientLevel((ClientLevel) clientLevel.getWrappedMcObject(), levelKey);
this.serverKeyedLevel = keyedLevel; this.serverKeyedLevel = keyedLevel;
this.enabled = true; this.enabled = true;
return keyedLevel; return keyedLevel;
} }
@Override @Override
public void clearKeyedLevel() { this.serverKeyedLevel = null; } public void clearServerKeyedLevel()
@Override {
public boolean isEnabled() { return this.enabled; } this.serverKeyedLevel = null;
@Override }
public void disable() { this.enabled = false; }
@Override
public boolean isEnabled()
{
return this.enabled;
}
@Override
public void disable()
{
this.enabled = false;
}
} }
@@ -6,29 +6,23 @@ import net.minecraft.client.multiplayer.ClientLevel;
public class ServerKeyedClientLevel extends ClientLevelWrapper implements IServerKeyedClientLevel public class ServerKeyedClientLevel extends ClientLevelWrapper implements IServerKeyedClientLevel
{ {
/** Returns the folder name the server wants the client to use. */
private final String serverKey;
/** A unique identifier (generally the level's name) for differentiating multiverse levels */ /** A unique identifier (generally the level's name) for differentiating multiverse levels */
private final String serverLevelKey; private final String serverLevelKey;
public ServerKeyedClientLevel(ClientLevel level, String serverLevelKey)
public ServerKeyedClientLevel(ClientLevel level, String serverKey, String serverLevelKey)
{ {
super(level); super(level);
this.serverKey = serverKey;
this.serverLevelKey = serverLevelKey; this.serverLevelKey = serverLevelKey;
} }
@Override
public String getServerKey() { return this.serverKey; }
@Override @Override
public String getServerLevelKey() { return this.serverLevelKey; } public String getServerLevelKey() { return this.serverLevelKey; }
@Override @Override
public String getDhIdentifier() { return this.getServerLevelKey(); } public String getDimensionName()
{
return this.getServerLevelKey();
}
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -22,7 +22,6 @@ package com.seibel.distanthorizons.common.wrappers.minecraft;
import java.io.File; import java.io.File;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.platform.NativeImage;
@@ -54,16 +53,11 @@ import net.minecraft.core.Direction;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TextComponent;
#endif #endif
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
#if MC_VER < MC_1_21_3
#else
import net.minecraft.util.profiling.Profiler;
#endif
/** /**
* A singleton that wraps the Minecraft object. * A singleton that wraps the Minecraft object.
* *
@@ -118,7 +112,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Override @Override
public float getShade(EDhDirection lodDirection) public float getShade(EDhDirection lodDirection)
{ {
EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.Quality.lodShading.get(); EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading.get();
switch (lodShading) switch (lodShading)
{ {
default: default:
@@ -208,46 +202,34 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Override @Override
public UUID getPlayerUUID() { return this.getPlayer().getUUID(); } public UUID getPlayerUUID() { return this.getPlayer().getUUID(); }
@Override
public String getUsername() { return MINECRAFT.getUser().getName(); }
@Override @Override
public DhBlockPos getPlayerBlockPos() public DhBlockPos getPlayerBlockPos()
{ {
LocalPlayer player = this.getPlayer(); BlockPos playerPos = this.getPlayer().blockPosition();
if (player == null)
{
return new DhBlockPos(0, 0, 0);
}
BlockPos playerPos = player.blockPosition();
return new DhBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ()); return new DhBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ());
} }
@Override @Override
public DhChunkPos getPlayerChunkPos() public DhChunkPos getPlayerChunkPos()
{ {
LocalPlayer player = this.getPlayer();
if (player == null)
{
return new DhChunkPos(0, 0);
}
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
ChunkPos playerPos = new ChunkPos(player.blockPosition()); ChunkPos playerPos = new ChunkPos(this.getPlayer().blockPosition());
#else #else
ChunkPos playerPos = player.chunkPosition(); ChunkPos playerPos = this.getPlayer().chunkPosition();
#endif #endif
return new DhChunkPos(playerPos.x, playerPos.z); return new DhChunkPos(playerPos.x, playerPos.z);
} }
@Nullable @Nullable
@Override @Override
public IClientLevelWrapper getWrappedClientLevel() { return this.getWrappedClientLevel(false); } public IClientLevelWrapper getWrappedClientLevel()
{
return this.getWrappedClientLevel(false);
}
@Override @Override
@Nullable @Nullable
public IClientLevelWrapper getWrappedClientLevel(boolean bypassLevelKeyManager) public IClientLevelWrapper getWrappedClientLevel(boolean bypassMultiverse)
{ {
ClientLevel level = MINECRAFT.level; ClientLevel level = MINECRAFT.level;
if (level == null) if (level == null)
@@ -255,26 +237,19 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return null; return null;
} }
return ClientLevelWrapper.getWrapper(level, bypassLevelKeyManager); return ClientLevelWrapper.getWrapper(level, bypassMultiverse);
} }
@Override @Override
public IProfilerWrapper getProfiler() public IProfilerWrapper getProfiler()
{ {
ProfilerFiller profiler;
#if MC_VER < MC_1_21_3
profiler = MINECRAFT.getProfiler();
#else
profiler = Profiler.get();
#endif
if (this.profilerWrapper == null) if (this.profilerWrapper == null)
{ {
this.profilerWrapper = new ProfilerWrapper(profiler); this.profilerWrapper = new ProfilerWrapper(MINECRAFT.getProfiler());
} }
else if (profiler != this.profilerWrapper.profiler) else if (MINECRAFT.getProfiler() != this.profilerWrapper.profiler)
{ {
this.profilerWrapper.profiler = profiler; this.profilerWrapper.profiler = MINECRAFT.getProfiler();
} }
return this.profilerWrapper; return this.profilerWrapper;
@@ -305,27 +280,10 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
{ {
return; return;
} }
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
player.sendMessage(new TextComponent(string), getPlayer().getUUID()); player.sendMessage(new TextComponent(string), getPlayer().getUUID());
#else #else
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false); player.sendSystemMessage(net.minecraft.network.chat.Component.translatable(string));
#endif
}
@Override
public void sendOverlayMessage(String string)
{
LocalPlayer player = this.getPlayer();
if (player == null)
{
return;
}
#if MC_VER < MC_1_19_2
player.displayClientMessage(new TextComponent(string), /*isOverlay*/true);
#else
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/true);
#endif #endif
} }
@@ -362,17 +320,9 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); } public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); }
@Override @Override
public int getPlayerCount() public boolean isWorldInitialized()
{ {
// can be null if the server hasn't finished booting up yet throw new NotImplementedException("TODO");
if (MINECRAFT.getSingleplayerServer() == null)
{
return 1;
}
else
{
return MINECRAFT.getSingleplayerServer().getPlayerCount();
}
} }
} }
@@ -6,34 +6,19 @@ import net.minecraft.server.dedicated.DedicatedServer;
import java.io.File; import java.io.File;
//@Environment(EnvType.SERVER) //@Environment(EnvType.SERVER)
public class MinecraftServerWrapper implements IMinecraftSharedWrapper public class MinecraftDedicatedServerWrapper implements IMinecraftSharedWrapper
{ {
public static final MinecraftServerWrapper INSTANCE = new MinecraftServerWrapper(); public static final MinecraftDedicatedServerWrapper INSTANCE = new MinecraftDedicatedServerWrapper();
private MinecraftDedicatedServerWrapper() { }
public DedicatedServer dedicatedServer = null; public DedicatedServer dedicatedServer = null;
//=============//
// constructor //
//=============//
private MinecraftServerWrapper() { }
//=========//
// methods //
//=========//
@Override @Override
public boolean isDedicatedServer() { return true; } public boolean isDedicatedServer() { return true; }
@Override @Override
public File getInstallationDirectory() public File getInstallationDirectory()
{ {
if (this.dedicatedServer == null) if (this.dedicatedServer == null)
{ {
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server completed initialization!"); throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!");
} }
#if MC_VER < MC_1_21_1 #if MC_VER < MC_1_21_1
@@ -44,9 +29,9 @@ public class MinecraftServerWrapper implements IMinecraftSharedWrapper
} }
@Override @Override
public int getPlayerCount() public boolean isWorldInitialized()
{ {
return this.dedicatedServer.getPlayerCount(); return this.dedicatedServer.getWorldData().overworldData().isInitialized();
} }
} }
@@ -1,252 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.wrappers.minecraft;
#if MC_VER < MC_1_21_5
import com.mojang.blaze3d.platform.GlStateManager;
#elif MC_VER >= MC_1_21_5
import com.mojang.blaze3d.opengl.GlStateManager;
#endif
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL32;
/**
* <b>Why does DH often call GL methods twice? </b><br>
* Once using the base {@link GL32} function and a second time using
* Minecraft's {@link GlStateManager}?<br><br>
*
* <b>Answer: </b><br>
* Compatibility and robustness<br>
* In general all MC rendering should go through MC's {@link GlStateManager},
* however that isn't always the case.
* So, to prevent issues if a mod (or MC itself) calls a direct GL function
* instead of the {@link GlStateManager} wrapper, we need to be sure about what the actual
* set value is (whether setting or getting) and that MC knows what DH has done.
* This way whether a mod (or MC) is using the {@link GlStateManager} or direct GL calls,
* they should always have the correct value for anything DH has modified.
* <br><br>
* This may slow down some low end GPUs that are driver limited,
* however James would rather have slow correct rendering vs fast broken rendering.
*/
public class MinecraftGLWrapper implements IMinecraftGLWrapper
{
public static final MinecraftGLWrapper INSTANCE = new MinecraftGLWrapper();
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
/*
private static final StencilState STENCIL;
*/
// scissor //
/** @see GL32#GL_SCISSOR_TEST */
@Override
public void enableScissorTest()
{
GL32.glEnable(GL32.GL_SCISSOR_TEST);
GlStateManager._enableScissorTest();
}
/** @see GL32#GL_SCISSOR_TEST */
@Override
public void disableScissorTest()
{
GL32.glDisable(GL32.GL_SCISSOR_TEST);
GlStateManager._disableScissorTest();
}
// stencil //
//
// /** @see GL32#GL_SCISSOR_TEST */
// public void enableScissorTest() { GlStateManager._stencilFunc(); }
// /** @see GL32#GL_SCISSOR_TEST */
// public void disableScissorTest() { GlStateManager._disableScissorTest(); }
// depth //
/** @see GL32#GL_DEPTH_TEST */
@Override
public void enableDepthTest()
{
GL32.glEnable(GL32.GL_DEPTH_TEST);
GlStateManager._enableDepthTest();
}
/** @see GL32#GL_DEPTH_TEST */
@Override
public void disableDepthTest()
{
GL32.glDisable(GL32.GL_DEPTH_TEST);
GlStateManager._disableDepthTest();
}
/** @see GL32#glDepthFunc(int) */
@Override
public void glDepthFunc(int func)
{
GL32.glDepthFunc(func);
GlStateManager._depthFunc(func);
}
/** @see GL32#glDepthMask(boolean) */
@Override
public void enableDepthMask()
{
GL32.glDepthMask(true);
GlStateManager._depthMask(true);
}
/** @see GL32#glDepthMask(boolean) */
@Override
public void disableDepthMask()
{
GL32.glDepthMask(false);
GlStateManager._depthMask(false);
}
// blending //
/** @see GL32#GL_BLEND */
@Override
public void enableBlend()
{
GL32.glEnable(GL32.GL_BLEND);
GlStateManager._enableBlend();
}
/** @see GL32#GL_BLEND */
@Override
public void disableBlend()
{
GL32.glDisable(GL32.GL_BLEND);
GlStateManager._disableBlend();
}
/** @see GL32#glBlendFunc */
@Override
public void glBlendFunc(int sfactor, int dfactor)
{
GL32.glBlendFunc(sfactor, dfactor);
#if MC_VER < MC_1_21_5
GlStateManager._blendFunc(sfactor, dfactor);
#endif
}
/** @see GL32#glBlendFuncSeparate */
@Override
public void glBlendFuncSeparate(int sfactorRGB, int dfactorRGB, int sfactorAlpha, int dfactorAlpha)
{
GL32.glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
GlStateManager._blendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
}
// frame buffers //
/** @see GL32#glBindFramebuffer */
@Override
public void glBindFramebuffer(int target, int framebuffer)
{
GL32.glBindFramebuffer(target, framebuffer);
GlStateManager._glBindFramebuffer(target, framebuffer);
}
// buffers //
/** @see GL32#glGenBuffers() */
@Override
public int glGenBuffers()
{ return GlStateManager._glGenBuffers(); }
/** @see GL32#glDeleteBuffers(int) */
@Override
public void glDeleteBuffers(int buffer)
{
GL32.glDeleteBuffers(buffer);
// MC's implementation has a bug where it will throw:
// GL_INVALID_OPERATION in glBufferData(immutable)
// when attempting to delete Storage Buffers
// So we need to manually delete the buffers ourselves
//GlStateManager._glDeleteBuffers(buffer);
}
// culling //
/** @see GL32#GL_CULL_FACE */
@Override
public void enableFaceCulling()
{
GL32.glEnable(GL32.GL_CULL_FACE);
GlStateManager._enableCull();
}
/** @see GL32#GL_CULL_FACE */
@Override
public void disableFaceCulling()
{
GL32.glDisable(GL32.GL_CULL_FACE);
GlStateManager._disableCull();
}
// textures //
/** @see GL32#glGenTextures() */
@Override
public int glGenTextures() { return GlStateManager._genTexture(); }
/** @see GL32#glDeleteTextures(int) */
@Override
public void glDeleteTextures(int texture) { GlStateManager._deleteTexture(texture); }
/** @see GL32#glActiveTexture(int) */
@Override
public void glActiveTexture(int textureId)
{
GL32.glActiveTexture(textureId);
GlStateManager._activeTexture(textureId);
}
@Override
public int getActiveTexture() { return GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D); }
/**
* Always binds to {@link GL32#GL_TEXTURE_2D}
* @see GL32#glBindTexture(int, int)
*/
@Override
public void glBindTexture(int texture)
{
GL32.glBindTexture(GL32.GL_TEXTURE_2D, texture);
GlStateManager._bindTexture(texture);
}
}
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -30,15 +30,11 @@ import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
#if MC_VER < MC_1_17_1 #if MC_VER >= MC_1_17_1
#elif MC_VER < MC_1_21_6
import net.minecraft.client.renderer.FogRenderer; import net.minecraft.client.renderer.FogRenderer;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
#else
import net.minecraft.client.renderer.fog.FogRenderer;
#endif #endif
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
@@ -46,6 +42,9 @@ import org.joml.Matrix4f;
import org.joml.Vector3f; import org.joml.Vector3f;
#else #else
#endif #endif
#if MC_VER >= MC_1_20_2
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
#endif
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -70,11 +69,7 @@ import net.minecraft.world.level.material.FogType;
#endif #endif
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.joml.Vector4f;
#if MC_VER >= MC_1_21_5
import com.mojang.blaze3d.opengl.GlTexture;
#endif
/** /**
* A singleton that contains everything * A singleton that contains everything
@@ -106,19 +101,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
*/ */
public int finalLevelFrameBufferId = -1; public int finalLevelFrameBufferId = -1;
public boolean colorTextureCastFailLogged = false;
public boolean depthTextureCastFailLogged = false;
#if MC_VER < MC_1_21_6
#else
private static FogRenderer mcFogRenderer = null;
#endif
//=========//
// methods //
//=========//
@Override @Override
public Vec3f getLookAtVector() public Vec3f getLookAtVector()
@@ -131,22 +114,11 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
/** Unless you really need to know if the player is blind, use {@link MinecraftRenderWrapper#isFogStateSpecial()}/{@link IMinecraftRenderWrapper#isFogStateSpecial()} instead */ /** Unless you really need to know if the player is blind, use {@link MinecraftRenderWrapper#isFogStateSpecial()}/{@link IMinecraftRenderWrapper#isFogStateSpecial()} instead */
public boolean playerHasBlindingEffect() public boolean playerHasBlindingEffect()
{ {
if (MC.player == null) return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null
{
return false;
}
else if (MC.player.getActiveEffectsMap() == null)
{
return false;
}
else
{
return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null
#if MC_VER >= MC_1_19_2 #if MC_VER >= MC_1_19_2
|| MC.player.getActiveEffectsMap().get(MobEffects.DARKNESS) != null // Deep dark effect || MC.player.getActiveEffectsMap().get(MobEffects.DARKNESS) != null // Deep dark effect
#endif #endif
; ;
}
} }
@Override @Override
@@ -164,55 +136,16 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
float[] colorValues = new float[4]; float[] colorValues = new float[4];
GL15.glGetFloatv(GL15.GL_FOG_COLOR, colorValues); GL15.glGetFloatv(GL15.GL_FOG_COLOR, colorValues);
return new Color( #else
Math.max(0f, Math.min(colorValues[0], 1f)), // r
Math.max(0f, Math.min(colorValues[1], 1f)), // g
Math.max(0f, Math.min(colorValues[2], 1f)), // b
Math.max(0f, Math.min(colorValues[3], 1f)) // a
);
#elif MC_VER < MC_1_21_3
FogRenderer.setupColor(MC.gameRenderer.getMainCamera(), partialTicks, MC.level, 1, MC.gameRenderer.getDarkenWorldAmount(partialTicks)); FogRenderer.setupColor(MC.gameRenderer.getMainCamera(), partialTicks, MC.level, 1, MC.gameRenderer.getDarkenWorldAmount(partialTicks));
float[] colorValues = RenderSystem.getShaderFogColor(); float[] colorValues = RenderSystem.getShaderFogColor();
return new Color(
Math.max(0f, Math.min(colorValues[0], 1f)), // r
Math.max(0f, Math.min(colorValues[1], 1f)), // g
Math.max(0f, Math.min(colorValues[2], 1f)), // b
Math.max(0f, Math.min(colorValues[3], 1f)) // a
);
#elif MC_VER < MC_1_21_6
Vector4f colorValues = FogRenderer.computeFogColor(MC.gameRenderer.getMainCamera(), partialTicks, MC.level, 1, MC.gameRenderer.getDarkenWorldAmount(partialTicks));
return new Color(
Math.max(0f, Math.min(colorValues.x, 1f)), // r
Math.max(0f, Math.min(colorValues.y, 1f)), // g
Math.max(0f, Math.min(colorValues.z, 1f)), // b
Math.max(0f, Math.min(colorValues.w, 1f)) // a
);
#else
if (mcFogRenderer == null)
{
mcFogRenderer = new FogRenderer();
}
if (MC.level == null)
{
// shouldn't happen, but just in case
return Color.white;
}
boolean isFoggy =
MC.level.effects().isFoggyAt(
MC.gameRenderer.getMainCamera().getBlockPosition().getX(),
MC.gameRenderer.getMainCamera().getBlockPosition().getZ())
|| MC.gui.getBossOverlay().shouldCreateWorldFog();
Vector4f colorValues = mcFogRenderer.setupFog(MC.gameRenderer.getMainCamera(), MC.options.getEffectiveRenderDistance(), isFoggy, MC.deltaTracker, MC.gameRenderer.getDarkenWorldAmount(MC.deltaTracker.getGameTimeDeltaPartialTick(true)), MC.level);
return new Color(
Math.max(0f, Math.min(colorValues.x, 1f)), // r
Math.max(0f, Math.min(colorValues.y, 1f)), // g
Math.max(0f, Math.min(colorValues.z, 1f)), // b
Math.max(0f, Math.min(colorValues.w, 1f)) // a
);
#endif #endif
return new Color(
Math.max(0f, Math.min(colorValues[0], 1f)),
Math.max(0f, Math.min(colorValues[1], 1f)),
Math.max(0f, Math.min(colorValues[2], 1f)),
Math.max(0f, Math.min(colorValues[3], 1f))
);
} }
// getSpecialFogColor() is the same as getFogColor() // getSpecialFogColor() is the same as getFogColor()
@@ -224,22 +157,16 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
float frameTime; float frameTime;
#if MC_VER < MC_1_21_1 #if MC_VER < MC_1_21_1
frameTime = MC.getFrameTime(); frameTime = MC.getFrameTime();
#elif MC_VER < MC_1_21_3
frameTime = MC.getTimer().getRealtimeDeltaTicks();
#else #else
frameTime = MC.deltaTracker.getGameTimeDeltaTicks(); frameTime = MC.getTimer().getRealtimeDeltaTicks();
#endif #endif
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), frameTime); Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), frameTime);
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
#elif MC_VER < MC_1_21_3
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
#else #else
int argbColorInt = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);; Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
return ColorUtil.toColorObjARGB(argbColorInt); // TODO MC changed color formats
#endif #endif
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
} }
else else
{ {
@@ -302,26 +229,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
private RenderTarget getRenderTarget() { return MC.getMainRenderTarget(); } private RenderTarget getRenderTarget() { return MC.getMainRenderTarget(); }
@Override
public boolean mcRendersToFrameBuffer()
{
#if MC_VER < MC_1_21_5
return true;
#else
return false;
#endif
}
@Override
public boolean runningLegacyOpenGL()
{
#if MC_VER <= MC_1_16_5
return true;
#else
return false;
#endif
}
@Override @Override
public int getTargetFrameBuffer() public int getTargetFrameBuffer()
{ {
@@ -331,87 +238,25 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
return this.finalLevelFrameBufferId; return this.finalLevelFrameBufferId;
} }
#if MC_VER < MC_1_21_5
return this.getRenderTarget().frameBufferId; return this.getRenderTarget().frameBufferId;
#else
// MC renders to a texture and then directly to the default FBO now
// we need to draw to their texture instead of the FBO
return 0; // 0 is the ID for the default frame buffer
#endif
} }
@Override @Override
public void clearTargetFrameBuffer() { this.finalLevelFrameBufferId = -1; } public void clearTargetFrameBuffer() { this.finalLevelFrameBufferId = -1; }
@Override @Override
public int getDepthTextureId() public int getDepthTextureId() { return this.getRenderTarget().getDepthTextureId(); }
{
#if MC_VER < MC_1_21_5
return this.getRenderTarget().getDepthTextureId();
#else
try
{
GlTexture glTexture = (GlTexture) this.getRenderTarget().getDepthTexture();
if (glTexture == null)
{
// shouldn't happen, but just in case
return 0;
}
return glTexture.glId();
}
catch (ClassCastException e)
{
// only log this error once per session
if (!this.depthTextureCastFailLogged)
{
this.depthTextureCastFailLogged = true;
LOGGER.error("Unable to cast render Target depth texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
}
return 0;
}
#endif
}
@Override
public int getColorTextureId()
{
#if MC_VER < MC_1_21_5
return this.getRenderTarget().getColorTextureId();
#else
try
{
GlTexture glTexture = (GlTexture) this.getRenderTarget().getColorTexture();
if (glTexture == null)
{
// shouldn't happen, but just in case
return 0;
}
return glTexture.glId();
}
catch (ClassCastException e)
{
// only log this error once per session
if (!this.colorTextureCastFailLogged)
{
this.colorTextureCastFailLogged = true;
LOGGER.error("Unable to cast render Target color texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
}
return 0;
}
#endif
}
@Override @Override
public int getTargetFrameBufferViewportWidth() public int getTargetFrameBufferViewportWidth()
{ {
return this.getRenderTarget().viewWidth; return getRenderTarget().viewWidth;
} }
@Override @Override
public int getTargetFrameBufferViewportHeight() public int getTargetFrameBufferViewportHeight()
{ {
return this.getRenderTarget().viewHeight; return getRenderTarget().viewHeight;
} }
@Override @Override
@@ -434,10 +279,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
#endif #endif
} }
/**
* It's better to use {@link MinecraftRenderWrapper#setLightmapId(int, IClientLevelWrapper)} if possible,
* however old MC versions don't support it.
*/
public void updateLightmap(NativeImage lightPixels, IClientLevelWrapper level) public void updateLightmap(NativeImage lightPixels, IClientLevelWrapper level)
{ {
// Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same // Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same
@@ -448,15 +289,5 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper()); LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
wrapper.uploadLightmap(lightPixels); wrapper.uploadLightmap(lightPixels);
} }
public void setLightmapId(int tetxureId, IClientLevelWrapper level)
{
// Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same
// object for the same MC level and/or the same hash,
// so this will have to do for now
IDimensionTypeWrapper dimensionType = level.getDimensionType();
LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
wrapper.setLightmapId(tetxureId);
}
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -31,19 +31,31 @@ public class ProfilerWrapper implements IProfilerWrapper
{ {
public ProfilerFiller profiler; public ProfilerFiller profiler;
public ProfilerWrapper(ProfilerFiller newProfiler) { this.profiler = newProfiler; } public ProfilerWrapper(ProfilerFiller newProfiler)
{
profiler = newProfiler;
}
/** starts a new section inside the currently running section */ /** starts a new section inside the currently running section */
@Override @Override
public void push(String newSection) { this.profiler.push(newSection); } public void push(String newSection)
{
profiler.push(newSection);
}
/** ends the currently running section and starts a new one */ /** ends the currently running section and starts a new one */
@Override @Override
public void popPush(String newSection) { this.profiler.popPush(newSection); } public void popPush(String newSection)
{
profiler.popPush(newSection);
}
/** ends the currently running section */ /** ends the currently running section */
@Override @Override
public void pop() { this.profiler.pop(); } public void pop()
{
profiler.pop();
}
} }
@@ -8,8 +8,4 @@ public interface IMixinServerPlayer
@Nullable @Nullable
ServerLevel distantHorizons$getDimensionChangeDestination(); ServerLevel distantHorizons$getDimensionChangeDestination();
#if MC_VER == MC_1_16_5
void distantHorizons$setDimensionChangeDestination(ServerLevel dimensionChangeDestination);
#endif
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -20,24 +20,16 @@
package com.seibel.distanthorizons.common.wrappers.misc; package com.seibel.distanthorizons.common.wrappers.misc;
import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.platform.NativeImage;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
public class LightMapWrapper implements ILightMapWrapper public class LightMapWrapper implements ILightMapWrapper
{ {
private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private int textureId = 0; private int textureId = 0;
//==============// //==============//
// constructors // // constructors //
//==============// //==============//
@@ -46,67 +38,41 @@ public class LightMapWrapper implements ILightMapWrapper
//==================// //=========//
// lightmap syncing // // methods //
//==================// //=========//
public void uploadLightmap(NativeImage image) public void uploadLightmap(NativeImage image)
{ {
#if MC_VER < MC_1_21_5 int currentBind = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
int currentTexture = GLMC.getActiveTexture();
if (this.textureId == 0) if (this.textureId == 0)
{ {
this.createLightmap(image); this.createLightmap(image);
} }
else else
{ {
GLMC.glBindTexture(this.textureId); GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
} }
image.upload(0, 0, 0, false); image.upload(0, 0, 0, false);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, currentBind);
// getActiveTexture() may return textures that aren't valid and attempting to bind them will
// throw a GL error in MC 1.21.1
if (GL32.glIsTexture(currentTexture))
{
GLMC.glBindTexture(currentTexture);
}
#else
throw new UnsupportedOperationException("setLightmapId should be used for MC versions after 1.21.5"); // TODO that MC version number is wrong, when did we actually start using setLightmapId()?
#endif
} }
private void createLightmap(NativeImage image) private void createLightmap(NativeImage image)
{ {
#if MC_VER < MC_1_21_5 this.textureId = GL32.glGenTextures();
this.textureId = GLMC.glGenTextures(); GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
GLMC.glBindTexture(this.textureId);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, image.format().glFormat(), image.getWidth(), image.getHeight(), GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, image.format().glFormat(), image.getWidth(), image.getHeight(),
0, image.format().glFormat(), GL32.GL_UNSIGNED_BYTE, (ByteBuffer) null); 0, image.format().glFormat(), GL32.GL_UNSIGNED_BYTE, (ByteBuffer) null);
#else
throw new UnsupportedOperationException("setLightmapId should be used for MC versions after 1.21.5"); // TODO that MC version number is wrong, when did we actually start using setLightmapId()?
#endif
} }
public void setLightmapId(int minecraftLightmapTetxureId)
{
// just use the MC texture ID
this.textureId = minecraftLightmapTetxureId;
}
//==============//
// lightmap use //
//==============//
@Override @Override
public void bind() public void bind()
{ {
GLMC.glActiveTexture(GL32.GL_TEXTURE0); GL32.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(this.textureId); GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
} }
@Override @Override
public void unbind() { GLMC.glBindTexture(0); } public void unbind() { GL32.glBindTexture(GL32.GL_TEXTURE_2D, 0); }
} }
@@ -1,30 +0,0 @@
package com.seibel.distanthorizons.common.wrappers.misc;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper;
import net.minecraft.core.BlockPos;
public class MutableBlockPosWrapper implements IMutableBlockPosWrapper
{
public final BlockPos.MutableBlockPos pos;
//=============//
// constructor //
//=============//
public MutableBlockPosWrapper()
{
this.pos = new BlockPos.MutableBlockPos();
}
//===========//
// overrides //
//===========//
@Override
public Object getWrappedMcObject() { return this.pos; }
}
@@ -15,7 +15,7 @@ import java.net.SocketAddress;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
/** /**
* This wrapper transparently ensures that the underlying {@link ServerPlayer} is always valid, * This wrapper transparently ensures that underlying {@link ServerPlayer} is always valid,
* unless the player has disconnected. * unless the player has disconnected.
*/ */
public class ServerPlayerWrapper implements IServerPlayerWrapper public class ServerPlayerWrapper implements IServerPlayerWrapper
@@ -23,41 +23,38 @@ public class ServerPlayerWrapper implements IServerPlayerWrapper
private static final ConcurrentMap<ServerGamePacketListenerImpl, ServerPlayerWrapper> serverPlayerWrapperMap = new MapMaker().weakKeys().weakValues().makeMap(); private static final ConcurrentMap<ServerGamePacketListenerImpl, ServerPlayerWrapper> serverPlayerWrapperMap = new MapMaker().weakKeys().weakValues().makeMap();
private final ServerGamePacketListenerImpl connection; private final ServerGamePacketListenerImpl connection;
private ServerPlayer serverPlayer()
{
return this.connection.player;
//=============// }
// constructor //
//=============//
public static ServerPlayerWrapper getWrapper(ServerPlayer serverPlayer) public static ServerPlayerWrapper getWrapper(ServerPlayer serverPlayer)
{ return serverPlayerWrapperMap.computeIfAbsent(serverPlayer.connection, ignored -> new ServerPlayerWrapper(serverPlayer.connection)); } {
return serverPlayerWrapperMap.computeIfAbsent(serverPlayer.connection, ignored -> new ServerPlayerWrapper(serverPlayer.connection));
}
private ServerPlayerWrapper(ServerGamePacketListenerImpl connection) { this.connection = connection; } private ServerPlayerWrapper(ServerGamePacketListenerImpl connection)
{
this.connection = connection;
}
//=========//
// getters //
//=========//
private ServerPlayer getServerPlayer() { return this.connection.player; }
@Override @Override
public String getName() { return this.getServerPlayer().getName().getString(); } public String getName()
{
return this.serverPlayer().getName().getString();
}
@Override @Override
public IServerLevelWrapper getLevel() public IServerLevelWrapper getLevel()
{ {
ServerLevel level = ((IMixinServerPlayer) this.getServerPlayer()).distantHorizons$getDimensionChangeDestination(); ServerLevel level = ((IMixinServerPlayer) this.serverPlayer()).distantHorizons$getDimensionChangeDestination();
if (level == null) if (level == null)
{ {
#if MC_VER < MC_1_20_1 #if MC_VER < MC_1_20_1
level = this.getServerPlayer().getLevel(); level = this.serverPlayer().getLevel();
#elif MC_VER < MC_1_21_6
level = this.getServerPlayer().serverLevel();
#else #else
level = this.getServerPlayer().level(); level = this.serverPlayer().serverLevel();
#endif #endif
} }
@@ -67,58 +64,57 @@ public class ServerPlayerWrapper implements IServerPlayerWrapper
@Override @Override
public Vec3d getPosition() public Vec3d getPosition()
{ {
Vec3 position = this.getServerPlayer().position(); Vec3 position = this.serverPlayer().position();
return new Vec3d(position.x, position.y, position.z); return new Vec3d(position.x, position.y, position.z);
} }
@Override @Override
public int getViewDistance() public int getViewDistance()
{ {
#if MC_VER < MC_1_21_6 return this.serverPlayer().server.getPlayerList().getViewDistance();
return this.getServerPlayer().server.getPlayerList().getViewDistance();
#else
return this.getServerPlayer().getServer().getPlayerList().getViewDistance();
#endif
} }
@Override @Override
public SocketAddress getRemoteAddress() public SocketAddress getRemoteAddress()
{ {
#if MC_VER >= MC_1_19_4 #if MC_VER >= MC_1_19_4
return this.getServerPlayer().connection.getRemoteAddress(); return this.serverPlayer().connection.getRemoteAddress();
#else // < 1.19.4 #else // < 1.19.4
return this.getServerPlayer().connection.connection.getRemoteAddress(); return this.serverPlayer().connection.connection.getRemoteAddress();
#endif #endif
} }
//================//
// base overrides //
//================//
@Override @Override
public Object getWrappedMcObject() { return this.getServerPlayer(); } public Object getWrappedMcObject()
@Override
public String toString() { return "Wrapped{" + this.getServerPlayer() + "}"; }
@Override
public boolean equals(Object obj)
{ {
if (this == obj) return this.serverPlayer();
}
@Override
public String toString()
{
return "Wrapped{" + this.serverPlayer() + "}";
}
@Override
public boolean equals(Object o)
{
if (this == o)
{ {
return true; return true;
} }
if (!(obj instanceof ServerPlayerWrapper)) if (!(o instanceof ServerPlayerWrapper))
{ {
return false; return false;
} }
ServerPlayerWrapper that = (ServerPlayerWrapper) obj; ServerPlayerWrapper that = (ServerPlayerWrapper) o;
return Objects.equal(this.connection, that.connection); return Objects.equal(this.connection, that.connection);
} }
@Override @Override
public int hashCode() { return Objects.hashCode(this.connection); } public int hashCode()
{
return Objects.hashCode(this.connection);
}
} }
@@ -25,19 +25,14 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.phys.Vec3;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.awt.*; import java.awt.*;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
#if MC_VER <= MC_1_20_4 #if MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
@@ -45,21 +40,10 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
#if MC_VER < MC_1_21_3
import net.minecraft.world.phys.Vec3;
#else
import com.seibel.distanthorizons.core.util.ColorUtil;
#endif
public class ClientLevelWrapper implements IClientLevelWrapper public class ClientLevelWrapper implements IClientLevelWrapper
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName()); private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName());
/** private static final ConcurrentHashMap<ClientLevel, ClientLevelWrapper> LEVEL_WRAPPER_BY_CLIENT_LEVEL = new ConcurrentHashMap<>(); // TODO can leak
* weak references are to prevent rare issues
* where, upon world closure, some levels aren't shutdown/removed properly
* and/or for servers were the level object isn't consistent
*/
private static final Map<ClientLevel, WeakReference<ClientLevelWrapper>> LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL = Collections.synchronizedMap(new WeakHashMap<>());
private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class); private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class);
private static final Minecraft MINECRAFT = Minecraft.getInstance(); private static final Minecraft MINECRAFT = Minecraft.getInstance();
@@ -67,10 +51,6 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private final ClientLevel level; private final ClientLevel level;
private final ConcurrentHashMap<BlockState, ClientBlockStateColorCache> blockCache = new ConcurrentHashMap<>(); private final ConcurrentHashMap<BlockState, ClientBlockStateColorCache> blockCache = new ConcurrentHashMap<>();
/** cached method reference to reduce GC overhead */
private final Function<BlockState, ClientBlockStateColorCache> cachedBlockColorCacheFunction = (blockState) -> this.createBlockColorCache(blockState);
private BlockStateWrapper dirtBlockWrapper; private BlockStateWrapper dirtBlockWrapper;
private BiomeWrapper plainsBiomeWrapper; private BiomeWrapper plainsBiomeWrapper;
@Deprecated // TODO circular references are bad @Deprecated // TODO circular references are bad
@@ -86,11 +66,14 @@ public class ClientLevelWrapper implements IClientLevelWrapper
//==================// //===============//
// instance methods // // wrapper logic //
//==================// //===============//
public static IClientLevelWrapper getWrapper(@NotNull ClientLevel level) { return getWrapper(level, false); } public static IClientLevelWrapper getWrapper(@NotNull ClientLevel level)
{
return getWrapper(level, false);
}
@Nullable @Nullable
public static IClientLevelWrapper getWrapper(@Nullable ClientLevel level, boolean bypassLevelKeyManager) public static IClientLevelWrapper getWrapper(@Nullable ClientLevel level, boolean bypassLevelKeyManager)
@@ -110,31 +93,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
} }
} }
return LEVEL_WRAPPER_BY_CLIENT_LEVEL.computeIfAbsent(level, ClientLevelWrapper::new);
WeakReference<ClientLevelWrapper> levelRef = LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.get(level);
if (levelRef != null)
{
ClientLevelWrapper levelWrapper = levelRef.get();
if (levelWrapper != null)
{
return levelWrapper;
}
}
return LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.compute(level, (newLevel, newLevelRef) ->
{
if (newLevelRef != null)
{
ClientLevelWrapper oldLevelWrapper = newLevelRef.get();
if (oldLevelWrapper != null)
{
return newLevelRef;
}
}
return new WeakReference<>(new ClientLevelWrapper(newLevel));
}).get();
} }
@Nullable @Nullable
@@ -168,8 +127,6 @@ public class ClientLevelWrapper implements IClientLevelWrapper
} }
} }
//====================// //====================//
// base level methods // // base level methods //
//====================// //====================//
@@ -179,13 +136,10 @@ public class ClientLevelWrapper implements IClientLevelWrapper
{ {
ClientBlockStateColorCache blockColorCache = this.blockCache.computeIfAbsent( ClientBlockStateColorCache blockColorCache = this.blockCache.computeIfAbsent(
((BlockStateWrapper) blockWrapper).blockState, ((BlockStateWrapper) blockWrapper).blockState,
this.cachedBlockColorCacheFunction); (block) -> new ClientBlockStateColorCache(block, this));
return blockColorCache.getColor((BiomeWrapper) biome, pos); return blockColorCache.getColor((BiomeWrapper) biome, pos);
} }
/** used by {@link ClientLevelWrapper#cachedBlockColorCacheFunction} */
private ClientBlockStateColorCache createBlockColorCache(BlockState block) { return new ClientBlockStateColorCache(block, this); }
@Override @Override
public int getDirtBlockColor() public int getDirtBlockColor()
@@ -235,13 +189,10 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Override @Override
public String getDimensionName() { return this.level.dimension().location().toString(); } public String getDimensionName()
{
@Override return this.level.dimension().location().toString();
public long getHashedSeed() { return this.level.getBiomeManager().biomeZoomSeed; } }
@Override
public String getDhIdentifier() { return this.getHashedSeedEncoded() + "@" + this.getDimensionName(); }
@Override @Override
public EDhApiLevelType getLevelType() { return EDhApiLevelType.CLIENT_LEVEL; } public EDhApiLevelType getLevelType() { return EDhApiLevelType.CLIENT_LEVEL; }
@@ -262,10 +213,8 @@ public class ClientLevelWrapper implements IClientLevelWrapper
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
return 0; return 0;
#elif MC_VER < MC_1_21_3
return this.level.getMinBuildHeight();
#else #else
return this.level.getMinY(); return this.level.getMinBuildHeight();
#endif #endif
} }
@@ -283,7 +232,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
return null; return null;
} }
return new ChunkWrapper(chunk, this); return new ChunkWrapper(chunk, this.level, this);
} }
@Override @Override
@@ -295,7 +244,9 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Override @Override
public IBlockStateWrapper getBlockState(DhBlockPos pos) public IBlockStateWrapper getBlockState(DhBlockPos pos)
{ return BlockStateWrapper.fromBlockState(this.level.getBlockState(McObjectConverter.Convert(pos)), this); } {
return BlockStateWrapper.fromBlockState(this.level.getBlockState(McObjectConverter.Convert(pos)), this);
}
@Override @Override
public IBiomeWrapper getBiome(DhBlockPos pos) { return BiomeWrapper.getBiomeWrapper(this.level.getBiome(McObjectConverter.Convert(pos)), this); } public IBiomeWrapper getBiome(DhBlockPos pos) { return BiomeWrapper.getBiomeWrapper(this.level.getBiome(McObjectConverter.Convert(pos)), this); }
@@ -306,22 +257,10 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Override @Override
public void onUnload() public void onUnload()
{ {
LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.remove(this.level); LEVEL_WRAPPER_BY_CLIENT_LEVEL.remove(this.level);
this.parentDhLevel = null; this.parentDhLevel = null;
} }
@Override
public File getDhSaveFolder()
{
if (this.parentDhLevel == null)
{
return null;
}
return this.parentDhLevel.getSaveStructure().getSaveFolder(this);
}
//===================// //===================//
@@ -345,13 +284,8 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Override @Override
public Color getCloudColor(float tickDelta) public Color getCloudColor(float tickDelta)
{ {
#if MC_VER < MC_1_21_3
Vec3 colorVec3 = this.level.getCloudColor(tickDelta); Vec3 colorVec3 = this.level.getCloudColor(tickDelta);
return new Color((float)colorVec3.x, (float)colorVec3.y, (float)colorVec3.z); return new Color((float)colorVec3.x, (float)colorVec3.y, (float)colorVec3.z);
#else
int argbColor = this.level.getCloudColor(tickDelta);
return ColorUtil.toColorObjARGB(argbColor);
#endif
} }
@@ -368,7 +302,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
return "Wrapped{null}"; return "Wrapped{null}";
} }
return "Wrapped{" + this.level.toString() + "@" + this.getDhIdentifier() + "}"; return "Wrapped{" + this.level.toString() + "@" + this.getDimensionName() + "}";
} }
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -28,80 +28,78 @@ import net.minecraft.world.level.dimension.DimensionType;
/** /**
* @author James Seibel * @author James Seibel
* @version 2022-9-16
*/ */
public class DimensionTypeWrapper implements IDimensionTypeWrapper public class DimensionTypeWrapper implements IDimensionTypeWrapper
{ {
private static final ConcurrentMap<String, DimensionTypeWrapper> DIMENSION_WRAPPER_BY_NAME = new ConcurrentHashMap<>(); private static final ConcurrentMap<DimensionType, DimensionTypeWrapper> dimensionTypeWrapperMap = new ConcurrentHashMap<>();
private final DimensionType dimensionType; private final DimensionType dimensionType;
public DimensionTypeWrapper(DimensionType dimensionType)
{
//=============// this.dimensionType = dimensionType;
// Constructor // }
//=============//
public DimensionTypeWrapper(DimensionType dimensionType) { this.dimensionType = dimensionType; }
public static DimensionTypeWrapper getDimensionTypeWrapper(DimensionType dimensionType) public static DimensionTypeWrapper getDimensionTypeWrapper(DimensionType dimensionType)
{ {
String dimName = getName(dimensionType); //first we check if the biome has already been wrapped
if (dimensionTypeWrapperMap.containsKey(dimensionType) && dimensionTypeWrapperMap.get(dimensionType) != null)
// check if the dimension has already been wrapped
if (DIMENSION_WRAPPER_BY_NAME.containsKey(dimName)
&& DIMENSION_WRAPPER_BY_NAME.get(dimName) != null)
{ {
return DIMENSION_WRAPPER_BY_NAME.get(dimName); return dimensionTypeWrapperMap.get(dimensionType);
} }
// create the missing wrapper //if it hasn't been created yet, we create it and save it in the map
DimensionTypeWrapper dimensionTypeWrapper = new DimensionTypeWrapper(dimensionType); DimensionTypeWrapper dimensionTypeWrapper = new DimensionTypeWrapper(dimensionType);
DIMENSION_WRAPPER_BY_NAME.put(dimName, dimensionTypeWrapper); dimensionTypeWrapperMap.put(dimensionType, dimensionTypeWrapper);
//we return the newly created wrapper
return dimensionTypeWrapper; return dimensionTypeWrapper;
} }
public static void clearMap() { DIMENSION_WRAPPER_BY_NAME.clear(); } public static void clearMap()
//=================//
// wrapper methods //
//=================//
@Override
public String getName() { return getName(this.dimensionType); }
public static String getName(DimensionType dimensionType)
{ {
#if MC_VER <= MC_1_16_5 dimensionTypeWrapperMap.clear();
}
private String getDimensionName()
{
#if MC_VER >= MC_1_17_1
return this.dimensionType.effectsLocation().getPath();
#else // < 1.17.1
// effectsLocation() is marked as client only, so using the backing field directly // effectsLocation() is marked as client only, so using the backing field directly
return dimensionType.effectsLocation.getPath(); return dimensionType.effectsLocation.getPath();
#else
return dimensionType.effectsLocation().getPath();
#endif #endif
} }
@Override @Override
public boolean hasCeiling() { return this.dimensionType.hasCeiling(); } public boolean hasCeiling()
{
return this.dimensionType.hasCeiling();
}
@Override @Override
public boolean hasSkyLight() { return this.dimensionType.hasSkyLight(); } public boolean hasSkyLight()
{
return this.dimensionType.hasSkyLight();
}
@Override @Override
public Object getWrappedMcObject() { return this.dimensionType; } public Object getWrappedMcObject()
{
return this.dimensionType;
}
@Override
public double getTeleportationScale(IDimensionTypeWrapper to)
{
return DimensionType.getTeleportationScale(this.dimensionType, (DimensionType) to.getWrappedMcObject());
}
// there's definitely a better way of doing this, but it should work well enough for now // there's definitely a better way of doing this, but it should work well enough for now
@Override @Override
public boolean isTheEnd() { return this.getName().equalsIgnoreCase("the_end"); } public boolean isTheEnd() { return this.getDimensionName().equalsIgnoreCase("the_end"); }
@Override
public double getCoordinateScale() { return this.dimensionType.coordinateScale(); }
//================//
// base overrides //
//================//
@Override @Override
public boolean equals(Object obj) public boolean equals(Object obj)
@@ -113,10 +111,9 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
else else
{ {
DimensionTypeWrapper other = (DimensionTypeWrapper) obj; DimensionTypeWrapper other = (DimensionTypeWrapper) obj;
return other.getName().equals(this.getName()); return other.getDimensionName().equals(this.getDimensionName());
} }
} }
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -20,10 +20,6 @@
package com.seibel.distanthorizons.common.wrappers.world; package com.seibel.distanthorizons.common.wrappers.world;
import java.io.File; import java.io.File;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
@@ -42,7 +38,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ChunkSource;
@@ -52,21 +47,15 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
#if MC_VER < MC_1_21_3
#else
import java.nio.file.Path;
#endif
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
/**
* @version 2022-9-16
*/
public class ServerLevelWrapper implements IServerLevelWrapper public class ServerLevelWrapper implements IServerLevelWrapper
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final Logger LOGGER = DhLoggerBuilder.getLogger();
/** private static final ConcurrentHashMap<ServerLevel, ServerLevelWrapper> LEVEL_WRAPPER_BY_SERVER_LEVEL = new ConcurrentHashMap<>();
* weak references are to prevent rare issues
* where, upon world closure, some levels aren't shutdown/removed properly
*/
private static final Map<ServerLevel, WeakReference<ServerLevelWrapper>> LEVEL_WRAPPER_REF_BY_SERVER_LEVEL = Collections.synchronizedMap(new WeakHashMap<>());
private final ServerLevel level; private final ServerLevel level;
@Deprecated // TODO circular references are bad @Deprecated // TODO circular references are bad
@@ -78,88 +67,70 @@ public class ServerLevelWrapper implements IServerLevelWrapper
// constructors // // constructors //
//==============// //==============//
public static ServerLevelWrapper getWrapper(ServerLevel level) public static ServerLevelWrapper getWrapper(ServerLevel level) { return LEVEL_WRAPPER_BY_SERVER_LEVEL.computeIfAbsent(level, ServerLevelWrapper::new); }
{
return LEVEL_WRAPPER_REF_BY_SERVER_LEVEL.compute(level, (newLevel, levelRef) ->
{
if (levelRef != null)
{
ServerLevelWrapper oldLevelWrapper = levelRef.get();
if (oldLevelWrapper != null)
{
return levelRef;
}
}
return new WeakReference<>(new ServerLevelWrapper(newLevel)); public ServerLevelWrapper(ServerLevel level)
}).get(); {
this.level = level;
} }
public ServerLevelWrapper(ServerLevel level) { this.level = level; }
//=========//
//==================// // methods //
// instance methods // //=========//
//==================//
@Override @Override
public File getMcSaveFolder() public File getSaveFolder()
{ {
#if MC_VER < MC_1_21_3
return this.level.getChunkSource().getDataStorage().dataFolder; return this.level.getChunkSource().getDataStorage().dataFolder;
#else
return this.level.getChunkSource().getDataStorage().dataFolder.toFile();
#endif
} }
@Override @Override
public String getWorldFolderName() public DimensionTypeWrapper getDimensionType()
{ {
// Need specifically overworld since it's the only dimension that is stored in a server root folder return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType());
#if MC_VER >= MC_1_21_3
return this.level.getServer().getLevel(Level.OVERWORLD).getChunkSource().getDataStorage().dataFolder.getParent().getFileName().toString();
#else // <= 1.21.3
return this.level.getServer().getLevel(Level.OVERWORLD).getChunkSource().getDataStorage().dataFolder.getParentFile().getName();
#endif
} }
@Override @Override
public DimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); } public String getDimensionName()
{
@Override return this.level.dimension().location().toString();
public String getDimensionName() { return this.level.dimension().location().toString(); } }
@Override
public long getHashedSeed() { return this.level.getBiomeManager().biomeZoomSeed; }
@Override
public String getDhIdentifier() { return this.getDimensionName(); }
@Override @Override
public EDhApiLevelType getLevelType() { return EDhApiLevelType.SERVER_LEVEL; } public EDhApiLevelType getLevelType() { return EDhApiLevelType.SERVER_LEVEL; }
public ServerLevel getLevel() { return this.level; } public ServerLevel getLevel()
{
return this.level;
}
@Override @Override
public boolean hasCeiling() { return this.level.dimensionType().hasCeiling(); } public boolean hasCeiling()
{
return this.level.dimensionType().hasCeiling();
}
@Override @Override
public boolean hasSkyLight() { return this.level.dimensionType().hasSkyLight(); } public boolean hasSkyLight()
{
return this.level.dimensionType().hasSkyLight();
}
@Override @Override
public int getMaxHeight() { return this.level.getHeight(); } public int getMaxHeight()
{
return this.level.getHeight();
}
@Override @Override
public int getMinHeight() public int getMinHeight()
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
return 0; return 0;
#elif MC_VER < MC_1_21_3
return this.level.getMinBuildHeight();
#else #else
return this.level.getMinY(); return this.level.getMinBuildHeight();
#endif #endif
} }
@@ -170,14 +141,12 @@ public class ServerLevelWrapper implements IServerLevelWrapper
{ {
return null; return null;
} }
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false); ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false);
if (chunk == null) if (chunk == null)
{ {
return null; return null;
} }
return new ChunkWrapper(chunk, this.level, this);
return new ChunkWrapper(chunk, this);
} }
@Override @Override
@@ -204,7 +173,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper
public ServerLevel getWrappedMcObject() { return this.level; } public ServerLevel getWrappedMcObject() { return this.level; }
@Override @Override
public void onUnload() { LEVEL_WRAPPER_REF_BY_SERVER_LEVEL.remove(this.level); } public void onUnload() { LEVEL_WRAPPER_BY_SERVER_LEVEL.remove(this.level); }
@Override @Override
@@ -221,18 +190,6 @@ public class ServerLevelWrapper implements IServerLevelWrapper
return this.parentDhLevel.getGenericRenderer(); return this.parentDhLevel.getGenericRenderer();
} }
@Override
public File getDhSaveFolder()
{
if (this.parentDhLevel == null)
{
return null;
}
return this.parentDhLevel.getSaveStructure().getSaveFolder(this);
}
//================// //================//
@@ -240,6 +197,6 @@ public class ServerLevelWrapper implements IServerLevelWrapper
//================// //================//
@Override @Override
public String toString() { return "Wrapped{" + this.level.toString() + "@" + this.getDhIdentifier() + "}"; } public String toString() { return "Wrapped{" + this.level.toString() + "@" + this.getDimensionName() + "}"; }
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -20,10 +20,11 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration; package com.seibel.distanthorizons.common.wrappers.worldGeneration;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.util.concurrent.*; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -45,7 +46,6 @@ public final class GenerationEvent
/** the number of chunks wide this event is */ /** the number of chunks wide this event is */
public final int size; public final int size;
public final EDhApiWorldGenerationStep targetGenerationStep; public final EDhApiWorldGenerationStep targetGenerationStep;
public final EDhApiDistantGeneratorMode generatorMode;
public EventTimer timer = null; public EventTimer timer = null;
public long inQueueTime; public long inQueueTime;
public long timeoutTime = -1; public long timeoutTime = -1;
@@ -56,13 +56,12 @@ public final class GenerationEvent
public GenerationEvent( public GenerationEvent(
DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup, DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer<IChunkWrapper> resultConsumer) EDhApiWorldGenerationStep targetGenerationStep, Consumer<IChunkWrapper> resultConsumer)
{ {
this.inQueueTime = System.nanoTime(); this.inQueueTime = System.nanoTime();
this.id = generationFutureDebugIDs++; this.id = generationFutureDebugIDs++;
this.minPos = minPos; this.minPos = minPos;
this.size = size; this.size = size;
this.generatorMode = generatorMode;
this.targetGenerationStep = targetGenerationStep; this.targetGenerationStep = targetGenerationStep;
this.threadedParam = ThreadedParameters.getOrMake(generationGroup.params); this.threadedParam = ThreadedParameters.getOrMake(generationGroup.params);
this.resultConsumer = resultConsumer; this.resultConsumer = resultConsumer;
@@ -72,11 +71,17 @@ public final class GenerationEvent
public static GenerationEvent startEvent( public static GenerationEvent startEvent(
DhChunkPos minPos, int size, BatchGenerationEnvironment genEnvironment, DhChunkPos minPos, int size, BatchGenerationEnvironment genEnvironment,
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer, EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
ExecutorService worldGeneratorThreadPool) ExecutorService worldGeneratorThreadPool)
{ {
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, generatorMode, target, resultConsumer); //if (size % 2 == 0)
generationEvent.future = CompletableFuture.supplyAsync(() -> //{
// size += 1; // size must be odd for vanilla world gen regions to work
//}
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, target, resultConsumer);
generationEvent.future = CompletableFuture.runAsync(() ->
{ {
long runStartTime = System.nanoTime(); long runStartTime = System.nanoTime();
generationEvent.timeoutTime = runStartTime; generationEvent.timeoutTime = runStartTime;
@@ -84,75 +89,19 @@ public final class GenerationEvent
generationEvent.timer = new EventTimer("setup"); generationEvent.timer = new EventTimer("setup");
BatchGenerationEnvironment.isDistantGeneratorThread.set(true); BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
try try
{ {
genEnvironment.generateLodFromListAsync(generationEvent, (runnable) -> //LOGGER.info("generating [{}]", event.minPos);
{ genEnvironment.generateLodFromList(generationEvent);
worldGeneratorThreadPool.execute(() ->
{
boolean alreadyMarked = BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread();
if (!alreadyMarked)
{
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
}
try
{
runnable.run();
}
catch (Throwable throwable)
{
handleWorldGenThrowable(generationEvent, throwable);
}
finally
{
if (!alreadyMarked)
{
BatchGenerationEnvironment.isDistantGeneratorThread.set(false);
}
}
});
});
}
catch (Throwable initialThrowable)
{
handleWorldGenThrowable(generationEvent, initialThrowable);
} }
catch (InterruptedException ignored) { }
finally finally
{ {
BatchGenerationEnvironment.isDistantGeneratorThread.remove(); BatchGenerationEnvironment.isDistantGeneratorThread.remove();
} }
return null;
}, worldGeneratorThreadPool); }, worldGeneratorThreadPool);
return generationEvent; return generationEvent;
} }
/** There's probably a better way to handle this, but it'll work for now */
private static void handleWorldGenThrowable(GenerationEvent generationEvent, Throwable initialThrowable)
{
Throwable throwable = initialThrowable;
while (throwable instanceof CompletionException)
{
throwable = throwable.getCause();
}
if (throwable instanceof InterruptedException
|| throwable instanceof UncheckedInterruptedException
|| throwable instanceof RejectedExecutionException)
{
// these exceptions can be ignored, generally they just mean
// the thread is busy so it'll need to try again later.
// FIXME this should cause the world gen task to be re-queued so we can try again later
// however, currently it can cause large gaps in the world gen instead.
// These gaps will generate correctly if the level is reloaded and the world gen is re-queued,
// however this is makes it look like the generator isn't working or skipped something.
}
else
{
generationEvent.future.completeExceptionally(throwable);
}
}
public boolean isComplete() { return this.future.isDone(); } public boolean isComplete() { return this.future.isDone(); }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -50,26 +50,23 @@ import net.minecraft.world.level.storage.WorldData;
public final class GlobalParameters public final class GlobalParameters
{ {
public final ChunkGenerator generator; public final ChunkGenerator generator;
public final IDhServerLevel lodLevel;
public final ServerLevel level;
public final Registry<Biome> biomes;
public final RegistryAccess registry;
public final long worldSeed;
public final DataFixer fixerUpper;
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
public final StructureManager structures; public final StructureManager structures;
#else #else
public final StructureTemplateManager structures; public final StructureTemplateManager structures;
public final RandomState randomState; public final RandomState randomState;
#endif #endif
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
public final WorldGenSettings worldGenSettings; public final WorldGenSettings worldGenSettings;
#else #else
public final WorldOptions worldOptions; public final WorldOptions worldOptions;
#endif #endif
public final IDhServerLevel lodLevel;
public final ServerLevel level;
public final Registry<Biome> biomes;
public final RegistryAccess registry;
public final long worldSeed;
public final DataFixer fixerUpper;
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
public final BiomeManager biomeManager; public final BiomeManager biomeManager;
public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed
@@ -79,34 +76,29 @@ public final class GlobalParameters
{ {
this.lodLevel = lodLevel; this.lodLevel = lodLevel;
this.level = ((ServerLevelWrapper) lodLevel.getServerLevelWrapper()).getWrappedMcObject(); level = ((ServerLevelWrapper) lodLevel.getServerLevelWrapper()).getWrappedMcObject();
MinecraftServer server = this.level.getServer(); MinecraftServer server = level.getServer();
WorldData worldData = server.getWorldData(); WorldData worldData = server.getWorldData();
this.registry = server.registryAccess(); registry = server.registryAccess();
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
this.worldGenSettings = worldData.worldGenSettings(); worldGenSettings = worldData.worldGenSettings();
this.biomes = registry.registryOrThrow(Registry.BIOME_REGISTRY); biomes = registry.registryOrThrow(Registry.BIOME_REGISTRY);
this.worldSeed = worldGenSettings.seed(); worldSeed = worldGenSettings.seed();
#elif MC_VER < MC_1_21_3
this.worldOptions = worldData.worldGenOptions();
this.biomes = registry.registryOrThrow(Registries.BIOME);
this.worldSeed = worldOptions.seed();
#else #else
this.worldOptions = worldData.worldGenOptions(); worldOptions = worldData.worldGenOptions();
this.biomes = this.registry.lookupOrThrow(Registries.BIOME); biomes = registry.registryOrThrow(Registries.BIOME);
this.worldSeed = this.worldOptions.seed(); worldSeed = worldOptions.seed();
#endif #endif
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
this.biomeManager = new BiomeManager(this.level, BiomeManager.obfuscateSeed(this.worldSeed)); biomeManager = new BiomeManager(level, BiomeManager.obfuscateSeed(worldSeed));
this.chunkScanner = this.level.getChunkSource().chunkScanner(); chunkScanner = level.getChunkSource().chunkScanner();
#endif #endif
this.structures = server.getStructureManager(); structures = server.getStructureManager();
this.generator = this.level.getChunkSource().getGenerator(); generator = level.getChunkSource().getGenerator();
this.fixerUpper = server.getFixerUpper(); fixerUpper = server.getFixerUpper();
#if MC_VER >= MC_1_19_2 #if MC_VER >= MC_1_19_2
this.randomState = this.level.getChunkSource().randomState(); randomState = level.getChunkSource().randomState();
#endif #endif
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU GPL v3 License. * licensed under the GNU GPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject; package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
import com.google.common.collect.Maps;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.Dynamic; import com.mojang.serialization.Dynamic;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
@@ -26,16 +27,21 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGeneratio
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import it.unimi.dsi.fastutil.shorts.ShortList;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
#if MC_VER >= MC_1_19_4 #if MC_VER >= MC_1_19_4
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
@@ -44,6 +50,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.*; import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
@@ -52,22 +59,20 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.*; import net.minecraft.world.level.chunk.*;
#if MC_VER < MC_1_21_3
import net.minecraft.world.level.chunk.storage.ChunkSerializer; import net.minecraft.world.level.chunk.storage.ChunkSerializer;
#else
#endif
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
import net.minecraft.world.level.levelgen.blending.BlendingData; import net.minecraft.world.level.levelgen.blending.BlendingData;
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
import net.minecraft.world.level.levelgen.feature.StructureFeature; import net.minecraft.world.level.levelgen.feature.StructureFeature;
#endif #endif
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
import net.minecraft.world.ticks.LevelChunkTicks; import net.minecraft.world.ticks.LevelChunkTicks;
#endif #endif
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
#endif #endif
@@ -86,13 +91,11 @@ import net.minecraft.world.level.chunk.status.ChunkType;
#endif #endif
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
import org.jetbrains.annotations.Nullable;
public class ChunkLoader public class ChunkLoader
{ {
private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false); private static boolean zeroChunkPosErrorLogged = false;
#if MC_VER >= MC_1_19_2 #if MC_VER >= MC_1_19_2
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
@@ -108,8 +111,6 @@ public class ChunkLoader
private static boolean lightingSectionErrorLogged = false; private static boolean lightingSectionErrorLogged = false;
private static final ConcurrentHashMap<String, Object> LOGGED_ERROR_MESSAGE_MAP = new ConcurrentHashMap<>();
//============// //============//
@@ -124,16 +125,19 @@ public class ChunkLoader
CompoundTag tagLevel = chunkData; CompoundTag tagLevel = chunkData;
#endif #endif
int chunkX = tagGetInt(tagLevel,"xPos"); ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos"));
int chunkZ = tagGetInt(tagLevel, "zPos");
ChunkPos actualPos = new ChunkPos(chunkX, chunkZ);
if (!Objects.equals(chunkPos, actualPos)) if (!Objects.equals(chunkPos, actualPos))
{ {
if (chunkX == 0 && chunkZ == 0) #if MC_VER >= MC_1_18_2
if (actualPos.equals(ChunkPos.ZERO))
#else
if (actualPos.equals(ChunkPos.INVALID_CHUNK_POS))
#endif
{ {
if (!ZERO_CHUNK_POS_ERROR_LOGGED_REF.getAndSet(true)) if (!zeroChunkPosErrorLogged)
{ {
zeroChunkPosErrorLogged = true;
// explicit chunkPos toString is necessary otherwise the JDK 17 compiler breaks // explicit chunkPos toString is necessary otherwise the JDK 17 compiler breaks
LOGGER.warn("Chunk file at ["+chunkPos.toString()+"] doesn't have a chunk pos. \n" + LOGGER.warn("Chunk file at ["+chunkPos.toString()+"] doesn't have a chunk pos. \n" +
"This might happen if the world was created using an external program. \n" + "This might happen if the world was created using an external program. \n" +
@@ -162,7 +166,7 @@ public class ChunkLoader
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK) if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
return null; return null;
#elif MC_VER < MC_1_21_6 #else
BlendingData blendingData = readBlendingData(tagLevel); BlendingData blendingData = readBlendingData(tagLevel);
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
@@ -172,42 +176,17 @@ public class ChunkLoader
if (chunkType == #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK #else ChunkType.PROTOCHUNK #endif && blendingData == null) if (chunkType == #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK #else ChunkType.PROTOCHUNK #endif && blendingData == null)
return null; return null;
#endif #endif
#else
// ignore blending data, there appears to be an issue with parsing it in 1.21.6
BlendingData blendingData = null;
if (chunkType == ChunkType.PROTOCHUNK)
{
return null;
}
#endif #endif
long inhabitedTime = tagGetLong(tagLevel, "InhabitedTime"); long inhabitedTime = tagLevel.getLong("InhabitedTime");
//================== Read params for making the LevelChunk ================== //================== Read params for making the LevelChunk ==================
UpgradeData upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
? new UpgradeData(tagLevel.getCompound(TAG_UPGRADE_DATA)#if MC_VER >= MC_1_17_1 , level #endif )
: UpgradeData.EMPTY;
UpgradeData upgradeData = UpgradeData.EMPTY; boolean isLightOn = tagLevel.getBoolean("isLightOn");
// commented out 2025-06-04 as a test to see if the upgrade data
// is actually necessary for DH or if it can be ignored
// (if it can't be ignored we'll need to handle null responses from tagGetCompoundTag())
//
//#if MC_VER < MC_1_17_1
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA))
// : UpgradeData.EMPTY;
//#elif MC_VER < MC_1_21_5
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
// : UpgradeData.EMPTY;
//#else
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA)
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
// : UpgradeData.EMPTY;
//#endif
boolean isLightOn = tagGetBoolean(tagLevel, "isLightOn");
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer( ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if MC_VER >= MC_1_17_1 , level #endif , level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if MC_VER >= MC_1_17_1 , level #endif ,
@@ -224,21 +203,17 @@ public class ChunkLoader
: new ProtoTickList<Fluid>(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos, : new ProtoTickList<Fluid>(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos,
tagLevel.getList("LiquidsToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif ); tagLevel.getList("LiquidsToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif );
#else #else
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10), LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos); string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos);
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10), LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos); string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
#elif MC_VER < MC_1_21_4 #else
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10), LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
(string -> BuiltInRegistries.BLOCK.getOptional(ResourceLocation.tryParse(string))), chunkPos); (string -> BuiltInRegistries.BLOCK.getOptional(ResourceLocation.tryParse(string))), chunkPos);
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10), LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
string -> BuiltInRegistries.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos); string -> BuiltInRegistries.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
#else #endif
// do we need the ticks for what we're doing?
LevelChunkTicks<Block> blockTicks = new LevelChunkTicks<>();
LevelChunkTicks<Fluid> fluidTicks = new LevelChunkTicks<>();
#endif
#endif #endif
LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel); LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel);
@@ -248,13 +223,14 @@ public class ChunkLoader
LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks, LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks,
fluidTicks, inhabitedTime, levelChunkSections, null); fluidTicks, inhabitedTime, levelChunkSections, null);
#else #else
LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks, LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks,
fluidTicks, inhabitedTime, levelChunkSections, null, blendingData); fluidTicks, inhabitedTime, levelChunkSections, null, blendingData);
#endif #endif
// Set some states after object creation // Set some states after object creation
chunk.setLightCorrect(isLightOn); chunk.setLightCorrect(isLightOn);
readHeightmaps(chunk, chunkData); readHeightmaps(chunk, chunkData);
//readPostPocessings(chunk, chunkData); readPostPocessings(chunk, chunkData);
return chunk; return chunk;
} }
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData) private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
@@ -262,144 +238,88 @@ public class ChunkLoader
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
#elif MC_VER < MC_1_21_3
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
#else #else
Registry<Biome> biomes = level.registryAccess().lookupOrThrow(Registries.BIOME); Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
#endif #endif
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec( Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS)); biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
#elif MC_VER < MC_1_19_2 #elif MC_VER < MC_1_19_2
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec( Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#elif MC_VER < MC_1_21_3
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS)); biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#else #else
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW( Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS)); biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#endif #endif
#endif #endif
int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex]; LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex];
ListTag tagSections = tagGetListTag(chunkData, "Sections", 10); boolean isLightOn = chunkData.getBoolean("isLightOn");
if (tagSections == null || tagSections.isEmpty()) boolean hasSkyLight = level.dimensionType().hasSkyLight();
{ ListTag tagSections = chunkData.getList("Sections", 10);
tagSections = tagGetListTag(chunkData, "sections", 10); if (tagSections.isEmpty()) tagSections = chunkData.getList("sections", 10);
}
for (int j = 0; j < tagSections.size(); ++j)
if (tagSections != null)
{ {
for (int j = 0; j < tagSections.size(); ++j) CompoundTag tagSection = tagSections.getCompound(j);
int sectionYPos = tagSection.getByte("Y");
#if MC_VER < MC_1_18_2
if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12))
{ {
CompoundTag tagSection = tagGetCompoundTag(tagSections, j); LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
if (tagSection == null) levelChunkSection.getStates().read(tagSection.getList("Palette", 10),
{ tagSection.getLongArray("BlockStates"));
continue; levelChunkSection.recalcBlockCounts();
} if (!levelChunkSection.isEmpty())
chunkSections[#if MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
final int sectionYPos = tagGetByte(tagSection, "Y"); = levelChunkSection;
}
#else
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
if (sectionId >= 0 && sectionId < chunkSections.length)
{
PalettedContainer<BlockState> blockStateContainer;
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12)) PalettedContainer<Biome> biomeContainer;
{
LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
levelChunkSection.getStates().read(tagSection.getList("Palette", 10),
tagSection.getLongArray("BlockStates"));
levelChunkSection.recalcBlockCounts();
if (!levelChunkSection.isEmpty())
chunkSections[#if MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
= levelChunkSection;
}
#else #else
int sectionId = level.getSectionIndexFromSectionY(sectionYPos); PalettedContainer<Holder<Biome>> biomeContainer;
if (sectionId >= 0 && sectionId < chunkSections.length)
{
PalettedContainer<BlockState> blockStateContainer;
#if MC_VER < MC_1_18_2
PalettedContainer<Biome> biomeContainer;
#else
PalettedContainer<Holder<Biome>> biomeContainer;
#endif
boolean containsBlockStates;
#if MC_VER < MC_1_21_5
containsBlockStates = tagSection.contains("block_states", 10);
#else
containsBlockStates = tagSection.contains("block_states");
#endif
if (containsBlockStates)
{
#if MC_VER < MC_1_20_6
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
#else
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
.getOrThrow((message) -> logErrorAndReturnException(message));
#endif
}
else
{
blockStateContainer = new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
}
#if MC_VER < MC_1_18_2
biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message))
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#else
boolean containsBiomes;
#if MC_VER < MC_1_21_5
containsBiomes = tagSection.contains("biomes", 10);
#else
containsBiomes = tagSection.contains("biomes");
#endif
if (containsBiomes)
{
#if MC_VER < MC_1_20_6
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
#else
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
.getOrThrow((message) -> logErrorAndReturnException(message));
#endif
}
else
{
biomeContainer = new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(),
#if MC_VER < MC_1_21_3
biomes.getHolderOrThrow(Biomes.PLAINS),
#else
biomes.getOrThrow(Biomes.PLAINS),
#endif
PalettedContainer.Strategy.SECTION_BIOMES);
}
#endif
#if MC_VER < MC_1_20_1
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
#else
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
#endif
}
#endif #endif
blockStateContainer = tagSection.contains("block_states", 10)
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
#if MC_VER < MC_1_20_6
.getOrThrow(false, LOGGER::error)
#else
.getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
#endif
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
#if MC_VER < MC_1_18_2
biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#else
biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
#if MC_VER < MC_1_20_6
.getOrThrow(false, LOGGER::error)
#else
.getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
#endif
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#endif
#if MC_VER < MC_1_20_1
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
#else
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
#endif
} }
#endif
} }
return chunkSections; return chunkSections;
} }
@@ -409,108 +329,48 @@ public class ChunkLoader
#else ChunkType #endif #else ChunkType #endif
readChunkType(CompoundTag tagLevel) readChunkType(CompoundTag tagLevel)
{ {
String statusString = tagGetString(tagLevel,"Status"); ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
if (statusString != null) if (chunkStatus != null)
{ {
ChunkStatus chunkStatus = ChunkStatus.byName(statusString); return chunkStatus.getChunkType();
if (chunkStatus != null)
{
return chunkStatus.getChunkType();
}
} }
#if MC_VER <= MC_1_20_4 return
return ChunkStatus.ChunkType.PROTOCHUNK; #if MC_VER <= MC_1_20_4 ChunkStatus.ChunkType.PROTOCHUNK;
#else #else ChunkType.PROTOCHUNK; #endif
return ChunkType.PROTOCHUNK;
#endif
} }
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData) private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
{ {
CompoundTag tagHeightmaps = tagGetCompoundTag(chunkData, "Heightmaps"); CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps");
if (tagHeightmaps != null) for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
{ {
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter()) String heightmap = type.getSerializationKey();
if (tagHeightmaps.contains(heightmap, 12))
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
}
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
}
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
{
ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
for (int n = 0; n < tagPostProcessings.size(); ++n)
{
ListTag listTag3 = tagPostProcessings.getList(n);
for (int o = 0; o < listTag3.size(); ++o)
{ {
String heightmap = type.getSerializationKey(); chunk.addPackedPostProcess(listTag3.getShort(o), n);
#if MC_VER < MC_1_21_5
if (tagHeightmaps.contains(heightmap, 12))
{
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
}
#else
if (tagHeightmaps.contains(heightmap))
{
Optional<long[]> optionalHeightmap = tagHeightmaps.getLongArray(heightmap);
if (optionalHeightmap.isPresent())
{
chunk.setHeightmap(type, optionalHeightmap.get());
}
}
#endif
} }
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
} }
} }
// commented out as a test as of 2025-06-04 to see if this is actually necessary for DH
// DH probably doesn't need any chunk post-processing data
//private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
//{
// ListTag tagPostProcessings = tagGetListTag(chunkData,"PostProcessing", 9);
// if (tagPostProcessings != null)
// {
// for (int i = 0; i < tagPostProcessings.size(); ++i)
// {
// ListTag listTag3 = tagGetListTag(tagPostProcessings, i);
// for (int j = 0; j < listTag3.size(); ++j)
// {
// #if MC_VER < MC_1_21_3
// chunk.addPackedPostProcess(listTag3.getShort(j), i);
// #else
// chunk.addPackedPostProcess(ShortList.of(tagGetShort(listTag3, j)), i);
// #endif
// }
// }
// }
//}
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
private static BlendingData readBlendingData(CompoundTag chunkData) private static BlendingData readBlendingData(CompoundTag chunkData)
{ {
BlendingData blendingData = null; BlendingData blendingData = null;
if (chunkData.contains("blending_data", 10))
boolean containsBlendingData;
#if MC_VER < MC_1_21_5
containsBlendingData = chunkData.contains("blending_data", 10);
#else
containsBlendingData = chunkData.contains("blending_data");
#endif
if (containsBlendingData)
{ {
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data")); Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial(LOGGER::error).orElse(null);
try
{
#if MC_VER < MC_1_21_3
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null);
#else
// blending data appears to have changed as of 1.21.6 causing a class cast exception here due to it being wrapped in a Java.Optional
blendingData = BlendingData.unpack(BlendingData.Packed.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null));
#endif
}
catch (Exception e)
{
String message = e.getMessage();
if (message == null || message.trim().isEmpty())
{
message = "Failed to parse blending data";
}
logParsingWarningOnce(message, e);
}
} }
return blendingData; return blendingData;
} }
@@ -532,7 +392,7 @@ public class ChunkLoader
return null; return null;
#else #else
CombinedChunkLightStorage combinedStorage = new CombinedChunkLightStorage(ChunkWrapper.getInclusiveMinBuildHeight(chunk), ChunkWrapper.getExclusiveMaxBuildHeight(chunk)); CombinedChunkLightStorage combinedStorage = new CombinedChunkLightStorage(ChunkWrapper.getMinBuildHeight(chunk), ChunkWrapper.getMaxBuildHeight(chunk));
ChunkLightStorage blockLightStorage = combinedStorage.blockLightStorage; ChunkLightStorage blockLightStorage = combinedStorage.blockLightStorage;
ChunkLightStorage skyLightStorage = combinedStorage.skyLightStorage; ChunkLightStorage skyLightStorage = combinedStorage.skyLightStorage;
@@ -587,37 +447,33 @@ public class ChunkLoader
// if null all lights = 0 // if null all lights = 0
byte[] blockLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "BlockLight"); byte[] blockLightNibbleArray = chunkSectionCompoundTag.getByteArray("BlockLight");
byte[] skyLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "SkyLight"); byte[] skyLightNibbleArray = chunkSectionCompoundTag.getByteArray("SkyLight");
if (blockLightNibbleArray != null // if any sky light was found then all lights above will be max brightness
&& skyLightNibbleArray != null) if (skyLightNibbleArray.length != 0)
{ {
// if any sky light was found then all lights above will be max brightness foundSkyLight = true;
if (skyLightNibbleArray.length != 0) }
{
foundSkyLight = true;
}
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++) for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++)
{
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
{ {
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++) // chunk sections are also 16 blocks tall
for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++)
{ {
// chunk sections are also 16 blocks tall int blockPosIndex = relY*16*16 + relZ*16 + relX;
for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++) byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex);
byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex);
if (skyLightNibbleArray.length == 0 && foundSkyLight)
{ {
int blockPosIndex = relY*16*16 + relZ*16 + relX; skyLight = LodUtil.MAX_MC_LIGHT;
byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex);
byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex);
if (skyLightNibbleArray.length == 0 && foundSkyLight)
{
skyLight = LodUtil.MAX_MC_LIGHT;
}
int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getInclusiveMinBuildHeight(chunk);
blockLightStorage.set(relX, y, relZ, blockLight);
skyLightStorage.set(relX, y, relZ, skyLight);
} }
int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getMinBuildHeight(chunk);
blockLightStorage.set(relX, y, relZ, blockLight);
skyLightStorage.set(relX, y, relZ, skyLight);
} }
} }
} }
@@ -639,194 +495,13 @@ public class ChunkLoader
} }
} }
//=========//
// logging //
//=========//
private static void logBlockDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message) private static void logBlockDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
{ {
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) -> LOGGER.warn("Unable to deserialize blocks for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+message+"]. This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
{
LOGGER.warn("Unable to deserialize blocks for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
return newMessage;
});
} }
private static void logBiomeDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message) private static void logBiomeDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
{ {
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) -> LOGGER.warn("Unable to deserialize biomes for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+message+"]. This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
{
LOGGER.warn("Unable to deserialize biomes for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
return newMessage;
});
}
private static void logParsingWarningOnce(String message) { logParsingWarningOnce(message, null); }
private static void logParsingWarningOnce(String message, Exception e)
{
if (message == null)
{
return;
}
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
{
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.",
e);
return newMessage;
});
}
private static RuntimeException logErrorAndReturnException(String message)
{
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
{
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
return newMessage;
});
// Currently we want to ignore these errors, if returning null is a problem, we can change this later
return null; //new RuntimeException(message);
}
//====================//
// tag helper methods //
//====================//
// TODO move into separate file (this file is getting long)
// these tag helpers are to simplify tag accessing between MC versions
/** defaults to "false" if the tag isn't present */
private static boolean tagGetBoolean(CompoundTag tag, String key)
{
#if MC_VER < MC_1_21_5
return tag.getBoolean(key);
#else
return tag.getBoolean(key).orElse(false);
#endif
}
/** defaults to "0" if the tag isn't present */
private static byte tagGetByte(CompoundTag tag, String key)
{
#if MC_VER < MC_1_21_5
return tag.getByte(key);
#else
return tag.getByte(key).orElse((byte)0);
#endif
}
/** defaults to "0" if the tag isn't present */
private static short tagGetShort(ListTag tag, int index)
{
#if MC_VER < MC_1_21_5
return tag.getShort(index);
#else
return tag.getShort(index).orElse((short)0);
#endif
}
/** defaults to "0" if the tag isn't present */
private static int tagGetInt(CompoundTag tag, String key)
{
#if MC_VER < MC_1_21_5
return tag.getInt(key);
#else
return tag.getInt(key).orElse(0);
#endif
}
/** defaults to "0" if the tag isn't present */
private static long tagGetLong(CompoundTag tag, String key)
{
#if MC_VER < MC_1_21_5
return tag.getInt(key);
#else
return tag.getLong(key).orElse(0L);
#endif
}
/** defaults to null if the tag isn't present */
@Nullable
private static String tagGetString(CompoundTag tag, String key)
{
#if MC_VER < MC_1_21_5
return tag.getString(key);
#else
return tag.getString(key).orElse(null);
#endif
}
/** defaults to null if the tag isn't present */
@Nullable
private static byte[] tagGetByteArray(CompoundTag tag, String key)
{
#if MC_VER < MC_1_21_5
return tag.getByteArray(key);
#else
return tag.getByteArray(key).orElse(null);
#endif
}
/** defaults to null if the tag isn't present */
@Nullable
private static CompoundTag tagGetCompoundTag(CompoundTag tag, String key)
{
#if MC_VER < MC_1_21_5
return tag.getCompound(key);
#else
return tag.getCompound(key).orElse(null);
#endif
}
/** defaults to null if the tag isn't present */
@Nullable
private static CompoundTag tagGetCompoundTag(ListTag tag, int index)
{
#if MC_VER < MC_1_21_5
return tag.getCompound(index);
#else
return tag.getCompound(index).orElse(null);
#endif
}
/**
* defaults to null if the tag isn't present
* @param elementType unused after MC 1.21.5
*/
@Nullable
private static ListTag tagGetListTag(CompoundTag tag, String key, int elementType)
{
#if MC_VER < MC_1_21_5
return tag.getList(key, elementType);
#else
return tag.getList(key).orElse(null);
#endif
}
/** defaults to null if the tag isn't present */
@Nullable
private static ListTag tagGetListTag(ListTag tag, int index)
{
#if MC_VER < MC_1_21_5
return tag.getList(index);
#else
return tag.getList(index).orElse(null);
#endif
} }
@@ -5,24 +5,19 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
import net.minecraft.server.level.GenerationChunkHolder; import net.minecraft.server.level.GenerationChunkHolder;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import java.util.concurrent.CompletableFuture;
public class DhGenerationChunkHolder extends GenerationChunkHolder public class DhGenerationChunkHolder extends GenerationChunkHolder
{ {
public DhGenerationChunkHolder(ChunkPos pos) { super(pos); } public DhGenerationChunkHolder(ChunkPos pos)
{
super(pos);
}
@Override @Override
public int getTicketLevel() { return 0; } public int getTicketLevel() { return 0; }
@Override @Override
public int getQueueLevel() { return 0; } public int getQueueLevel() { return 0; }
#if MC_VER < MC_1_21_3
#else
@Override
protected void addSaveDependency(CompletableFuture<?> completableFuture) { }
#endif
} }
#endif #endif
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -68,13 +68,6 @@ import com.google.common.collect.ImmutableList;
import net.minecraft.server.level.GenerationChunkHolder; import net.minecraft.server.level.GenerationChunkHolder;
#endif #endif
#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.ticks.BlackholeTickAccess;
import net.minecraft.world.ticks.LevelTickAccess;
#endif
public class DhLitWorldGenRegion extends WorldGenRegion public class DhLitWorldGenRegion extends WorldGenRegion
{ {
@@ -83,9 +76,8 @@ public class DhLitWorldGenRegion extends WorldGenRegion
private static ChunkStatus debugTriggeredForStatus = null; private static ChunkStatus debugTriggeredForStatus = null;
public final ServerLevel serverLevel;
public final DummyLightEngine lightEngine; public final DummyLightEngine lightEngine;
public final BatchGenerationEnvironment.IEmptyChunkRetrievalFunc generator; public final BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator;
public final int writeRadius; public final int writeRadius;
public final int size; public final int size;
@@ -130,7 +122,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
ChunkAccess centerChunk, ChunkAccess centerChunk,
ServerLevel serverLevel, DummyLightEngine lightEngine, ServerLevel serverLevel, DummyLightEngine lightEngine,
List<ChunkAccess> chunkList, ChunkStatus chunkStatus, int writeRadius, List<ChunkAccess> chunkList, ChunkStatus chunkStatus, int writeRadius,
BatchGenerationEnvironment.IEmptyChunkRetrievalFunc generator) BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator)
{ {
#if MC_VER == MC_1_16_5 #if MC_VER == MC_1_16_5
super(serverLevel, chunkList); super(serverLevel, chunkList);
@@ -147,10 +139,9 @@ public class DhLitWorldGenRegion extends WorldGenRegion
new ChunkDependencies(ImmutableList.copyOf(ChunkStatus.getStatusList()).reverse()), new ChunkDependencies(ImmutableList.copyOf(ChunkStatus.getStatusList()).reverse()),
writeRadius, (WorldGenContext var1, ChunkStep var2, StaticCache2D<GenerationChunkHolder> var3, ChunkAccess var4) -> null), writeRadius, (WorldGenContext var1, ChunkStep var2, StaticCache2D<GenerationChunkHolder> var3, ChunkAccess var4) -> null),
centerChunk); centerChunk);
#endif
#endif
this.firstPos = chunkList.get(0).getPos(); this.firstPos = chunkList.get(0).getPos();
this.serverLevel = serverLevel;
this.generator = generator; this.generator = generator;
this.lightEngine = lightEngine; this.lightEngine = lightEngine;
this.writeRadius = writeRadius; this.writeRadius = writeRadius;
@@ -179,18 +170,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
if (center.isUpgrading()) if (center.isUpgrading())
{ {
LevelHeightAccessor levelHeightAccessor = center.getHeightAccessorForGeneration(); LevelHeightAccessor levelHeightAccessor = center.getHeightAccessorForGeneration();
if (blockPos.getY() < levelHeightAccessor.getMinBuildHeight() || blockPos.getY() >= levelHeightAccessor.getMaxBuildHeight())
int minY;
int maxY;
#if MC_VER < MC_1_21_3
minY = levelHeightAccessor.getMinBuildHeight();
maxY = levelHeightAccessor.getMaxBuildHeight();
#else
minY = levelHeightAccessor.getMinY();
maxY = levelHeightAccessor.getMaxY();
#endif
if (blockPos.getY() < minY || blockPos.getY() >= maxY)
{ {
return false; return false;
} }
@@ -200,22 +180,6 @@ public class DhLitWorldGenRegion extends WorldGenRegion
} }
#endif #endif
#if MC_VER >= MC_1_18_2
@Override
@NotNull
public LevelTickAccess<Block> getBlockTicks()
{
// DH world gen doesn't need ticking, so return the BlackholeTickAccess list (which causes all ticks to be ignored).
// If this isn't done the server may attempt to tick chunks outside the vanilla render distance,
// which can throw warnings or cause other issues
return BlackholeTickAccess.emptyLevelList();
}
@Override
@NotNull
public LevelTickAccess<Fluid> getFluidTicks() { return BlackholeTickAccess.emptyLevelList(); }
#endif
// TODO Check this // TODO Check this
// @Override // @Override
// public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos, // public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
@@ -229,16 +193,8 @@ public class DhLitWorldGenRegion extends WorldGenRegion
{ {
ChunkAccess chunkAccess = this.getChunk(blockPos); ChunkAccess chunkAccess = this.getChunk(blockPos);
if (chunkAccess instanceof LevelChunk) if (chunkAccess instanceof LevelChunk)
{
return true; return true;
} chunkAccess.setBlockState(blockPos, blockState, false);
#if MC_VER < MC_1_21_5
chunkAccess.setBlockState(blockPos, blockState, /*isBlockMoving*/false);
#else
chunkAccess.setBlockState(blockPos, blockState, /*flags*/0);
#endif
// This is for post ticking for water on gen and stuff like that. Not enabled // This is for post ticking for water on gen and stuff like that. Not enabled
// for now. // for now.
// if (blockState.hasPostProcess(this, blockPos)) // if (blockState.hasPostProcess(this, blockPos))
@@ -383,7 +339,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
if (chunk == null) if (chunk == null)
{ {
// chunk isn't in memory, generate a new one // chunk isn't in memory, generate a new one
chunk = this.generator.getChunk(chunkX, chunkZ); chunk = this.generator.generate(chunkX, chunkZ);
if (chunk == null) if (chunk == null)
{ {
throw new NullPointerException("The provided generator should not return null!"); throw new NullPointerException("The provided generator should not return null!");
@@ -434,10 +390,14 @@ public class DhLitWorldGenRegion extends WorldGenRegion
/** Overriding allows us to use our own lighting engine */ /** Overriding allows us to use our own lighting engine */
@Override @Override
public boolean canSeeSky(@NotNull BlockPos blockPos) public boolean canSeeSky(@NotNull BlockPos blockPos)
{ return (this.getBrightness(LightLayer.SKY, blockPos) >= LodUtil.MAX_MC_LIGHT); } {
return (this.getBrightness(LightLayer.SKY, blockPos) >= this.getMaxLightLevel());
}
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver) public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
{ return this.calculateBlockTint(blockPos, colorResolver); } {
return this.calculateBlockTint(blockPos, colorResolver);
}
private Biome _getBiome(BlockPos pos) private Biome _getBiome(BlockPos pos)
{ {
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -22,11 +22,11 @@ import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
#endif #endif
/** /**
* Shouldn't be used when the C2ME mod is present, * @deprecated should be replaced with net.minecraft.world.level.chunk.storage.IOWorker to
* otherwise there may be potential file corruption. * prevent potential file corruption and issues with the C2ME mod.
* When C2ME is present use (via MC ServerLevel) level.getChunkSource().chunkMap.worker#loadAsync() * Generally this would be done via (MC ServerLevel) level.getChunkSource().chunkMap.worker#loadAsync()
* instead.
*/ */
@Deprecated
public class RegionFileStorageExternalCache implements AutoCloseable public class RegionFileStorageExternalCache implements AutoCloseable
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final Logger LOGGER = DhLoggerBuilder.getLogger();
@@ -46,11 +46,22 @@ public class RegionFileStorageExternalCache implements AutoCloseable
static class RegionFileCache
{
public final long pos;
public final RegionFile file;
public RegionFileCache(long pos, RegionFile file)
{
this.pos = pos;
this.file = file;
}
}
private final ConcurrentLinkedQueue<RegionFileCache> regionFileCache = new ConcurrentLinkedQueue<>();
public ConcurrentLinkedQueue<RegionFileCache> regionFileCache = new ConcurrentLinkedQueue<>();
public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; } public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; }
@@ -139,7 +150,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
if (retryCount >= maxRetryCount) if (retryCount >= maxRetryCount)
{ {
BatchGenerationEnvironment.LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + pos + "]."); BatchGenerationEnvironment.LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at " + pos + ".");
} }
@@ -226,22 +237,4 @@ public class RegionFileStorageExternalCache implements AutoCloseable
} }
//================//
// helper classes //
//================//
private static class RegionFileCache
{
public final long pos;
public final RegionFile file;
public RegionFileCache(long pos, RegionFile file)
{
this.pos = pos;
this.file = file;
}
}
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -68,50 +68,33 @@ public final class StepBiomes
} }
else if (chunk instanceof ProtoChunk) else if (chunk instanceof ProtoChunk)
{ {
chunkWrapper.trySetStatus(STATUS); #if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk); chunksToDo.add(chunk);
} }
} }
for (ChunkAccess chunk : chunksToDo) for (ChunkAccess chunk : chunksToDo)
{ {
// System.out.println("StepBiomes: "+chunk.getPos());
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk); this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk);
#elif MC_VER < MC_1_19_2 #elif MC_VER < MC_1_19_2
chunk = this.environment.confirmFutureWasRunSynchronously( chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
this.environment.params.generator.createBiomes( tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
this.environment.params.biomes,
Runnable::run,
Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk)
);
#elif MC_VER < MC_1_19_4 #elif MC_VER < MC_1_19_4
chunk = this.environment.confirmFutureWasRunSynchronously( chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
this.environment.params.generator.createBiomes( tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
this.environment.params.biomes,
Runnable::run,
this.environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk)
);
#elif MC_VER < MC_1_21_1 #elif MC_VER < MC_1_21_1
chunk = this.environment.confirmFutureWasRunSynchronously( chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
this.environment.params.generator.createBiomes( tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
Runnable::run,
this.environment.params.randomState,
Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk)
);
#else #else
chunk = this.environment.confirmFutureWasRunSynchronously( chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.randomState, Blender.of(worldGenRegion),
this.environment.params.generator.createBiomes( tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
this.environment.params.randomState,
Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk)
);
#endif #endif
} }
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -66,7 +66,11 @@ public final class StepFeatures
} }
else if (chunk instanceof ProtoChunk) else if (chunk instanceof ProtoChunk)
{ {
chunkWrapper.trySetStatus(STATUS); #if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
} }
@@ -87,6 +91,7 @@ public final class StepFeatures
#endif #endif
Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter()); Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter());
BatchGenerationEnvironment.clearDistantGenerationMixinData();
} }
catch (Exception e) catch (Exception e)
{ {
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -67,42 +67,32 @@ public final class StepNoise
{ {
continue; continue;
} }
chunkWrapper.trySetStatus(STATUS);
#if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk); chunksToDo.add(chunk);
} }
for (ChunkAccess chunk : chunksToDo) for (ChunkAccess chunk : chunksToDo)
{ {
// System.out.println("StepNoise: "+chunk.getPos());
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk); this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
#elif MC_VER < MC_1_18_2 #elif MC_VER < MC_1_18_2
chunk = this.environment.confirmFutureWasRunSynchronously( chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run,
this.environment.params.generator.fillFromNoise( tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
Runnable::run,
tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk));
#elif MC_VER < MC_1_19_2 #elif MC_VER < MC_1_19_2
chunk = this.environment.confirmFutureWasRunSynchronously( chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
this.environment.params.generator.fillFromNoise( tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
Runnable::run,
Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk));
#elif MC_VER < MC_1_21_1 #elif MC_VER < MC_1_21_1
chunk = this.environment.confirmFutureWasRunSynchronously( chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), this.environment.params.randomState,
this.environment.params.generator.fillFromNoise( tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
Runnable::run,
Blender.of(worldGenRegion),
this.environment.params.randomState,
tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk));
#else #else
chunk = this.environment.confirmFutureWasRunSynchronously( chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Blender.of(worldGenRegion), this.environment.params.randomState,
this.environment.params.generator.fillFromNoise( tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
Blender.of(worldGenRegion),
this.environment.params.randomState,
tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk));
#endif #endif
UncheckedInterruptedException.throwIfInterrupted(); UncheckedInterruptedException.throwIfInterrupted();
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -66,7 +66,12 @@ public final class StepStructureReference
} }
else if (chunk instanceof ProtoChunk) else if (chunk instanceof ProtoChunk)
{ {
chunkWrapper.trySetStatus(STATUS); #if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk);
} }
} }
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -28,9 +28,7 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGeneratio
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.WorldGenRegion; import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -85,7 +83,12 @@ public final class StepStructureStart
} }
else if (chunk instanceof ProtoChunk) else if (chunk instanceof ProtoChunk)
{ {
chunkWrapper.trySetStatus(STATUS); #if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk);
} }
} }
@@ -93,8 +96,7 @@ public final class StepStructureStart
if (this.environment.params.worldGenSettings.generateFeatures()) if (this.environment.params.worldGenSettings.generateFeatures())
{ {
#elif MC_VER < MC_1_19_4 #elif MC_VER < MC_1_19_4
if (this.environment.params.worldGenSettings.generateStructures()) if (this.environment.params.worldGenSettings.generateStructures()) {
{
#else #else
if (this.environment.params.worldOptions.generateStructures()) if (this.environment.params.worldOptions.generateStructures())
{ {
@@ -112,20 +114,15 @@ public final class StepStructureStart
STRUCTURE_PLACEMENT_LOCK.lock(); STRUCTURE_PLACEMENT_LOCK.lock();
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
this.environment.params.generator.createStructures(this.environment.params.registry, tParams.structFeat, chunk, this.environment.params.structures, environment.params.generator.createStructures(environment.params.registry, tParams.structFeat, chunk, environment.params.structures,
this.environment.params.worldSeed); environment.params.worldSeed);
#elif MC_VER < MC_1_19_4 #elif MC_VER < MC_1_19_4
this.environment.params.generator.createStructures(this.environment.params.registry, this.environment.params.randomState, tParams.structFeat, chunk, this.environment.params.structures, environment.params.generator.createStructures(environment.params.registry, environment.params.randomState, tParams.structFeat, chunk, environment.params.structures,
this.environment.params.worldSeed); environment.params.worldSeed);
#elif MC_VER <= MC_1_21_3
this.environment.params.generator.createStructures(this.environment.params.registry,
this.environment.params.level.getChunkSource().getGeneratorState(),
tParams.structFeat, chunk, this.environment.params.structures);
#else #else
this.environment.params.generator.createStructures(this.environment.params.registry, environment.params.generator.createStructures(environment.params.registry,
this.environment.params.level.getChunkSource().getGeneratorState(), environment.params.level.getChunkSource().getGeneratorState(),
tParams.structFeat, chunk, this.environment.params.structures, tParams.structFeat, chunk, environment.params.structures);
this.environment.params.level.dimension());
#endif #endif
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -65,7 +65,12 @@ public final class StepSurface
} }
else if (chunk instanceof ProtoChunk) else if (chunk instanceof ProtoChunk)
{ {
chunkWrapper.trySetStatus(STATUS); #if MC_VER < MC_1_21_1
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk); chunksToDo.add(chunk);
} }
} }
@@ -2,8 +2,6 @@ accessWidener v1 named
# used when determining where to save files to # used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File; accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering # used when rendering
accessible field com/mojang/blaze3d/vertex/VertexBuffer vertexCount I accessible field com/mojang/blaze3d/vertex/VertexBuffer vertexCount I
@@ -33,9 +31,6 @@ accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecr
#accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder; #accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
#accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V #accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
# lod generation from save file # lod generation from save file
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop; accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
@@ -1,9 +1,8 @@
accessWidener v1 named accessWidener v1 named
# used when determining where to save files to # used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File; accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering # used when rendering
accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I
@@ -32,11 +31,6 @@ accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecr
# accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder; # accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
#accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V #accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file # lod generation from save file
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop; accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
@@ -2,8 +2,6 @@ accessWidener v1 named
# used when determining where to save files to # used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File; accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering # used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
@@ -17,11 +15,6 @@ accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chu
# world generation # world generation
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file # lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker; accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
@@ -2,8 +2,6 @@ accessWidener v1 named
# used when determining where to save files to # used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File; accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering # used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
@@ -17,11 +15,6 @@ accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chu
# world generation # world generation
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file # lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker; accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
@@ -2,8 +2,6 @@ accessWidener v1 named
# used when determining where to save files to # used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File; accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering # used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
@@ -17,11 +15,6 @@ accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chu
# world generation # world generation
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file # lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker; accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
@@ -2,8 +2,6 @@ accessWidener v1 named
# used when determining where to save files to # used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File; accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used to help determine what folder a clientLevel iss
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering # used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
@@ -19,11 +17,6 @@ accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chu
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage; accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file # lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker; accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
@@ -2,8 +2,6 @@ accessWidener v1 named
# used when determining where to save files to # used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File; accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering # used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
@@ -18,11 +16,6 @@ accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage; accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file # lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker; accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
@@ -2,8 +2,6 @@ accessWidener v1 named
# used when determining where to save files to # used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File; accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering # used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
@@ -18,11 +16,6 @@ accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage; accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file # lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker; accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
@@ -1,53 +0,0 @@
accessWidener v1 named
# used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/nio/file/Path;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)F
accessible field net/minecraft/client/Minecraft deltaTracker Lnet/minecraft/client/DeltaTracker$Timer;
# used for grabbing vanilla rendered chunks
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
# world generation
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage regionCache Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage folder Ljava/nio/file/Path;
# grabbing textures
accessible class net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameX (I)I
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameY (I)I
accessible field net/minecraft/client/renderer/texture/SpriteContents animatedTexture Lnet/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture;
accessible field net/minecraft/client/renderer/texture/SpriteContents originalImage Lcom/mojang/blaze3d/platform/NativeImage;
# UI stuff
accessible field net/minecraft/client/gui/components/AbstractButton SPRITES Lnet/minecraft/client/gui/components/WidgetSprites;
# Handles inserting the config button
accessible field net/minecraft/client/gui/layouts/HeaderAndFooterLayout headerFrame Lnet/minecraft/client/gui/layouts/FrameLayout;
accessible field net/minecraft/client/gui/layouts/FrameLayout children Ljava/util/List;
accessible class net/minecraft/client/gui/layouts/FrameLayout$ChildContainer
accessible field net/minecraft/client/gui/layouts/LinearLayout wrapped Lnet/minecraft/client/gui/layouts/GridLayout;
# hacky stuff
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
accessible field net/minecraft/client/gui/components/AbstractSelectionList scrollAmount D # Hack to bypass vanilla's setScrollAmount's clamp
@@ -1,52 +0,0 @@
accessWidener v1 named
# used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/nio/file/Path;
# used to help determine what folder a clientLevel is
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
# used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)F
accessible field net/minecraft/client/Minecraft deltaTracker Lnet/minecraft/client/DeltaTracker$Timer;
# used for grabbing vanilla rendered chunks
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
# world generation
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage regionCache Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage folder Ljava/nio/file/Path;
# grabbing textures
accessible class net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameX (I)I
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameY (I)I
accessible field net/minecraft/client/renderer/texture/SpriteContents animatedTexture Lnet/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture;
accessible field net/minecraft/client/renderer/texture/SpriteContents originalImage Lcom/mojang/blaze3d/platform/NativeImage;
# UI stuff
accessible field net/minecraft/client/gui/components/AbstractButton SPRITES Lnet/minecraft/client/gui/components/WidgetSprites;
# Handles inserting the config button
accessible field net/minecraft/client/gui/layouts/HeaderAndFooterLayout headerFrame Lnet/minecraft/client/gui/layouts/FrameLayout;
accessible field net/minecraft/client/gui/layouts/FrameLayout children Ljava/util/List;
accessible class net/minecraft/client/gui/layouts/FrameLayout$ChildContainer
accessible field net/minecraft/client/gui/layouts/LinearLayout wrapped Lnet/minecraft/client/gui/layouts/GridLayout;
# hacky stuff
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
+6 -11
View File
@@ -1,26 +1,21 @@
plugins { plugins {
id "fabric-loom" version "1.10-SNAPSHOT" id "fabric-loom" version "1.6-SNAPSHOT"
} }
loom { loom {
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener") accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
// Custom logging
log4jConfigs.from(file("log4j-dev.xml"))
// "runs" isn't required, but when we do need it then it can be useful // "runs" isn't required, but when we do need it then it can be useful
runs { runs {
client { client {
client() client()
setConfigName("Fabric Client") setConfigName("Fabric Client")
ideConfigGenerated(true) // When true a run configuration file will be generated for IDE's. By default only set to true for the root project. ideConfigGenerated(true)
runDir("../run/client") runDir("../run/client")
vmArgs( vmArgs("-Dio.netty.leakDetection.level=advanced")
// https://github.com/FabricMC/fabric-loom/issues/915#issuecomment-1609154390
"-Dminecraft.api.auth.host=https://nope.invalid",
"-Dminecraft.api.account.host=https://nope.invalid",
"-Dminecraft.api.session.host=https://nope.invalid",
"-Dminecraft.api.services.host=https://nope.invalid",
// https://netty.io/wiki/reference-counted-objects.html#leak-detection-levels
"-Dio.netty.leakDetection.level=advanced"
)
programArgs("--username", "Dev") programArgs("--username", "Dev")
} }
server { server {
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="Dev" monitorInterval="10">
<Loggers>
<Logger name="com.seibel.distanthorizons.core.network" level="trace" additivity="false">
<AppenderRef ref="DebugFile" level="${sys:fabric.log.debug.level:-debug}" />
<AppenderRef ref="SysOut" />
<AppenderRef ref="LatestFile" level="${sys:fabric.log.level:-info}" />
<AppenderRef ref="ServerGuiConsole" />
</Logger>
</Loggers>
</Configuration>
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -33,7 +33,6 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.util.math.Mat4f; import com.seibel.distanthorizons.core.util.math.Mat4f;
@@ -53,14 +52,13 @@ import net.minecraft.client.gui.screens.TitleScreen;
import com.seibel.distanthorizons.common.CommonPacketPayload; import com.seibel.distanthorizons.common.CommonPacketPayload;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
#else #else
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
#endif #endif
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
#endif #endif
import java.util.HashSet; import java.util.HashSet;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
@@ -83,7 +81,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
{ {
private final ClientApi clientApi = ClientApi.INSTANCE; private final ClientApi clientApi = ClientApi.INSTANCE;
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final Logger LOGGER = DhLoggerBuilder.getLogger();
// TODO we shouldn't be filtering keys on the Forge/Fabric side, only in ClientApi // TODO we shouldn't be filtering keys on the Forge/Fabric side, only in ClientApi
@@ -129,7 +126,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
if (MC.clientConnectedToDedicatedServer()) if (MC.clientConnectedToDedicatedServer())
{ {
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel); SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
} }
}); });
@@ -145,7 +142,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
// executor to prevent locking up the render/event thread // executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected // if the getChunk() takes longer than expected
// (which can be caused by certain mods) // (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor(); ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null) if (executor != null)
{ {
executor.execute(() -> executor.execute(() ->
@@ -157,7 +154,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level); IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
SharedApi.INSTANCE.chunkBlockChangedEvent( SharedApi.INSTANCE.chunkBlockChangedEvent(
new ChunkWrapper(chunk, wrappedLevel), new ChunkWrapper(chunk, level, wrappedLevel),
wrappedLevel wrappedLevel
); );
} }
@@ -185,7 +182,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
// executor to prevent locking up the render/event thread // executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected // if the getChunk() takes longer than expected
// (which can be caused by certain mods) // (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor(); ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null) if (executor != null)
{ {
executor.execute(() -> executor.execute(() ->
@@ -197,7 +194,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level); IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
SharedApi.INSTANCE.chunkBlockChangedEvent( SharedApi.INSTANCE.chunkBlockChangedEvent(
new ChunkWrapper(chunk, wrappedLevel), new ChunkWrapper(chunk, level, wrappedLevel),
wrappedLevel wrappedLevel
); );
} }
@@ -228,14 +225,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix()); modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix());
#endif #endif
//LOGGER.info("\n\n" +
// "Level Render\n" +
// "Mc MVM: \n" + modelViewMatrix.toString() + "\n" +
// "Mc Proj: \n" + projectionMatrix.toString()
//);
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()), this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
modelViewMatrix, modelViewMatrix,
projectionMatrix, projectionMatrix,
@@ -247,67 +236,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
); );
}); });
// TODO add to forge and neo
WorldRenderEvents.AFTER_ENTITIES.register((renderContext) ->
{
Mat4f projectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
Mat4f modelViewMatrix;
#if MC_VER < MC_1_20_6
modelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose());
#else
modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix());
#endif
this.clientApi.renderFadeOpaque(
modelViewMatrix,
projectionMatrix,
#if MC_VER < MC_1_21_1
renderContext.tickDelta(),
#else
renderContext.tickCounter().getGameTimeDeltaTicks(),
#endif
ClientLevelWrapper.getWrapper(renderContext.world())
);
});
// TODO add to forge and neo
WorldRenderEvents.AFTER_TRANSLUCENT.register((renderContext) ->
{
Mat4f projectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
Mat4f modelViewMatrix;
#if MC_VER < MC_1_20_6
modelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose());
#else
modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix());
#endif
#if MC_VER < MC_1_21_6
// rendered in MixinLevelRenderer
#else
ClientApi.INSTANCE.renderDeferredLodsForShaders(ClientLevelWrapper.getWrapper(renderContext.world()),
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime
);
#endif
this.clientApi.renderFade(
modelViewMatrix,
projectionMatrix,
#if MC_VER < MC_1_21_1
renderContext.tickDelta(),
#else
renderContext.tickCounter().getGameTimeDeltaTicks(),
#endif
ClientLevelWrapper.getWrapper(renderContext.world())
);
});
// Debug keyboard event // Debug keyboard event
// FIXME: Use better hooks so it doesn't trigger key press events in text boxes // FIXME: Use better hooks so it doesn't trigger key press events in text boxes
ClientTickEvents.END_CLIENT_TICK.register(client -> ClientTickEvents.END_CLIENT_TICK.register(client ->
@@ -325,6 +253,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
//==================// //==================//
#if MC_VER >= MC_1_20_6 #if MC_VER >= MC_1_20_6
PayloadTypeRegistry.playC2S().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec());
PayloadTypeRegistry.playS2C().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec()); PayloadTypeRegistry.playS2C().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec());
ClientPlayNetworking.registerGlobalReceiver(CommonPacketPayload.TYPE, (payload, context) -> ClientPlayNetworking.registerGlobalReceiver(CommonPacketPayload.TYPE, (payload, context) ->
{ {
@@ -337,7 +266,9 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
#else #else
ClientPlayNetworking.registerGlobalReceiver(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, (client, handler, buffer, packetSender) -> ClientPlayNetworking.registerGlobalReceiver(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, (client, handler, buffer, packetSender) ->
{ {
AbstractNetworkMessage message = PACKET_SENDER.decodeMessage(buffer); // Forge packet ID
buffer.readByte();
NetworkMessage message = AbstractPluginPacketSender.decodeMessage(buffer);
if (message != null) if (message != null)
{ {
ClientApi.INSTANCE.pluginMessageReceived(message); ClientApi.INSTANCE.pluginMessageReceived(message);
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizons mod * This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License. * licensed under the GNU LGPL v3 License.
* *
* Copyright (C) 2020 James Seibel * Copyright (C) 2020-2023 James Seibel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@@ -20,7 +20,6 @@
package com.seibel.distanthorizons.fabric; package com.seibel.distanthorizons.fabric;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.api.enums.config.EDhApiMcRenderingFadeMode;
import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase; import com.seibel.distanthorizons.core.config.ConfigBase;
@@ -41,7 +40,6 @@ import net.minecraft.commands.CommandSourceStack;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.lwjgl.util.tinyfd.TinyFileDialogs;
#if MC_VER >= MC_1_19_2 #if MC_VER >= MC_1_19_2
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
@@ -91,13 +89,16 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
{ {
ModAccessorInjector.INSTANCE.bind(ISodiumAccessor.class, new SodiumAccessor()); ModAccessorInjector.INSTANCE.bind(ISodiumAccessor.class, new SodiumAccessor());
// If sodium is installed Indium is also necessary for versions 0.5 and less in order to use the Fabric rendering API // If sodium is installed Indium is also necessary in order to use the Fabric rendering API
if (!modChecker.isModLoaded("indium") && SodiumAccessor.isSodiumV5OrLess) if (!modChecker.isModLoaded("indium"))
{ {
String indiumMissingMessage = ModInfo.READABLE_NAME + " needs Indium to work with Sodium.\nPlease download Indium from https://modrinth.com/mod/indium"; String indiumMissingMessage = ModInfo.READABLE_NAME + " needs Indium to work with Sodium.\nPlease download Indium from https://modrinth.com/mod/indium";
LOGGER.fatal(indiumMissingMessage); LOGGER.fatal(indiumMissingMessage);
TinyFileDialogs.tinyfd_messageBox(ModInfo.READABLE_NAME, indiumMissingMessage, "ok", "error", false); if (!GraphicsEnvironment.isHeadless())
{
JOptionPane.showMessageDialog(null, indiumMissingMessage, ModInfo.READABLE_NAME, JOptionPane.INFORMATION_MESSAGE);
}
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
String errorMessage = "loading Distant Horizons. Distant Horizons requires Indium in order to run with Sodium."; String errorMessage = "loading Distant Horizons. Distant Horizons requires Indium in order to run with Sodium.";
@@ -118,17 +119,13 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
@Override @Override
protected void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler) protected void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler)
{ {
CommandRegistrationCallback.EVENT.register( CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess #if MC_VER >= MC_1_19_2 , environment #endif ) -> {
(dispatcher, registryAccess #if MC_VER >= MC_1_19_2 , environment #endif ) -> eventHandler.accept(dispatcher);
{ });
eventHandler.accept(dispatcher);
}
);
} }
@Override @Override
protected void subscribeClientStartedEvent(Runnable eventHandler) protected void subscribeClientStartedEvent(Runnable eventHandler) { ClientLifecycleEvents.CLIENT_STARTED.register((mc) -> eventHandler.run()); }
{ ClientLifecycleEvents.CLIENT_STARTED.register((mc) -> eventHandler.run()); }
@Override @Override
protected void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler) protected void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler)
@@ -142,7 +139,7 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
{ {
SingletonInjector.INSTANCE.runDelayedSetup(); SingletonInjector.INSTANCE.runDelayedSetup();
if (!Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get() && SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib")) if (Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get() && SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib"))
{ {
ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).setRenderCustomFog(false); // Remove BCLib's fog ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).setRenderCustomFog(false); // Remove BCLib's fog
} }
@@ -1,7 +1,7 @@
package com.seibel.distanthorizons.fabric; package com.seibel.distanthorizons.fabric;
import com.seibel.distanthorizons.common.AbstractPluginPacketSender; import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
@@ -16,25 +16,29 @@ import net.minecraft.network.FriendlyByteBuf;
public class FabricPluginPacketSender extends AbstractPluginPacketSender public class FabricPluginPacketSender extends AbstractPluginPacketSender
{ {
@Override @Override
public void sendToServer(AbstractNetworkMessage message) public void sendPluginPacketClient(NetworkMessage message)
{ {
#if MC_VER >= MC_1_20_6 #if MC_VER >= MC_1_20_6
ClientPlayNetworking.send(new CommonPacketPayload(message)); ClientPlayNetworking.send(new CommonPacketPayload(message));
#else // < 1.20.6 #else // < 1.20.6
FriendlyByteBuf buffer = PacketByteBufs.create(); FriendlyByteBuf buffer = PacketByteBufs.create();
this.encodeMessage(buffer, message); // Forge packet ID
buffer.writeByte(0);
AbstractPluginPacketSender.encodeMessage(buffer, message);
ClientPlayNetworking.send(WRAPPER_PACKET_RESOURCE, buffer); ClientPlayNetworking.send(WRAPPER_PACKET_RESOURCE, buffer);
#endif #endif
} }
@Override @Override
public void sendToClient(ServerPlayer serverPlayer, AbstractNetworkMessage message) public void sendPluginPacketServer(ServerPlayer serverPlayer, NetworkMessage message)
{ {
#if MC_VER >= MC_1_20_6 #if MC_VER >= MC_1_20_6
ServerPlayNetworking.send(serverPlayer, new CommonPacketPayload(message)); ServerPlayNetworking.send(serverPlayer, new CommonPacketPayload(message));
#else // < 1.20.6 #else // < 1.20.6
FriendlyByteBuf buffer = PacketByteBufs.create(); FriendlyByteBuf buffer = PacketByteBufs.create();
this.encodeMessage(buffer, message); // Forge packet ID
buffer.writeByte(0);
AbstractPluginPacketSender.encodeMessage(buffer, message);
ServerPlayNetworking.send(serverPlayer, WRAPPER_PACKET_RESOURCE, buffer); ServerPlayNetworking.send(serverPlayer, WRAPPER_PACKET_RESOURCE, buffer);
#endif #endif
} }

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