Compare commits

..

475 Commits

Author SHA1 Message Date
Ran 3f37f7f02a Update Readme.md 2022-04-17 17:00:53 +00:00
TomTheFurry a88feda9ec Fix it so it build 2022-04-04 15:47:49 +08:00
TomTheFurry 07b7ecb30a Maybe fixed the light again? 2022-04-04 12:01:01 +08:00
TomTheFurry 32bbe487c0 Fix dumb stuff costing performance on world gen 2022-04-03 16:02:06 +08:00
TomTheFurry b367e5c3aa Fix dumb stuff costing performance on world gen 2022-04-03 16:01:54 +08:00
TomTheFurry a43b2b69a6 Fix up big blocks missing side faces 2022-04-03 13:06:18 +08:00
James Seibel 2a1de6f579 add missing fabric libraries for sodium 2022-04-02 23:46:31 -05:00
James Seibel 7dadff4219 automatically copy lod.accesswidener when building
By default the fabric build folder needs this file to run, but it wasn't being copied over, now it should be.
2022-04-02 23:08:33 -05:00
James Seibel 07c53a02ca Add phosphor as an option to build.gradle 2022-04-02 23:06:57 -05:00
TomTheFurry 1e54885d88 Disabled framebuffer fix for now making optifine shaders to work again 2022-04-02 22:24:17 +08:00
TomTheFurry 68f4084ab0 Fix coolGi's java-8 port 2022-04-02 22:18:40 +08:00
TomTheFurry 6fa968e016 Make lightmap fix works with Optifine shaders? 2022-04-02 21:11:38 +08:00
TomTheFurry 93c2078724 Make lightmap fix works with Optifine shaders? 2022-04-02 21:09:39 +08:00
TomTheFurry 2289d898ce Update core. 2022-04-02 15:25:28 +08:00
TomTheFurry 15e5a04ffd Maybe fixed colormatic's mod compat? 2022-04-02 13:49:28 +08:00
TomTheFurry 150ba98a4e MacOS Patch Successful! + fix missing fabric api 2022-04-01 19:46:54 +08:00
coolGi2007 d9484c9df4 Why dose the readme still say preprocessor_test 2022-04-01 08:26:59 +00:00
James Seibel a92e09c2be Merge branch '1.18.X' of gitlab.com:jeseibel/minecraft-lod-mod into 1.18.X 2022-03-31 21:23:41 -05:00
James Seibel f7e1dc378f Fix the default folder selection if sub-dimensions are disabled 2022-03-31 21:23:38 -05:00
Ran f7b84b1909 It was nice knowing you fabric-api 2022-03-31 14:49:53 +06:00
Ran abae2f6358 I forgor 2022-03-31 14:35:03 +06:00
Ran e83939f1b2 Remove fabric api as a dependency 2022-03-31 14:30:41 +06:00
James Seibel 0bddc2dcac Fix invalid files that use the server port 2022-03-30 21:18:59 -05:00
James Seibel 42a8e0e0f0 Add additional logging to getFileBasePath 2022-03-30 19:57:59 -05:00
TomTheFurry 7b77e07a7d Fix race & stuck playerData in sub-dim, add dataPoint verify 2022-03-30 18:39:10 +08:00
cola98765 db17d27823 change XZ setting 3 -> 1 made it easier to change it with static at the start of the file 2022-03-30 11:55:02 +02:00
James Seibel 362b800f25 Close #140 (no rendering if world named "No World Loaded" ) 2022-03-29 20:49:11 -05:00
TomTheFurry 29e26d659d I think test renderer is now more correct? 2022-03-29 13:09:29 +08:00
TomTheFurry afa658cc00 Add RendererType & Debug Renderer + fix Logger bug 2022-03-28 17:04:06 +08:00
James Seibel cde0d466dd Fix a null pointer error when moving empty folders 2022-03-27 21:49:26 -05:00
James Seibel 4031b55630 Fix old folders not moving if sub-dims are disabled 2022-03-27 00:09:41 -05:00
James Seibel 86e07156d1 Make multi-Dim similarity = 0 disable the new system
By default the old system of 1 world per dimension is used
2022-03-26 23:16:12 -05:00
James Seibel 1e8df274ee Update a log in Sub-Dim 2022-03-26 21:34:47 -05:00
James Seibel f0153cc4a6 Fix incorrect files/folders crashing the sub-dim system 2022-03-26 21:27:28 -05:00
James Seibel 3044c238fd Automatically move old files to the new sub-dim system 2022-03-26 20:53:53 -05:00
James Seibel ead58390cd Merge in SubDim changes 2022-03-26 11:39:31 -05:00
TomTheFurry 504d22ff37 Update core 2022-03-26 23:32:50 +08:00
TomTheFurry cc42f8667f Update core 2022-03-26 18:56:39 +08:00
James Seibel 6135b3ce7f Merge branch '1.18.X' of gitlab.com:jeseibel/minecraft-lod-mod into 1.18.X 2022-03-23 21:18:06 -05:00
James Seibel 3c8efa17d5 Add better logging and hopefully fix some issues with multi-dim support 2022-03-23 21:18:03 -05:00
James Seibel dccae0aea0 Re-add the gradle cache to hopefully improve compile speed 2022-03-23 02:06:42 +00:00
James Seibel 2728236ced Merge branch '1.18.X' of gitlab.com:jeseibel/minecraft-lod-mod into 1.18.X 2022-03-22 20:48:46 -05:00
James Seibel 76ce1d6b21 Change the deleteMerged task's folder path 2022-03-22 20:48:37 -05:00
James Seibel 94ddebaec0 Fix some YAML errors 2022-03-23 01:28:43 +00:00
James Seibel cec165176b Go back to sequential compiles, deleting the merged between compiles 2022-03-22 20:13:38 -05:00
James Seibel 99ad837441 comment out one of the artifacts and rename the caches 2022-03-22 19:52:50 -05:00
James Seibel f8be132ba2 Increase compiler memory and flip the compile order 2022-03-22 19:43:49 -05:00
James Seibel 122f5431a6 Try disabling caching and re-enabling the daemon 2022-03-23 00:31:17 +00:00
James Seibel c2884954a4 Disable the gradle daemon to hopefully fix a compiler crash 2022-03-22 12:28:25 +00:00
James Seibel 3a0453c8c5 Dummy commit to trigger a rebuild 2022-03-22 12:22:19 +00:00
TomTheFurry 9d241ab175 Add CaveCullingHeight + 'Fun' mode into config 2022-03-22 18:23:53 +08:00
TomTheFurry ee7eed8d3c Fix 0 size quad bug + improve black face filling 2022-03-22 13:05:22 +08:00
Ran 1125452a8f Fix DHJarMerger 2022-03-22 10:55:30 +06:00
James Seibel a3712c8f72 Last attempt at fixing artifacts incorrectly merging for the night
7707f55b appears to have worked correctly, now if I can just figure out if it was a fluke...
2022-03-22 04:16:35 +00:00
James Seibel e2022fab2d Make compiling sequential to fix a mystery compiler error 2022-03-22 03:36:39 +00:00
James Seibel bcea1be19b Fix the cache key being incorrectly set 2022-03-22 03:20:19 +00:00
James Seibel 8d799203c5 Update .gitlab-ci.yml file 2022-03-22 03:14:55 +00:00
James Seibel 980ce2f2af Go back to parallel builds
And potentially fix the caching
2022-03-22 03:14:25 +00:00
James Seibel c6bea3faa3 Try sequential builds in CI 2022-03-22 03:02:44 +00:00
James Seibel 7707f55b25 Update .gitlab-ci.yml file 2022-03-22 02:39:42 +00:00
James Seibel f087bb7182 Update .gitlab-ci.yml file 2022-03-22 02:38:33 +00:00
James Seibel bf269c9abf Fix an incorrect Array Index 2022-03-21 21:21:22 -05:00
tom lee a8c7405f9d Update core + forgot to undo the always getMaxRenderedChunk() 2022-03-21 17:29:33 +08:00
tom lee 43c9232e7e Update core 2022-03-21 16:56:40 +08:00
tom lee 8351c58d7b Update core + remove Manifold from core + remove awt.Colors 2022-03-21 15:16:37 +08:00
tom lee aa86381b80 Update core 2022-03-20 23:18:23 +08:00
tom lee 563840ca58 Fix some block failing to get correct colors 2022-03-20 17:15:12 +08:00
tom lee b5b9b688c3 Update core 2022-03-20 16:31:04 +08:00
tom lee 3731223087 Update core 2022-03-20 16:27:40 +08:00
tom lee 72d770c0f3 Maybe this will work? 2022-03-20 13:51:49 +08:00
tom lee ee4b83fa99 Fix StructFeatManager to work on 1.18.2 + Update core 2022-03-20 13:42:12 +08:00
James Seibel ee6e3a9876 Merge branch 'preprocessor_test' into 1.18.X 2022-03-19 20:15:18 -05:00
James Seibel 17e375bc61 Return IBlockDetailWrappers 2022-03-19 20:04:11 -05:00
James Seibel a2c8c90a5e Merge branch '1.18.2' into preprocessor_test 2022-03-19 19:56:04 -05:00
James Seibel b376014df8 Update the manifold version 2022-03-19 18:20:28 -05:00
James Seibel b9ee54f6ad add multi-dim and brightness/saturation 2022-03-19 12:39:09 -05:00
James Seibel 6c7e1900a3 Merge in fog changes 2022-03-19 11:20:44 -05:00
tom lee 6f929f40f9 Update core 2022-03-19 22:34:11 +08:00
James Seibel b6a8930855 Add a config for the MultiDimension Similarity 2022-03-18 23:57:32 -05:00
coolGi2007 7a91b258de Updated mods, readme and fixed 1 thing in the config gui 2022-03-17 17:52:19 +10:30
TomTheFurry 35bef76aeb Fix 1.18.2 WorldRenderer renderSky() mixin falling 2022-03-16 19:57:27 +08:00
TomTheFurry 780d0ad9fb Complete the push 2022-03-16 18:53:16 +08:00
TomTheFurry c0d5dd6dee ADVANCED FOGGGGGGGGGGGGGGGG~~~~~~~~~~~~~~~~ 2022-03-16 18:52:56 +08:00
TomTheFurry 3e87e625ba Pushed the stuff leetom did on my macbook 2022-03-15 21:17:07 +10:30
TomTheFurry 56f9403859 Add proper multi FrameBuffer support(And fix MacOS?) 2022-03-15 16:38:39 +08:00
TomTheFurry 8259c79e9c Fixup MixinUtilBackgroudThread+more render log 2022-03-15 18:48:27 +10:30
TomTheFurry be1e2fe7e6 Merge remote-tracking branch 'origin/preprocessor_test' into preprocessor_test 2022-03-15 12:38:10 +08:00
TomTheFurry 609ee5c70d Improve GLMessage Parser 2022-03-15 12:37:51 +08:00
James Seibel 207cab9a0f Clean up the build script 2022-03-15 04:05:12 +00:00
James Seibel c80b025ac1 Clean up the build script 2022-03-15 03:52:25 +00:00
James Seibel 8610917b86 Update .gitlab-ci.yml file 2022-03-15 03:41:17 +00:00
James Seibel fae4bee871 Update .gitlab-ci.yml file 2022-03-15 03:34:52 +00:00
James Seibel b9608498a2 Check if Gradle setup is necessary + fix artifacts not being populated 2022-03-15 03:34:29 +00:00
James Seibel fe59c6b0c9 Check if Gradle setup is necessary 2022-03-15 03:25:09 +00:00
James Seibel b082b048d6 Update .gitlab-ci.yml file 2022-03-15 03:21:59 +00:00
James Seibel 91712cee2a Rough artifact test 2022-03-15 03:21:44 +00:00
James Seibel 5adfbb2dee Update .gitlab-ci.yml 2022-03-15 03:04:50 +00:00
James Seibel ec32d09468 Try separating the archiving into a separate step
This will make adding/removing MC versions to compile easier
2022-03-15 02:51:39 +00:00
James Seibel 919990820e Fix exporting duplicate jars 2022-03-15 02:43:12 +00:00
James Seibel 5cc31efa12 Attempt to add 1.18.1 and 1.18.2 auto building 2022-03-15 02:16:04 +00:00
TomTheFurry 5f48b41693 Add Advanced Fog config entries. Actual impl is a todo. 2022-03-15 00:00:36 +08:00
TomTheFurry 9530eea287 Update core and fix serverRenderDistanceMax not being checked 2022-03-14 16:23:04 +08:00
TomTheFurry ebbf304c94 Updated core 2022-03-14 15:10:20 +08:00
TomTheFurry 7c8ac0c2ff Fix mistakes + update core 2022-03-13 22:57:42 +08:00
TomTheFurry eefad5e052 Improved getMaximumRenderedChunk and fix GLMessage on forge 2022-03-13 22:57:07 +08:00
TomTheFurry 9a1e6e29d4 Update Readme.md on switching versions 2022-03-13 16:45:41 +08:00
TomTheFurry 62ab450d98 Update Core 2022-03-13 16:16:29 +08:00
TomTheFurry b4a5da4a74 Update Config defaults 2022-03-13 16:15:29 +08:00
TomTheFurry ed82480c89 Update .gitmodules properly this time 2022-03-13 07:41:53 +00:00
TomTheFurry 82449c5edc Update and fix core branch tracking(I think?) 2022-03-13 15:40:08 +08:00
TomTheFurry b165726bc9 Add new Config: BiomeBlending 2022-03-13 15:26:24 +08:00
TomTheFurry 11910d0f28 Fix IDE not reconising preprocessor 2022-03-10 17:29:27 +08:00
TomTheFurry f66e27b077 First version where 1.18.1 & 1.18.2 is merged 2022-03-10 17:05:14 +08:00
coolGi2007 f84570a6fc Downgraded stuff from 1.18.2 to 1.18.X 2022-03-10 16:35:20 +10:30
James Seibel 835beb607d Close #207 (re-add brightness/contrast configs) 2022-03-09 23:06:34 -06:00
TomTheFurry c4e2d3fb0f Remove unused stuff 2022-03-09 16:21:44 +08:00
TomTheFurry eb3d8d9da5 Add Manifold Preprocessor plugin to gradle 2022-03-09 16:14:16 +08:00
TomTheFurry 151d548099 Update core + Fix biome blending 2022-03-08 23:27:14 +08:00
TomTheFurry c5cdc2760f Update core 2022-03-08 16:05:30 +08:00
coolGi2007 a663bf9f19 Added the multiplayer folder thing from 1.18.X to 1.18.2 and fixed building 2022-03-08 17:43:10 +10:30
James Seibel a0f5af46a2 Closes #217 (Change Server Folder Name)
Adds multiple options for formatting the server folder name.
If LODs have already been generated with a previous setting the files will have to be transferred to the new folder.
2022-03-07 22:16:00 -06:00
coolGi2007 7ddd48d132 Updated what james did from 1.18.X to 1.18.2 2022-03-07 16:56:35 +10:30
James Seibel 18074f15f5 Rename MinecraftWrapper -> MinecraftClientWrapper
closes #150
2022-03-05 18:28:36 -06:00
James Seibel bba0424c6d remove WorldWrapper.isEmpty()
It wasn't used and there was a comment saying not to use it
2022-03-05 18:14:22 -06:00
James Seibel 282f6cfbb8 Update the DependencyHandler to support circular references
Also rename "DependencySetup" To "FabricDependencySetup"
2022-03-05 17:52:22 -06:00
Ran ce10a43cc6 Fix accesswidener for 1.18.2 2022-03-03 14:34:47 +06:00
tom lee 5476af5bb3 Fixed chunkloader to work with 1.18.2 2022-03-02 19:28:16 +08:00
coolGi2007 b97b1b61b7 Reverted the commit that added 1.18.2 to this branch 2022-03-02 18:08:11 +10:30
coolGi2007 25d2cfd7b8 Quick 1.18.2 branch (**DISABLE GENERATION TO WORK**) 2022-03-02 17:43:46 +10:30
James Seibel 1b754387e0 Refactor the dependency injectors 2022-03-01 21:20:00 -06:00
James Seibel bcad40069f Merge branch '1.18.X' of gitlab.com:jeseibel/minecraft-lod-mod into 1.18.X 2022-02-28 17:57:01 -06:00
James Seibel 5aa9061006 remove the discord notification experiment
Using this changed how the messages look in a way I don't like; removing the committer's icon and commit message.
2022-02-28 17:54:41 -06:00
James Seibel 873e8cec57 Update .gitlab-ci.yml file 2022-02-28 23:37:29 +00:00
James Seibel f6f96c3aea Test pipeline discord notifications 2022-02-28 17:18:02 -06:00
tom lee aeed672295 Update core 2022-02-27 17:02:06 +08:00
tom lee 832fbe6d15 Update core 2022-02-26 16:16:00 +08:00
tom lee 03deddf666 Optimized the McObjectConverter for Direction 2022-02-26 14:04:49 +08:00
tom lee d06413d1b4 Update core 2022-02-25 15:15:51 +08:00
tom lee 8afa50d585 Update core + improved GenEvent Terminate speed 2022-02-24 22:28:59 +08:00
Morippi 9f28f1f812 Added comments 2022-02-23 18:26:35 +01:00
Morippi 985388fd90 Removed border from details circles and regions 2022-02-23 16:38:19 +01:00
tom lee e27e10082a Update core 2022-02-22 23:12:59 +08:00
tom lee 4e510d96fc Update core + fix colors. See commit in core 2022-02-22 23:10:58 +08:00
coolGi2007 c0ec02f062 forgot this like 2022-02-22 07:22:33 +00:00
coolGi2007 bd27a96bde Updated the readme and updated the DHJarMerger (now marks the jar as an executable so linux users have an easier time when runnung the jar) 2022-02-22 17:49:23 +10:30
tom lee d6aeaf8e9d Update Core 2022-02-22 11:37:22 +08:00
Ran 2b9bba4aa7 Update core 2022-02-21 17:36:08 +06:00
Ran 58b0991891 Put logger in ApiShared.java 2022-02-21 17:34:52 +06:00
Ran 59cbbef327 Merge remote-tracking branch 'origin/1.18.X' into 1.18.X 2022-02-21 17:29:41 +06:00
Ran 7047c81a2b Put logger in ApiShared.java 2022-02-21 17:27:54 +06:00
tom lee 6e2ab47359 Rework Block color / shape 2022-02-21 19:23:30 +08:00
Ran f879332e1d Client 2 Server packets 2022-02-21 13:40:42 +06:00
coolGi2007 6fcafecc61 Updated fabric, modmenu and readme 2022-02-21 16:36:10 +10:30
coolGi2007 a5af93aef1 Renamed the thing to JarMain 2022-02-20 22:26:01 +00:00
coolGi2007 4b84fd2a67 Added a way to run jar (dosnt do anything but could be used to check opengl and move mod to mods folder) 2022-02-20 22:16:21 +10:30
cola98765 924efc0cbd update core 2022-02-20 12:34:09 +01:00
tom lee 288457b5bd Update core 2022-02-20 17:35:11 +08:00
James Seibel d29fa86de6 Merge branch 'jeffthejeffthejeff-1.18.X-patch-51031' into '1.18.X'
Added an image and improved start of Readme.md

See merge request jeseibel/minecraft-lod-mod!17
2022-02-20 05:13:39 +00:00
James Seibel 97be227e3d Add a missing "s" 2022-02-20 05:12:16 +00:00
James Seibel 909d6a54c3 Slightly reword the blurb 2022-02-20 05:10:35 +00:00
Ran 228b6a80dc Merge branch '1.18.X' of https://gitlab.com/jeseibel/minecraft-lod-mod into 1.18.X 2022-02-20 09:32:44 +06:00
Ran 6936a5f96f I forgor 💀 2022-02-20 09:31:55 +06:00
cola98765 740560a50a actually fix tint on custom water textures. 2022-02-19 22:32:53 +01:00
cola98765 47c28f0f37 actually fix tint on custom water textures. 2022-02-19 22:28:35 +01:00
Ran 1c859cd7da Oops was registering channels to wrong environments 2022-02-20 00:15:33 +06:00
tom lee e4a97dd76d Update core 2022-02-20 01:01:59 +08:00
Ran 4fd1e5ea06 Update core 2022-02-19 22:58:05 +06:00
Ran 6039aeabde Server client communication! maybe 2022-02-19 22:55:53 +06:00
tom lee 17a384f074 Update core 2022-02-19 22:15:04 +08:00
coolGi2007 25e8f5ec6a Forgot to push this file 2022-02-19 08:30:06 +00:00
coolGi2007 eac8cacd42 Removed new config 2022-02-19 18:53:34 +10:30
James Seibel 75193d76a3 Update the version number to 1.6.2a 2022-02-17 20:11:13 -06:00
James Seibel aa24fd341e Update the version number to 1.6.2a 2022-02-17 20:10:02 -06:00
Dog 81adade05b Capitalised Source Code Installation to be grammatically correct 2022-02-17 23:55:38 +00:00
Dog e3808dc986 Updated title of Readme to look nicer 2022-02-17 23:45:55 +00:00
tom lee d669b2a1fe Update and merge the render_test core 2022-02-17 22:26:48 +08:00
cola98765 2bd8dab240 #159 multiply color by color... not by alpha 2022-02-15 11:50:14 +01:00
cola98765 2b423c2edd squared colour averaging as in #159
please check if it works looks better.
2022-02-15 11:37:54 +01:00
cola98765 1a4faf4bdd close #188; fix lang parts in #189 2022-02-15 11:21:23 +01:00
cola98765 b70829aceb RotatedPillarBlock colors are taken form sides, resolving #191 2022-02-15 11:06:37 +01:00
cola98765 bba771d376 Potentially fix water texture packs. 2022-02-14 17:31:36 +01:00
James Seibel 75b18f8bd8 Update the forge version to fix a potential crash with Biomes-o-plenty 2022-02-13 16:28:21 -06:00
James Seibel 60da404900 Merge branch '1.18.X' of gitlab.com:jeseibel/minecraft-lod-mod into 1.18.X 2022-02-13 07:37:43 -06:00
coolGi2007 b75eebd0dc Getting more stuff ready for new config 2022-02-13 14:48:56 +10:30
James Seibel 72cbd1167a Prepare for 1.6.1a 2022-02-12 12:01:40 -06:00
tom lee e4e51ebf5b Update core 2022-02-12 23:54:23 +08:00
tom lee dd2096bf1b Frontported the forge mixin issue fix. (It may work without that but...) 2022-02-12 23:54:23 +08:00
coolGi2007 393a94a7a1 We don’t talk about this 1 line in the gradle 2022-02-12 14:04:18 +00:00
tom lee ef0023ef39 Switch to another way to do the world gen. Now more mod compat! 2022-02-12 22:00:09 +08:00
coolGi2007 f0994fff75 Added a way to add mods in code and not run on runtime and moved issues and source to gradle.properties 2022-02-12 19:34:54 +10:30
tom lee 31f41540c0 Fix chat format color. Add failsafe stopping of generator 2022-02-12 15:13:58 +08:00
tom lee 81fe13b9c0 Add backup to VanillaRenderedChunks & many generator stuff 2022-02-12 14:30:04 +08:00
tom lee 332df13b29 Fix loadChunk try/catch missing the mark & add WRAN on modded chunkGen 2022-02-12 13:12:25 +08:00
James Seibel b3af6df0c5 Update the version number to 1.6.1a-pre and re-enable dev code 2022-02-11 22:08:35 -06:00
James Seibel 9392e618c0 I accidently removed the "a" 2022-02-11 20:00:40 -06:00
James Seibel fd361a39a1 Update the version number and homepage link for a1.6.0 2022-02-11 19:59:23 -06:00
coolGi2007 f41de59f39 Removed some file stuff that didnt work 2022-02-11 13:05:23 +00:00
coolGi2007 c701cf987b Merge remote-tracking branch 'origin/1.18.X' into 1.18.X 2022-02-11 16:07:22 +10:30
coolGi2007 f05e878600 Added version to config file for the future 2022-02-11 16:07:10 +10:30
tom lee dc028db5ed update core + change a bit for sodium get chunk so it works better 2022-02-11 13:35:39 +08:00
James Seibel c59d7a7d27 Slightly improve the tooltips for the config GUI 2022-02-10 22:07:55 -06:00
tom lee a3dd346a02 Update core + Config + fixed blindness fog 2022-02-10 22:05:57 +08:00
tom lee dba8061f71 Update core 2022-02-10 17:08:00 +08:00
tom lee 3da2d961fc Update core 2022-02-10 16:23:33 +08:00
James Seibel aa83dc7465 Update Core 2022-02-09 19:22:29 -06:00
Morippi 392821c081 Tried to fix the render distance min detail bug 2022-02-09 22:01:17 +01:00
tom lee 7e5fc979cc Impl MEM LEAK fix from 1.16, though didn't think it was an issue before 2022-02-09 18:46:37 +08:00
tom lee 7ebb555b94 Update core 2022-02-08 13:45:04 +08:00
tom lee 3612a2f9e0 Updated core 2022-02-07 14:02:12 +08:00
coolGi2007 42b67825f8 Added custom toml to forge 2022-02-07 09:46:08 +10:30
coolGi2007 30a636c840 Added toml to be able to be used in core 2022-02-07 09:14:08 +10:30
tom lee e5722c19a9 Update core and impl the changing Region Size 2022-02-06 22:55:06 +08:00
tom lee 6b6a9ab0a9 Update core 2022-02-06 21:33:58 +08:00
tom lee 6da74c6f4e Forgot to update core... 2022-02-06 19:40:03 +08:00
tom lee 0bafa37f66 Fix and unify how key events work 2022-02-06 14:58:39 +08:00
coolGi2007 6ba6b11f6b Use cursedforge rather than modrinth for sodium download 2022-02-06 05:45:58 +00:00
James Seibel 739653f37a Add an expiration to the archives 2022-02-05 15:42:15 +00:00
coolGi2007 213d70f2d1 Removed clouds 2022-02-05 09:41:53 +00:00
tom lee dda3c7636b Update core + Moved ChunkLoader to be in line with other versions 2022-02-05 16:24:24 +08:00
tom lee 3956578043 Update core 2022-02-05 14:44:30 +08:00
tom lee d11f067392 Update core 2022-02-04 14:33:55 +08:00
tom lee 9f9fe6a231 Updated core 2022-02-04 00:32:55 +08:00
tom lee 486a30cb93 Update core 2022-02-04 00:16:25 +08:00
tom lee 01545dc295 Update the generator with 1.16 changes 2022-02-03 18:01:09 +08:00
coolGi2007 165a3799f3 Put some stuff that was duplicated in gradle to the main gradle 2022-02-02 22:40:41 +00:00
coolGi2007 308f809d5d Cleaned up some gradle stuff 2022-01-30 15:53:47 +10:30
tom lee 003dbdff02 Fixed C2ME log spam compat issue 2022-01-29 17:33:57 +08:00
tom lee 99f8dbb042 Mod compat: Fixed issue with Repurposed Structures 2022-01-29 16:50:02 +08:00
tom lee 4263ea9733 Add patch for BCLib to solve patchy features gen issue 2022-01-29 16:11:52 +08:00
tom lee c09b07a21b Greatly improve speed on loading existing chunks. 2022-01-27 14:08:06 +08:00
coolGi2007 4e0160648b Fixed issue 162 (renamed stuff) 2022-01-27 02:38:13 +00:00
coolGi2007 ad367f681d (made accidentally added string at the end of something) 2022-01-27 12:51:37 +10:30
coolGi2007 a5a70cd65b Made stuff about mod get from gradle.properties so it is easier to edit 2022-01-27 12:50:19 +10:30
coolGi2007 4ff37cfdad Fxed forge version 2022-01-27 11:14:07 +10:30
cola98765 9a1abdefa1 fixed mergeMultiData and lodBuilder with connected lods 2022-01-26 09:25:50 +01:00
tom lee 37cc7e7b37 Fixed a bug causing Fast Light mode stuck in gen loop 2022-01-26 13:14:57 +08:00
coolGi2007 04cbb1e92c Fixed forge crashing on world join 2022-01-26 04:53:45 +00:00
CodeF53 5033175808 Fix small typo. 2022-01-25 17:52:45 +00:00
tom lee 689928708c Update core and fix forge serverTickEvent firing 2 times per tick 2022-01-25 18:27:21 +08:00
tom lee 98327e6fdf Update core + Config Wrapper 2022-01-25 17:08:55 +08:00
coolGi2007 5aef0977c0 I always forget to update core 2022-01-25 04:58:09 +00:00
coolGi2007 e6738f1c80 Added comments to config file (temp solution) 2022-01-25 15:26:21 +10:30
James Seibel b55c1b8f56 Delete OptiFine_1.18.1_HD_U_H4.jar 2022-01-25 00:59:34 +00:00
tom lee 3764a4cc9e Updated core and follow core changes 2022-01-24 23:37:33 +08:00
tom lee d6bbb9d8dc Updated core and followed with some tweaks for FAR_FRIST gen 2022-01-24 23:02:53 +08:00
tom lee a38e7a00e4 Update core, Change some small stuff. 2022-01-24 21:08:17 +08:00
coolGi2007 2ec84ae3cf Fixed a typoish thing 2022-01-24 09:21:51 +00:00
coolGi2007 f03035e3f9 After all these years, the ints show up correctly after restarting (it was literally a 1 line fix) 2022-01-24 19:41:33 +10:30
coolGi2007 1d914b8f8a Refactored some stuff 2022-01-24 18:54:16 +10:30
Ran ee947b36a2 maybe it'll work 2022-01-24 10:58:26 +06:00
Ran ba393f61e5 I forgor 2022-01-24 10:32:00 +06:00
Ran 796c8e7bef Update DHJarMerger-1.0.jar 2022-01-24 10:29:03 +06:00
CodeF53 fe60de314d Dummy commit to force new job 2022-01-24 03:41:08 +00:00
CodeF53 d237db3302 remove invalid yaml code from prior commmit 2022-01-24 03:23:05 +00:00
CodeF53 f665b452b0 Don't cache old builds, uncomment jar versioning. 2022-01-24 03:19:31 +00:00
James Seibel 17750691d6 comment out the jar versioning 2022-01-23 20:52:28 -06:00
James Seibel 89ba5b9d15 Update the pipeline 2022-01-23 20:33:27 -06:00
James Seibel cea44a3f8a Update the pipeline 2022-01-23 20:17:50 -06:00
James Seibel a99c9aff76 Update the pipeline 2022-01-23 19:11:15 -06:00
James Seibel 1827ab646c Update the pipeline 2022-01-23 18:56:48 -06:00
James Seibel db00f7ebec Update the pipeline 2022-01-23 18:45:23 -06:00
James Seibel 0b93c7b5dc Update the pipeline 2022-01-23 18:25:17 -06:00
James Seibel 97204f3a3c Update the pipeline 2022-01-23 18:11:18 -06:00
James Seibel 02a6db0a62 Update the pipeline 2022-01-23 18:00:43 -06:00
James Seibel 577af4d854 Update the pipeline 2022-01-23 17:58:42 -06:00
James Seibel 68155142c3 Update the pipeline 2022-01-23 17:44:11 -06:00
James Seibel 43897e1298 Add the version name override to fabric 2022-01-23 16:48:33 -06:00
James Seibel bf2c520966 Fix a typo in the pipeline 2022-01-23 16:47:24 -06:00
James Seibel ee1528f694 Merge branch '1.18.X' of gitlab.com:jeseibel/minecraft-lod-mod into 1.18.X 2022-01-23 16:26:16 -06:00
James Seibel 8bd7556c89 Add the dateTime to compiled jars and the commit to artifacts 2022-01-23 16:25:37 -06:00
James Seibel facbb174f5 Remove logo and IDE files (they are stored in Core) 2022-01-23 16:22:29 -06:00
tom lee 9d3ce5307c Updated core + cleanup imports in WorldGen 2022-01-23 23:17:04 +08:00
tom lee 54f3e9e12d Update core 2022-01-23 21:19:53 +08:00
tom lee e294fc79eb Fixed using wrong func for makeBiome(). 2022-01-23 20:28:35 +08:00
tom lee a750aaf90a Update core + cleanup some junks 2022-01-23 19:12:18 +08:00
James Seibel be8e09eb9b Update jar merging pipeline 2022-01-22 22:47:35 -06:00
James Seibel 016d26a6f7 Update jar merging pipeline 2022-01-22 22:35:51 -06:00
James Seibel 539698c456 Update jar merging pipeline 2022-01-22 22:34:35 -06:00
James Seibel bcc11b8f0c Update jar merging pipeline 2022-01-22 22:24:52 -06:00
James Seibel c2a960162e Add a link to Ran's Jar merger repo 2022-01-22 22:24:42 -06:00
James Seibel c42a3a5fb3 Update jar merging pipeline 2022-01-22 22:13:59 -06:00
James Seibel 59d6289177 Update jar merging pipeline 2022-01-22 22:04:56 -06:00
James Seibel 4f028d118d Set the default Generation Priority to NEAR_FIRST closes #160 2022-01-22 22:04:36 -06:00
James Seibel b555e35016 Update jar merging pipeline 2022-01-22 21:58:57 -06:00
James Seibel 26b4c3a2d9 Update jar merging pipeline 2022-01-22 21:34:46 -06:00
James Seibel 2a5199f851 Update jar merging pipeline 2022-01-22 21:18:32 -06:00
James Seibel 408dbc2169 Update jar merging pipeline 2022-01-22 21:05:09 -06:00
James Seibel c9ffcfb1e8 Add jar merging to the pipeline 2022-01-22 20:50:16 -06:00
tom lee 3bd1eedcb8 Fixed Lithium WorldGen NullPtr issue cause by lazyness
Detail cause: I only override the getChunk(x,y,status,bool) and not its
sub set like getChunk(x,y), getChunk(x,y,status) because... Programmer
is always lazy. Aren't they?
2022-01-22 23:05:11 +08:00
tom lee 8500ec7a00 Fixed WorldGen to provide better support for StarLight 2022-01-22 22:38:33 +08:00
tom lee 223570a0b7 Update core. Fixed WorldGen using Util.background threads 2022-01-22 18:10:53 +08:00
tom lee de8c063731 Update core + cleanup debug logging 2022-01-22 16:10:32 +08:00
tom lee 0cffa30286 Updated core 2022-01-22 13:45:51 +08:00
coolGi2007 1d3a282c60 Added optifine tough dosnt run yet since forge dependances arnt set up yet 2022-01-21 17:49:47 +10:30
tom lee 9b6cd955b5 Updated core 2022-01-20 22:54:06 +08:00
tom lee 8e1559ac61 Update core and fix under lava (and powder snow) render fog issue 2022-01-20 21:55:17 +08:00
tom lee ce597576ba Update core and fixed slight bugs 2022-01-20 19:29:22 +08:00
tom lee d53a7a5fc4 Update core 2022-01-19 23:33:09 +08:00
tom lee 35bb5cdc92 Update core 2022-01-19 19:01:50 +08:00
tom lee 26e9cc21fd Add and fix mod compat issue with Optifine 2022-01-19 13:52:05 +08:00
tom lee 71fd448b7f Dummy commit to kick start CI, hopefully. 2022-01-18 23:15:36 +08:00
tom lee 93e18230f0 GENERATE LOD FROM FILE IS HERE!!!!!!!
Noted issue:

1. Non problematic WARN of `Tried to access a block entity before it
   was created`

2. The loading is.... a bit slow due to single thread action. Will be
   improved soon.

3. Possible Chunk Status not correct issue. It... sometimes happen, but
   it's mostly fine~

Special thanks to the YouTube commentors on the a1.6 Teaser Trailer
video. If not for them, I would not notice how many people want this,
and actually look into slapping in this feature in a1.6.
2022-01-18 22:50:57 +08:00
cola98765 d305741be2 resolved warnings. part 3 2022-01-18 11:29:01 +01:00
cola98765 5830c8d87a resolved warnings. part 2 2022-01-18 11:00:08 +01:00
cola98765 5161439536 resolved warnings. now more carefully. 2022-01-18 10:38:40 +01:00
coolGi2007 deb6ada6cc Fixed a typo 2022-01-18 09:18:36 +00:00
coolGi2007 e72a0546be Cleaned up comment on gradle and made stuff more consistent 2022-01-18 19:24:36 +10:30
jas35484 e27b43f03a Increment the version from '1.5.4a' to '1.6.0a-pre' 2022-01-17 20:33:35 -06:00
jas35484 daf4f06a30 Add .gitlab-ci.yml 2022-01-17 19:51:40 -06:00
Ran e5ef93a26d Universal jar for forge & fabric 2022-01-18 00:43:13 +06:00
cola98765 b158dff2c6 Revert "resolved couple warnings. If it causes problems just revert it."
This reverts commit b390e54801.
2022-01-17 16:27:27 +01:00
cola98765 23bbbce749 reverted config changes.... it was a bit too final 2022-01-17 16:14:52 +01:00
tom lee 898be82aab Update core 2022-01-17 22:51:28 +08:00
tom lee dc9ed37de2 Update core 2022-01-17 22:04:07 +08:00
cola98765 b390e54801 resolved couple warnings. If it causes problems just revert it. 2022-01-17 14:18:14 +01:00
tom lee 9736d2169e Update core+fabric disable StarLight 2022-01-16 17:34:35 +08:00
tom lee b507f459b3 Add basic StarLight compat. (Make it not crash) 2022-01-15 21:56:48 +08:00
tom lee 51a7053d7e Update core & make LightMode easy to switch. 2022-01-15 19:10:59 +08:00
coolGi2007 3ba40dd910 Added starlight 2022-01-15 10:14:44 +00:00
tom lee 248f8e5e70 ExpWorldGen: Add LightMode support. TODO: Config. 2022-01-15 16:58:16 +08:00
coolGi2007 49b0911aaf Escape saves config and added a immersive portals comment 2022-01-14 13:52:42 +10:30
tom lee e4b40c9383 Update core + Add disableVanillaFog for Forge 2022-01-13 23:35:18 +08:00
tom lee 328ac93178 Fixed Sodium Fog Issue. 2022-01-13 20:00:36 +08:00
tom lee d91f86aed5 Update core 2022-01-12 18:18:01 +08:00
tom lee 8119cc06ad Finally a reliable onClientChunkLoad event without light issues! 2022-01-12 16:16:20 +08:00
coolGi2007 94c9d0e276 Updated core 2022-01-11 08:45:33 +00:00
coolGi2007 e262dfa14a Fixed clouds for immersive portals 2022-01-11 08:39:09 +00:00
coolGi2007 5e0b63347e Fixes all (hopefully) problems with saving the config file 2022-01-11 17:35:45 +10:30
coolGi2007 b7df3bad22 Added a warning for clouds 2022-01-10 04:54:37 +00:00
coolGi2007 6a56c0c96f Update to add mod versions 2022-01-10 04:15:41 +00:00
tom lee fd8a94d77c Impl a semi-working getRenderedChunk for Sodium 2022-01-09 14:57:42 +08:00
tom lee 7d38fac16d Update core & try patch the light issue 2022-01-09 00:31:39 +08:00
tom lee 235ffb03a5 Make light works on pre generated chunks! Changed ChunkWrapper 2022-01-08 22:53:51 +08:00
tom lee fa2702209c Impl a getVanillaRenderedChunk 2022-01-08 15:05:12 +08:00
coolGi2007 f9f9f98750 Removed FogRenderer from forge(sorry for adding) 2022-01-08 06:25:06 +00:00
tom lee 0c46947f4d Update core 2022-01-07 19:09:07 +08:00
tom lee b5b57dfaba Update core and config 2022-01-07 18:59:02 +08:00
tom lee 39e7812f8b Updated core. Fixed wrong math in VanillaRenderedChunks 2022-01-07 15:53:30 +08:00
coolGi2007 025e8b3f9b Made clouds more optimised 2022-01-07 17:33:31 +10:30
coolGi2007 35e3a4262b Added disable vanilla fog to forge 2022-01-07 11:45:51 +10:30
coolGi2007 562c8154ff Fixed some config stuff 2022-01-06 10:49:25 +00:00
tom lee e23244181a Update core & comment out debug. Fixed/Cleaned up Fabric/Forge warpper 2022-01-06 16:28:25 +08:00
tom lee 6aa6c32299 Update core and tried fixing FAR_FIRST. Failed though.
Will continue tomorrow.
2022-01-06 00:09:45 +08:00
coolGi2007 fbdabf52e7 Made a way to save 1 config entry at a time 2022-01-05 23:07:40 +10:30
tom lee f4c1f1bcd7 Updated core and fixed generator bug 2022-01-05 19:19:14 +08:00
coolGi2007 965c19d426 Save config if you set something in the config wrapper singleton 2022-01-05 20:45:06 +10:30
tom lee 239a876fcf Update core 2022-01-05 16:58:31 +08:00
tom lee d53165881f Update core and ExperWorldGen for faster >Chunk details generation 2022-01-04 18:58:58 +08:00
tom lee 40733ea1fc Update core 2022-01-04 16:47:07 +08:00
coolGi2007 66a16ee508 Made clouds get from texture rather than use noise 2022-01-04 07:57:55 +00:00
tom lee b1a9a8ac8d Update core 2022-01-04 15:11:36 +08:00
tom lee 06a2f9f336 Updated core and comment out the @ConfigAnnotations.Category 2022-01-03 00:10:11 +08:00
coolGi2007 978bc58c11 Removed the need for any config category. The config now guesses the category 2022-01-02 16:34:47 +10:30
coolGi2007 a5577e80f1 Reordered forge mixin 2022-01-02 05:16:16 +00:00
Eric 9daf5a013c Changed cloud projection matrix to have custom clip values. 2022-01-01 21:28:56 -07:00
coolGi2007 72e2cb8a64 Updated core and fixed config crash 2022-01-02 03:51:19 +00:00
cola98765 db819698af fixed updateData 2022-01-01 13:31:23 +01:00
tom lee 09e427ab97 Updated core 2022-01-01 15:26:34 +08:00
tom lee a6b3a7ea5a Update core and fixed MixinFogs and added underwater fog 2022-01-01 13:51:35 +08:00
tom lee 4d08339f79 Updated core 2022-01-01 12:05:12 +08:00
tom lee 2ba32a8c94 Update core 2021-12-31 21:03:18 +08:00
coolGi2007 ebedd5e181 Moved some resources to core 2021-12-31 10:42:10 +00:00
tom lee 357c355e26 Updated core 2021-12-31 17:02:26 +08:00
tom lee faca159721 Updated core 2021-12-31 16:10:13 +08:00
coolGi2007 3556528932 I always forget to update core 2021-12-31 07:22:37 +00:00
coolGi2007 8513e46fdc Abstracting clouds 2021-12-31 17:51:32 +10:30
coolGi2007 323eced2a4 Fixed cloud problems 2021-12-31 17:24:45 +10:30
coolGi2007 6a87539ca3 Made a way to fully disable my clouds. Will be off by defult till clouds are done 2021-12-31 16:12:47 +10:30
coolGi2007 fe725b6795 Extended clouds 2021-12-31 04:55:01 +00:00
tom lee 02862a770f Fixed rebase issues and now it builds again 2021-12-30 22:06:30 +08:00
tom lee a7759ab8e9 Update core and config 2021-12-30 22:04:29 +08:00
cola98765 da1b2051dd made config for minimum back side culling distance. actual value is using prev player pos so on long flights it works better. 2021-12-30 13:19:47 +01:00
tom lee 4fdc596474 Update core 2021-12-29 20:38:13 +08:00
tom lee d0c710b7e1 Update core 2021-12-29 18:19:23 +08:00
tom lee 41ee9dcd99 ExperWorldGen: Hopefully fixed the ArrayIndexOutOfBound in StructStart 2021-12-29 15:10:22 +08:00
tom lee 506ce87f5f Updated core 2021-12-29 13:47:18 +08:00
coolGi2007 08e42ebfe5 Fixed ConfigGui 2021-12-29 16:16:21 +10:30
coolGi2007 699d27afd2 More universal config (works with java 8 & 16) 2021-12-28 10:50:32 +00:00
tom lee 4a64ce0bed Forge Bugfix: Fixed mixins metadata 2021-12-28 15:42:36 +08:00
tom lee b3b94d29b5 Forge Bugfix: Added accesswidener to fix access violations 2021-12-28 15:40:39 +08:00
tom lee 3a30516088 Update core & changed System.out to ClientApi.debug 2021-12-28 15:28:46 +08:00
Ran 6f469737f3 Fix forge's access transformers 2021-12-28 12:58:37 +06:00
coolGi2007 183720d1e5 Updated some config stuff for less crashing 2021-12-28 05:33:18 +00:00
tom lee b2dcc66bd0 update core 2021-12-28 00:10:18 +08:00
tom lee 5c67be30de Updated core 2021-12-27 23:43:46 +08:00
tom lee 4ad4e2c29c BufferUpload: Coresponding to core commit
Changed configs. Also added some more exception logging in
ExperWorldGen. And added a flag to JVM Minecraft to force JVM to always
capture Stack Traces.
2021-12-27 16:09:20 +08:00
cola98765 d1f805d178 optimised setupColorAndTint, specifically part where it calculates if block is gray for no reason if it's not going to be tinted anyway. 2021-12-26 16:08:02 +01:00
cola98765 73071119fa forgot I'm working on wrapper... still, I need color. 2021-12-26 15:41:58 +01:00
cola98765 97c52834f5 fixed SPRUCE and BIRCH leaves, as they require hardcoded biome color. TODO azalea also is like that 2021-12-26 15:36:18 +01:00
coolGi2007 3e472e454a Fixed bugs with ConfigGui 2021-12-26 16:47:28 +10:30
coolGi2007 7ddab31337 Updated comment for config 2021-12-26 03:50:07 +00:00
coolGi2007 fd5b9be523 WAHOO. CONFIG FINALLY SAVES!!! 2021-12-26 03:39:39 +00:00
cola98765 f9dd870067 changed fabric debug key to F8 2021-12-25 13:45:34 +01:00
cola98765 4908acd7ac fixed light requiring Y offset 2021-12-25 13:19:10 +01:00
coolGi2007 87486f6825 Fixed some config stuff. Only 1 more thing to go 2021-12-25 20:52:46 +10:30
tom lee c721c14e27 ExperWorldGen: Added perf logger
set ENABLE_PERF_LOGGING at WorldGenerationStep to true to enable it
2021-12-24 23:44:00 +08:00
tom lee 3521af9792 ExperWorldGen: Make it also works with non Feature 2021-12-24 22:23:02 +08:00
tom lee ff94dba348 ExperWorldGen: Fix major bugs and improved speed 2021-12-24 22:14:04 +08:00
cola98765 31d0a45555 potential fix to cherry leaves (call me if you see gray blocks that should not be gray) 2021-12-24 12:56:00 +01:00
tom lee 41c1473e04 ExperWorldGen: Use ThreadLocal to cache stuff 2021-12-24 17:18:58 +08:00
tom lee d5f12466b2 ExperWorldGen: Fixed World gen on non Overworld 2021-12-24 14:43:07 +08:00
coolGi2007 bdd9ef6b40 Fixed tooltip. Now only the saving is needed to be fixed 2021-12-24 16:14:35 +10:30
James Seibel 9b6895ec68 Refactor and comment ConfigGui 2021-12-23 20:01:53 -06:00
Ran a3854561fc Merge remote-tracking branch 'origin/1.18.X' into 1.18.X 2021-12-23 22:50:32 +06:00
Ran a66df74ec9 BlockEvents 2021-12-23 22:50:06 +06:00
tom lee eb4b31e876 Render: Changed rendered chunk getter to return circles 2021-12-23 18:40:22 +08:00
tom lee 6015b9a1dc ExperWorldGen: Increased timeout for slow CPUs 2021-12-23 18:40:22 +08:00
tom lee 146d42bbe9 Fabric: Added no vanilla fog support.
This isn't availible due to Forge default overrides something. Note that
this noFog also won't work on custom renderer.
2021-12-23 18:40:22 +08:00
Ran 16b14bc424 Add MinecraftForge License 2021-12-23 14:53:58 +06:00
Ran a37e4ca232 Merge remote-tracking branch 'origin/1.18.X' into 1.18.X 2021-12-23 14:47:59 +06:00
Ran 8103c16064 Fix warnings & add License 2021-12-23 14:47:38 +06:00
tom lee 6ae41b0caa ExperWorldGen: Polished stuff. No more error messages. use configs.
I would say this version is the first that is playable.
2021-12-23 16:36:14 +08:00
Ran ba81f31027 Update some stuffs 2021-12-22 22:16:08 +06:00
tom lee 71c72e26e7 ExprWorldGen: Fixed lots of stuff and Features now works!
Still Features exception, which I know how to fix I think.
2021-12-22 23:02:28 +08:00
Ran 97828f465d Server-sided Incoming 2021-12-22 20:32:03 +06:00
Ran ec37803572 Merge remote-tracking branch 'origin/1.18.X' into 1.18.X 2021-12-22 19:47:45 +06:00
Ran b7a54eff7a Explain why this exists 2021-12-22 19:47:22 +06:00
coolGi2007 9604ce297c Fixed not building 2021-12-22 09:53:56 +00:00
Ran 5ad961d80e Delete random log file; Sorry if this was important 2021-12-22 14:02:54 +06:00
Ran 843ec2fef8 Disable run for core & common 2021-12-22 14:01:27 +06:00
Ran 1b3e90b669 Make gradle compatible with Java 17 2021-12-22 13:53:34 +06:00
coolGi2007 55aadb73f1 Fixed the config button on forge menu 2021-12-22 07:07:21 +00:00
coolGi2007 e3d87c70c4 Updated config to be smaller 2021-12-22 05:37:59 +00:00
tom lee 8b1205f79e Fixed Fog color 2021-12-22 11:24:25 +08:00
tom lee 291f5d247c updated core 2021-12-21 21:13:44 +08:00
tom lee ad63825194 ExprWorldGen: Fixed some bugs. Still more to go. 2021-12-21 16:11:57 +08:00
tom lee b0e0cd107d Updated core 2021-12-21 15:49:44 +08:00
tom lee 5f60cd8d4d WorldGen: Added thread timeout failsafe 2021-12-20 14:31:32 +08:00
tom lee d0e17ccab7 Modified a bit of how it determine generation range 2021-12-19 22:35:21 +08:00
tom lee 38a4643cf3 WorldGen: Reversed priority for far vs near 2021-12-19 22:03:15 +08:00
tom lee 938adca022 Changed config for world gen 2021-12-19 21:42:05 +08:00
tom lee e2ec80134e Set the UseUnstable...Config to true by default for now 2021-12-19 21:39:51 +08:00
tom lee 903f166041 ExpWorldGen: Fix DeadLocks, improved cpu utilisations
Now world gen aways try to keep a certain amount of generation events
active.
2021-12-19 18:27:42 +08:00
TomTheFurry a9bdbfda4e Merge branch '1.18' into '1.18.X'
Merge the exprimental world gen

See merge request jeseibel/minecraft-lod-mod!13
2021-12-18 16:40:44 +00:00
tom lee 378349b870 Added experimental world generator. (Features mode only for now)
Turn on the AllowUnstableFeatureGeneration button to enable it. It is a
temp setting and will be renamed later. There will be many issues with
the generator, but at least it for now works... To be fixed tomorrow.
2021-12-19 00:32:42 +08:00
coolGi2007 190ce716ff Forgot to make the forge run client actually run forge 2021-12-17 11:59:05 +00:00
coolGi2007 d2c3a87fa8 Fixed some general stuff that broke when updating to .1.8.1 2021-12-17 11:47:39 +00:00
coolGi2007 2d5acbbf45 Updated to 1.18.1 but also works on 1.18 2021-12-17 08:52:46 +00:00
coolGi2007 4e973099f9 Updated my config 2021-12-17 08:29:14 +00:00
tom lee ee4f43cc59 WorldGen: Now only somewhat lock up server TPS
Use recent change to core so that we no longer request 8 chunk
generations per server tick, but instead just 1.
2021-12-17 16:00:44 +08:00
tom lee 3e64b7400e Updated core 2021-12-17 14:56:29 +08:00
James Seibel c44daa759c Remove the Forge server mod requirement and update the credits 2021-12-16 21:47:23 -06:00
tom lee 17c662b10f Fix -64 offset color bug: Impl' getMinHeight()
It calls works by calling getMinBuildHeight()
2021-12-16 18:39:58 +08:00
tom lee 3cfbb69dd9 Update core & fix Wrappers 2021-12-15 16:45:33 +08:00
tom lee 470668265b Updated core. Cann't test if works, in a hurry. 2021-12-15 00:08:38 +08:00
tom lee b6ced30d70 Updated core 2021-12-14 21:40:15 +08:00
coolGi2007 d3e0f1e14d leetom can you check it works before updating core 2021-12-14 08:36:33 +00:00
tom lee 910350ba3a Update core to use new Renderer system 2021-12-14 15:06:32 +08:00
coolGi2007 8dcf30e776 Updated core 2021-12-13 12:27:28 +00:00
coolGi2007 30d4bcd6a1 Updated config 2021-12-13 12:11:39 +00:00
tom lee 66300cbe70 WorldGen: Fix VersionConstants and more comments
More comments in WorldGenWrapper and fix version constants to always
return true in isWorldGeneratorSingleThreaded()
2021-12-12 23:28:18 +08:00
coolGi2007 50ae719f24 Updatec core 2021-12-12 04:01:04 +00:00
coolGi2007 dccad778fb Updaterd core 2021-12-12 01:44:05 +00:00
tom lee f163e31cd2 WorldGen: Half fixed world gen
Note that currently world gen is single threaded. Below is the current
mapped settings:

BIOME_ONLY -> ChunkStatus.BIOMES : <1 tick
BIOME_ONLY_SIMULATE_HEIGHT -> ChunkStatus.NOISE : <1 tick
SURFACE -> ChunkStatus.SURFACE : <1 tick
FEATURE -> ChunkStatus.FEATURE : 1-2 tick
FULL -> ChunkStatus.FULL : ~ 1-10 tick (?? Probably because of the threaded light engine update)
2021-12-12 02:05:12 +08:00
coolGi2007 5499079ada Updated readme to say to install git 2021-12-11 10:36:25 +00:00
coolGi2007 8d1277db1b Fixed build not building 2021-12-11 09:15:38 +00:00
coolGi2007 34fcac25c2 Updated behind the scenes config stuff 2021-12-11 06:06:10 +00:00
coolGi2007 cb0516cae8 Updated core 2021-12-11 04:05:48 +00:00
cola98765 4fdad05252 Merge branch '1.18' into '1.18'
FIx lightmap flicker on pause menu

See merge request jeseibel/minecraft-lod-mod!12
2021-12-10 10:39:40 +00:00
tom lee dc785b4fe1 Bugfix: Pause menu flicker issue 2021-12-10 17:29:16 +08:00
coolGi2007 8df7e1762a Updated core 2021-12-10 05:22:18 +00:00
coolGi2007 43d9b41648 Updated readme & removed stuff from conig 2021-12-10 01:21:04 +00:00
coolGi2007 880559f94a Updated core 2021-12-10 01:07:27 +00:00
Morippi 6f04ddce87 added the get names 2021-12-09 16:10:47 +01:00
Ran 6eb065f7c9 We do a little bit of coring here 2021-12-09 17:00:34 +06:00
Ran 17ebad9141 Merge remote-tracking branch 'origin/1.18' into 1.18 2021-12-09 16:59:51 +06:00
coolGi2007 9bcc799b0b Fixed forge not building 2021-12-09 10:44:38 +00:00
Ran f247410ae4 We do a little bit of coring here 2021-12-09 16:38:45 +06:00
coolGi2007 2f3bb2ec34 Update readme to be more accurate with architectury 2021-12-09 06:27:24 +00:00
coolGi2007 5c47170ef4 Now uses Architectury and added Forge support 2021-12-09 06:14:30 +00:00
coolGi2007 29d152b312 Updated core (i really need to add a subproject) 2021-12-08 23:54:04 +00:00
coolGi2007 aa48f0f5c6 Might fix windows not working 2021-12-07 05:24:13 +00:00
coolGi2007 05ea683fcf Fixed build problem 2021-12-06 12:39:42 +00:00
coolGi2007 65163a2477 Update Readme.md 2021-12-06 11:43:42 +00:00
coolGi2007 9dc4c46b99 Initual upload to branch 2021-12-06 11:39:57 +00:00
140 changed files with 7674 additions and 1638 deletions
+32 -11
View File
@@ -3,7 +3,8 @@ image: gradle:eclipse-temurin
# all stages need to be defined here
stages:
- build_17_1
- build_18_1
- build_18_2
variables:
# Pull core when building
@@ -16,19 +17,39 @@ before_script:
- echo GE_JOB_ID=$CI_JOB_ID >> generate_jars.env
# 1.17.1 build
build_17_1:
stage: build_17_1
script:
# 1.18.1 build
build_18_1:
stage: build_18_1
script:
- ./gradlew deleteMerged --gradle-user-home cache/; # make sure any previously merged jars are removed before running this job
- ./gradlew build -PmcVer=1.17.1 --gradle-user-home cache/;
- ./gradlew build -PmcVer=1.18.1 --gradle-user-home cache/;
- ./gradlew merge --gradle-user-home cache/;
# build using Java 16
image: eclipse-temurin:16
# build using Java 17
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_17_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
name: "Merged_NightlyBuild_1_18_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
# relative to the root directory
- Merged
expire_in: 1 day
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
# 1.18.2 build
build_18_2:
stage: build_18_2
script:
- ./gradlew deleteMerged --gradle-user-home cache/;
- ./gradlew build -PmcVer=1.18.2 --gradle-user-home cache/;
- ./gradlew merge --gradle-user-home cache/;
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_18_2-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
# relative to the root directory
- Merged
expire_in: 1 day
cache:
@@ -61,5 +82,5 @@ build_17_1:
# - name: 'Fabric Jars'
# url: 'https://gitlab.com/jeseibel/minecraft-lod-mod/cw/-/jobs/${GE_JOB_ID}/artifacts/file/fabric/build/libs'
# - name: 'Forge Jars'
# url: 'https://gitlab.com/jeseibel/minecraft-lod-mod/cw/-/jobs/${GE_JOB_ID}/artifacts/file/forge/build/libs'
# url: 'https://gitlab.com/jeseibel/minecraft-lod-mod/cw/-/jobs/${GE_JOB_ID}/artifacts/file/forge/build/libs'
+1 -1
View File
@@ -1,4 +1,4 @@
[submodule "core"]
path = core
url = https://gitlab.com/jeseibel/distant-horizons-core.git
branch = main
branch = main
-36
View File
@@ -1,36 +0,0 @@
org.gradle.jvmargs=-Xmx2048M
minecraft_version=1.17.1
java_version=16
# Fabric loader
fabric_loader_version=0.13.2
fabric_api_version=0.46.1+1.17
# Fabric mod versions
modmenu_version=2.0.14
starlight_version_fabric=3442770
lithium_version=mc1.17.1-0.7.5
sodium_version=3605275
iris_version=1.17.x-v1.1.4
immersive_portals_version = 0.14-1.17
# Fabric mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight=0
enable_lithium=0
enable_sodium=1
enable_iris=0
# Forge loader
forge_version=37.1.1
# Forge mod versions
starlight_version_forge=3457784
# Forge mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight_forge=0
+39
View File
@@ -0,0 +1,39 @@
# 1.18.1 version based stuff
minecraft_version=1.18.1
java_version = 17
# Fabric loader
fabric_loader_version=0.13.3
fabric_api_version=0.46.6+1.18
# Fabric mod versions
modmenu_version=3.0.1
starlight_version_fabric=3554912
phosphor_version_fabric=3573395
lithium_version=mc1.18.1-0.7.7
sodium_version=3605309
iris_version=1.18.x-v1.1.4
bclib_version=1.2.5
immersive_portals_version = v1.0.4-1.18
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=0
enable_bclib=0
# Forge loader
forge_version=39.1.2
# Forge mod versions
starlight_version_forge=3559934
# Forge mod run
# 0 = Dont enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
+40
View File
@@ -0,0 +1,40 @@
# 1.18.2 version based stuff
# architectury_plugin_version = 3.4-SNAPSHOT
# dev_architectury_loom_version = 0.10.0-SNAPSHOT
minecraft_version=1.18.2
java_version = 17
# Fabric loader
fabric_loader_version=0.13.3
fabric_api_version=0.48.0+1.18.2
# Fabric mod versions
modmenu_version=3.1.0
starlight_version_fabric=3667443
phosphor_version_fabric=3573395
lithium_version=mc1.18.2-0.7.9
sodium_version=3669187
iris_version=1.18.x-v1.2.2
immersive_portals_version = v1.0.4-1.18
bclib_version=0
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=0
enable_bclib=0
# Forge loader
forge_version=40.0.18
# Forge mod versions
starlight_version_forge=0
# Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
+23 -11
View File
@@ -21,11 +21,22 @@ If you want to see a quick demo, check out a video covering the mod here:
Architectury version: 3.4-SNAPSHOT\
Java Compiler plugin: Manifold Preprocessor
#### 1.17.1 mods
Forge version: 37.1.1\
Fabric version: 0.13.2\
Fabric API version: 0.46.1+1.17\
Modmenu version: 2.0.14
#### 1.18.2 mods
Forge version: 40.0.18\
Fabric version: 0.13.3\
Fabric API version: 0.48.0+1.18.2\
Modmenu version: 3.1.0
#### 1.18.1 mods
Forge version: 39.1.2\
Fabric version: 0.13.3\
Fabric API version: 0.46.6+1.18\
Modmenu version: 3.0.1
Notes:\
This version has been confirmed to work in IDE and Retail Minecraft.\
(Retail running forge version 1.18.1-39.0.5 and fabric version 1.18-0.12.12 and 1.18.1-0.13.2)
## Source Code Installation
@@ -51,14 +62,15 @@ https://fabricmc.net/wiki/tutorial:setup
4. Import the project into eclipse
## Switching Versions
This branch support 1 built versions:
- 1.17.1 (which also runs on 1.17)
This branch support 2 built versions:
- 1.18.2
- 1.18.1 (which also runs on 1.18)
To switch between active versions, change `mcVer=1.17.?` in `gradle.properties` file.
To switch between active versions, change `mcVer=1.18.?` in `gradle.properties` file.
If running on IDE, to ensure IDE pickup the changed versions, you will need to run a gradle command again to allow gradle to update all the libs. (In IntellJ you will also need to do a gradle sync again if it didn't start it automatically.)
>Note: There may be a `java.nio.file.FileSystemException` thrown on running the command after switching versions. To fix it, either restart your IDE (as your IDE is locking up a file) or use tools like LockHunter to unlock the linked file. (Often a lib file under `common\build\lib` or `forge\build\lib` or `fabric\build\lib`). If anyone knows how to solve this issue please comment to this issue: https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/233
## Compiling
**Using GUI**
@@ -70,12 +82,12 @@ If running on IDE, to ensure IDE pickup the changed versions, you will need to r
6. The compiled jar file will be in the folder `Merged`
**If in terminal:**
1. `git clone -b preprocessor_test --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
1. `git clone -b 1.18.X --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
2. `cd minecraft-lod-mod`
3. `./gradlew assemble`
4. `./gradlew mergeJars`
5. The compiled jar file will be in the folder `Merged`
>Note: You can add the arg: `-PmcVer=1.17.?` to tell gradle to build a selected MC version instead of having to manually modify the `gradle.properties` file.
>Note: You can add the arg: `-PmcVer=1.18.?` to tell gradle to build a selected MC version instead of having to manually modify the `gradle.properties` file.
## Other commands
+52 -36
View File
@@ -9,7 +9,7 @@ buildscript {
plugins {
id "architectury-plugin" version "3.4-SNAPSHOT"
id "dev.architectury.loom" version "0.10.0.195" apply false
id "dev.architectury.loom" version "0.10.0-SNAPSHOT" apply false
}
def writeBuildGradlePredefine() {
@@ -18,20 +18,20 @@ def writeBuildGradlePredefine() {
}
def loadProperties() {
def defaultMcVersion = '1.17.1'
def defaultMcVersion = '1.18.2'
if (!project.hasProperty("mcVer")) {
println "No mcVer set! Defaulting to ${defaultMcVersion}."
println "Tip: Use -PmcVer='${defaultMcVersion}' in cmd arg to set mcVer."
}
def mcVersion = project.hasProperty("mcVer") ? mcVer : defaultMcVersion
println "Loading properties file at " + mcVersion + ".properties"
def props = new Properties()
props.load(new FileInputStream("$rootProject.rootDir/"+"$mcVersion"+".properties"))
def mcVersion = project.hasProperty("mcVer") ? mcVer : defaultMcVersion
println "Loading properties file at " + mcVersion + ".properties"
def props = new Properties()
props.load(new FileInputStream("$rootProject.rootDir/"+"$mcVersion"+".properties"))
props.each { prop ->
rootProject.ext.set(prop.key, prop.value)
// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
rootProject.ext.set(prop.key, prop.value)
// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
}
writeBuildGradlePredefine()
}
@@ -60,9 +60,9 @@ subprojects { p ->
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
// The following line declares the mojmap mappings
mappings loom.officialMojangMappings()
//Manifold
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
//Manifold
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
// Toml
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
@@ -73,7 +73,6 @@ subprojects { p ->
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
}
if (p != project(":core")) {
common(project(":core")) { transitive false }
shadowMe(project(":core")) { transitive false }
@@ -89,7 +88,7 @@ subprojects { p ->
}
}
allprojects {
allprojects { p ->
apply plugin: "java"
apply plugin: "architectury-plugin"
apply plugin: "maven-publish"
@@ -102,9 +101,9 @@ allprojects {
mavenCentral()
// used to download and compile dependencies from git repos
maven { url 'https://jitpack.io' }
// For Manifold Preprocessor
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// For Manifold Preprocessor
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// Required for importing Modrinth mods
maven {
@@ -138,6 +137,7 @@ allprojects {
}
}
// Put stuff from gradle.properties into the mod info
processResources {
def resourceTargets = ["fabric.mod.json", "META-INF/mods.toml"] // Location of where to put
@@ -174,36 +174,52 @@ allprojects {
}
}
tasks.withType(JavaCompile) {
// // Add Manifold Preprocessor
//// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
//// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
////
// //options.compilerArgs += ['-deprecation']
// //options.compilerArgs += ['-verbose']
// //options.compilerArgs += ['-Xlint:unchecked']
// //options.compilerArgs += ['-Xdiags:verbose']
// //options.compilerArgs += ['-Xprint']
// //options.compilerArgs += ['-XprintProcessorInfo']
// //options.compilerArgs += ['-XprintRounds']
// Add Manifold Preprocessor
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
//
// // println options.compilerArgs
// if (p != project(":core")) {
// options.compilerArgs += ['-Xplugin:Manifold']
// options.release = rootProject.java_version as Integer
// }
options.encoding = "UTF-8"
options.release = 16
//options.compilerArgs += ['-deprecation']
//options.compilerArgs += ['-verbose']
//options.compilerArgs += ['-Xlint:unchecked']
//options.compilerArgs += ['-Xdiags:verbose']
//options.compilerArgs += ['-Xprint']
//options.compilerArgs += ['-XprintProcessorInfo']
//options.compilerArgs += ['-XprintRounds']
// println options.compilerArgs
if (p != project(":core")) {
options.compilerArgs += ['-Xplugin:Manifold']
options.release = rootProject.java_version as Integer
}
}
java {
withSourcesJar()
}
if (p == project(":core") || p == project(":common")) {
runClient.enabled = false
runServer.enabled = false
}
// this is necessary for running the fabric build
if (p == project(":common")) {
println "Coping [common/src/main/resources/lod.accesswidner] to [fabric/build/resources/main]."
copy {
from "$rootProject.rootDir/common/src/main/resources"
into "$rootProject.rootDir/fabric/build/resources/main"
include "*.accesswidener"
}
}
}
// this deletes the merged folder so we don't carry over
// the previous merges to each new build job in the CI/CD pipeline
task deleteMerged(type: Delete) {
delete files("./Merged")
delete files("./Merged")
}
@@ -19,7 +19,6 @@
package com.seibel.lod.common;
import com.seibel.lod.common.wrappers.config.ConfigGui;
import com.seibel.lod.core.config.*;
import com.seibel.lod.core.enums.config.*;
import com.seibel.lod.core.enums.rendering.*;
@@ -33,12 +32,14 @@ import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.I
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IAdvanced;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IAdvanced.IDebugging.*;
/**
* This handles any configuration the user has access to.
* @author coolGi2007
* @version 12-12-2021
*/
public class Config extends ConfigGui
public class Config
//public class Config extends TinyConfig
{
// CONFIG STRUCTURE
@@ -55,12 +56,12 @@ public class Config extends ConfigGui
// |-> Threads
// |-> Buffers
// |-> Debugging
// Since the original config system uses forge stuff, that means we have to rewrite the whole config system
@ConfigAnnotations.ScreenEntry
public static Client client;
@ConfigAnnotations.FileComment
public static String _optionsButton = ILodConfigWrapperSingleton.IClient.OPTIONS_BUTTON_DESC;
// I know this option should be in Client
@@ -68,58 +69,61 @@ public class Config extends ConfigGui
// Tough it is in client in the wrapper singleton
@ConfigAnnotations.Entry
public static boolean optionsButton = true;
public static class Client {
public static class Client
{
@ConfigAnnotations.ScreenEntry
public static Graphics graphics;
@ConfigAnnotations.ScreenEntry
public static WorldGenerator worldGenerator;
@ConfigAnnotations.ScreenEntry
public static Multiplayer multiplayer;
@ConfigAnnotations.ScreenEntry
public static Advanced advanced;
public static class Graphics {
public static class Graphics
{
@ConfigAnnotations.ScreenEntry
public static Quality quality;
@ConfigAnnotations.ScreenEntry
public static FogQuality fogQuality;
@ConfigAnnotations.ScreenEntry
public static AdvancedGraphics advancedGraphics;
public static class Quality {
public static class Quality
{
@ConfigAnnotations.FileComment
public static String _drawResolution = IQuality.DRAW_RESOLUTION_DESC;
@ConfigAnnotations.Entry
public static HorizontalResolution drawResolution = IQuality.DRAW_RESOLUTION_DEFAULT;
@ConfigAnnotations.FileComment
public static String _lodChunkRenderDistance = IQuality.LOD_CHUNK_RENDER_DISTANCE_DESC;
@ConfigAnnotations.Entry(minValue = 16, maxValue = 2048)
public static int lodChunkRenderDistance = IQuality.LOD_CHUNK_RENDER_DISTANCE_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _verticalQuality = IQuality.VERTICAL_QUALITY_DESC;
@ConfigAnnotations.Entry
public static VerticalQuality verticalQuality = IQuality.VERTICAL_QUALITY_DEFAULT;
@ConfigAnnotations.FileComment
public static String _horizontalScale = IQuality.HORIZONTAL_SCALE_DESC;
@ConfigAnnotations.Entry(minValue = 2, maxValue = 32)
public static int horizontalScale = IQuality.HORIZONTAL_SCALE_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _horizontalQuality = IQuality.HORIZONTAL_SCALE_DESC;
@ConfigAnnotations.Entry
public static HorizontalQuality horizontalQuality = IQuality.HORIZONTAL_QUALITY_DEFAULT;
@ConfigAnnotations.FileComment
public static String _dropoffQuality = IQuality.DROPOFF_QUALITY_DESC;
@ConfigAnnotations.Entry
@@ -130,70 +134,71 @@ public class Config extends ConfigGui
@ConfigAnnotations.Entry(minValue = 0, maxValue = 7)
public static int lodBiomeBlending = IQuality.LOD_BIOME_BLENDING_MIN_DEFAULT_MAX.defaultValue;
}
public static class FogQuality {
public static class FogQuality
{
@ConfigAnnotations.FileComment
public static String _fogDistance = IFogQuality.FOG_DISTANCE_DESC;
@ConfigAnnotations.Entry
public static FogDistance fogDistance = IFogQuality.FOG_DISTANCE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _fogDrawMode = IFogQuality.FOG_DRAW_MODE_DESC;
@ConfigAnnotations.Entry
public static FogDrawMode fogDrawMode = IFogQuality.FOG_DRAW_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _fogColorMode = IFogQuality.FOG_COLOR_MODE_DESC;
@ConfigAnnotations.Entry
public static FogColorMode fogColorMode = IFogQuality.FOG_COLOR_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _disableVanillaFog = IFogQuality.DISABLE_VANILLA_FOG_DESC;
@ConfigAnnotations.Entry
public static boolean disableVanillaFog = IFogQuality.DISABLE_VANILLA_FOG_DEFAULT;
@ConfigAnnotations.ScreenEntry
public static AdvancedFog advancedFog;
public static class AdvancedFog {
static final double SQRT2 = 1.4142135623730951;
@ConfigAnnotations.FileComment
public static String _farFogStart = IAdvancedFog.FAR_FOG_START_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
public static double farFogStart = IAdvancedFog.FAR_FOG_START_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _farFogEnd = IAdvancedFog.FAR_FOG_END_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
public static double farFogEnd = IAdvancedFog.FAR_FOG_END_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _farFogMin = IAdvancedFog.FAR_FOG_MIN_DESC;
@ConfigAnnotations.Entry(minValue = -5.0, maxValue = SQRT2)
public static double farFogMin = IAdvancedFog.FAR_FOG_MIN_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _farFogMax = IAdvancedFog.FAR_FOG_MAX_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = 5.0)
public static double farFogMax = IAdvancedFog.FAR_FOG_MAX_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _farFogType = IAdvancedFog.FAR_FOG_TYPE_DESC;
@ConfigAnnotations.Entry
public static FogSetting.FogType farFogType = IAdvancedFog.FAR_FOG_TYPE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _farFogDensity = IAdvancedFog.FAR_FOG_DENSITY_DESC;
@ConfigAnnotations.Entry(minValue = 0.01, maxValue = 50.0)
public static double farFogDensity = IAdvancedFog.FAR_FOG_DENSITY_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.ScreenEntry
public static HeightFog heightFog;
public static class HeightFog {
@ConfigAnnotations.FileComment
public static String _heightFogMixMode = IHeightFog.HEIGHT_FOG_MIX_MODE_DESC;
@ConfigAnnotations.Entry
@@ -202,52 +207,54 @@ public class Config extends ConfigGui
public static String _heightFogMode = IHeightFog.HEIGHT_FOG_MODE_DESC;
@ConfigAnnotations.Entry
public static HeightFogMode heightFogMode = IHeightFog.HEIGHT_FOG_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _heightFogHeight = IHeightFog.HEIGHT_FOG_HEIGHT_DESC;
@ConfigAnnotations.Entry(minValue = -4096.0, maxValue = 4096.0)
public static double heightFogHeight = IHeightFog.HEIGHT_FOG_HEIGHT_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogStart = IHeightFog.HEIGHT_FOG_START_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
public static double heightFogStart = IHeightFog.HEIGHT_FOG_START_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogEnd = IHeightFog.HEIGHT_FOG_END_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
public static double heightFogEnd = IHeightFog.HEIGHT_FOG_END_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogMin = IHeightFog.HEIGHT_FOG_MIN_DESC;
@ConfigAnnotations.Entry(minValue = -5.0, maxValue = SQRT2)
public static double heightFogMin = IHeightFog.HEIGHT_FOG_MIN_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogMax = IHeightFog.HEIGHT_FOG_MAX_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = 5.0)
public static double heightFogMax = IHeightFog.HEIGHT_FOG_MAX_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogType = IHeightFog.HEIGHT_FOG_TYPE_DESC;
@ConfigAnnotations.Entry
public static FogSetting.FogType heightFogType = IHeightFog.HEIGHT_FOG_TYPE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _heightFogDensity = IHeightFog.HEIGHT_FOG_DENSITY_DESC;
@ConfigAnnotations.Entry(minValue = 0.01, maxValue = 50.0)
public static double heightFogDensity = IHeightFog.HEIGHT_FOG_DENSITY_MIN_DEFAULT_MAX.defaultValue;
}
}
}
public static class AdvancedGraphics {
public static class AdvancedGraphics
{
@ConfigAnnotations.FileComment
public static String _disableDirectionalCulling = IAdvancedGraphics.DISABLE_DIRECTIONAL_CULLING_DESC;
@ConfigAnnotations.Entry
public static boolean disableDirectionalCulling = IAdvancedGraphics.DISABLE_DIRECTIONAL_CULLING_DEFAULT;
@ConfigAnnotations.FileComment
public static String _vanillaOverdraw = IAdvancedGraphics.VANILLA_OVERDRAW_DESC;
@ConfigAnnotations.Entry
@@ -262,12 +269,12 @@ public class Config extends ConfigGui
public static String _useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DESC;
@ConfigAnnotations.Entry
public static boolean useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _brightnessMultiplier = IAdvancedGraphics.BRIGHTNESS_MULTIPLIER_DESC;
@ConfigAnnotations.Entry
public static double brightnessMultiplier = IAdvancedGraphics.BRIGHTNESS_MULTIPLIER_DEFAULT;
@ConfigAnnotations.FileComment
public static String _saturationMultiplier = IAdvancedGraphics.SATURATION_MULTIPLIER_DESC;
@ConfigAnnotations.Entry
@@ -281,7 +288,7 @@ public class Config extends ConfigGui
@ConfigAnnotations.FileComment
public static String _caveCullingHeight = IAdvancedGraphics.CAVE_CULLING_HEIGHT_DESC;
@ConfigAnnotations.Entry(minValue = -4096, maxValue = 4096)
public static int caveCullingHeight = IAdvancedGraphics.CAVE_CULLING_HEIGHT_MIN_DEFAULT_MAX.defaultValue;
public static int caveCullingHeight = IAdvancedGraphics.CAVE_CULLING_HEIGHT_MIN_DEFAULT_MAX.defaultValue;
/*
@ConfigAnnotations.FileComment
@@ -291,24 +298,25 @@ public class Config extends ConfigGui
*/
}
}
public static class WorldGenerator {
public static class WorldGenerator
{
@ConfigAnnotations.FileComment
public static String _enableDistantGeneration = IWorldGenerator.ENABLE_DISTANT_GENERATION_DESC;
@ConfigAnnotations.Entry
public static boolean enableDistantGeneration = IWorldGenerator.ENABLE_DISTANT_GENERATION_DEFAULT;
// @ConfigAnnotations.FileComment
// public static String _distanceGenerationMode = IWorldGenerator.getDistanceGenerationModeDesc();
@ConfigAnnotations.Entry
public static DistanceGenerationMode distanceGenerationMode = IWorldGenerator.DISTANCE_GENERATION_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _lightGenerationMode = IWorldGenerator.LIGHT_GENERATION_MODE_DESC;
@ConfigAnnotations.Entry
public static LightGenerationMode lightGenerationMode = IWorldGenerator.LIGHT_GENERATION_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _generationPriority = IWorldGenerator.GENERATION_PRIORITY_DESC;
@ConfigAnnotations.Entry
@@ -321,34 +329,37 @@ public class Config extends ConfigGui
@ConfigAnnotations.Entry
public static boolean allowUnstableFeatureGeneration = true;//IWorldGenerator.ALLOW_UNSTABLE_FEATURE_GENERATION_DEFAULT;
*/
@ConfigAnnotations.FileComment
public static String _blocksToAvoid = IWorldGenerator.BLOCKS_TO_AVOID_DESC;
@ConfigAnnotations.Entry
public static BlocksToAvoid blocksToAvoid = IWorldGenerator.BLOCKS_TO_AVOID_DEFAULT;
}
public static class Multiplayer {
public static class Multiplayer
{
@ConfigAnnotations.FileComment
public static String _serverFolderNameMode = IMultiplayer.SERVER_FOLDER_NAME_MODE_DESC;
@ConfigAnnotations.Entry
public static ServerFolderNameMode serverFolderNameMode = IMultiplayer.SERVER_FOLDER_NAME_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _multiDimensionRequiredSimilarity = IMultiplayer.MULTI_DIMENSION_REQUIRED_SIMILARITY_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = 1.0)
public static double multiDimensionRequiredSimilarity = IMultiplayer.MULTI_DIMENSION_REQUIRED_SIMILARITY_MIN_DEFAULT_MAX.defaultValue;
}
public static class Advanced {
public static class Advanced
{
@ConfigAnnotations.ScreenEntry
public static Threading threading;
@ConfigAnnotations.ScreenEntry
public static Debugging debugging;
@ConfigAnnotations.ScreenEntry
public static Buffers buffers;
@@ -358,110 +369,112 @@ public class Config extends ConfigGui
public static boolean lodOnlyMode = IAdvanced.LOD_ONLY_MODE_DEFAULT;
public static class Threading {
public static class Threading
{
@ConfigAnnotations.FileComment
public static String _numberOfWorldGenerationThreads = IThreading.NUMBER_OF_WORLD_GENERATION_THREADS_DESC;
@ConfigAnnotations.Entry(minValue = 1, maxValue = 50)
public static int numberOfWorldGenerationThreads = IThreading.NUMBER_OF_WORLD_GENERATION_THREADS_DEFAULT.defaultValue;
@ConfigAnnotations.FileComment
public static String _numberOfBufferBuilderThreads = IThreading.NUMBER_OF_BUFFER_BUILDER_THREADS_DESC;
@ConfigAnnotations.Entry(minValue = 1, maxValue = 50)
public static int numberOfBufferBuilderThreads = IThreading.NUMBER_OF_BUFFER_BUILDER_THREADS_MIN_DEFAULT_MAX.defaultValue;
}
public static class Debugging {
public static class Debugging
{
@ConfigAnnotations.FileComment
public static String _rendererType = IDebugging.RENDERER_TYPE_DESC;
@ConfigAnnotations.Entry
public static RendererType rendererType = IDebugging.RENDERER_TYPE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _debugMode = IDebugging.DEBUG_MODE_DESC;
@ConfigAnnotations.Entry
public static DebugMode debugMode = IDebugging.DEBUG_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _enableDebugKeybindings = IDebugging.DEBUG_KEYBINDINGS_ENABLED_DESC;
@ConfigAnnotations.Entry
public static boolean enableDebugKeybindings = IDebugging.DEBUG_KEYBINDINGS_ENABLED_DEFAULT;
@ConfigAnnotations.ScreenEntry
public static DebugSwitch debugSwitch;
public static class DebugSwitch {
/* The logging switches available:
* WorldGenEvent
* WorldGenPerformance
* WorldGenLoadEvent
* LodBuilderEvent
* RendererBufferEvent
* RendererGLEvent
* FileReadWriteEvent
* FileSubDimEvent
* NetworkEvent //NOT IMPL YET
*/
@ConfigAnnotations.FileComment
public static String _logWorldGenEvent = IDebugSwitch.LOG_WORLDGEN_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenEvent = IDebugSwitch.LOG_WORLDGEN_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logWorldGenPerformance = IDebugSwitch.LOG_WORLDGEN_PERFORMANCE_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenPerformance = IDebugSwitch.LOG_WORLDGEN_PERFORMANCE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logWorldGenLoadEvent = IDebugSwitch.LOG_WORLDGEN_LOAD_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenLoadEvent = IDebugSwitch.LOG_WORLDGEN_LOAD_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logLodBuilderEvent = IDebugSwitch.LOG_LODBUILDER_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logLodBuilderEvent = IDebugSwitch.LOG_LODBUILDER_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logRendererBufferEvent = IDebugSwitch.LOG_RENDERER_BUFFER_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logRendererBufferEvent = IDebugSwitch.LOG_RENDERER_BUFFER_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logRendererGLEvent = IDebugSwitch.LOG_RENDERER_GL_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logRendererGLEvent = IDebugSwitch.LOG_RENDERER_GL_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logFileReadWriteEvent = IDebugSwitch.LOG_FILE_READWRITE_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logFileReadWriteEvent = IDebugSwitch.LOG_FILE_READWRITE_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logFileSubDimEvent = IDebugSwitch.LOG_FILE_SUB_DIM_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logFileSubDimEvent = IDebugSwitch.LOG_FILE_SUB_DIM_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logNetworkEvent = IDebugSwitch.LOG_NETWORK_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logNetworkEvent = IDebugSwitch.LOG_NETWORK_EVENT_DEFAULT;
}
}
@ConfigAnnotations.ScreenEntry
public static DebugSwitch debugSwitch;
public static class DebugSwitch {
/* The logging switches available:
* WorldGenEvent
* WorldGenPerformance
* WorldGenLoadEvent
* LodBuilderEvent
* RendererBufferEvent
* RendererGLEvent
* FileReadWriteEvent
* FileSubDimEvent
* NetworkEvent //NOT IMPL YET
*/
@ConfigAnnotations.FileComment
public static String _logWorldGenEvent = IDebugSwitch.LOG_WORLDGEN_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenEvent = IDebugSwitch.LOG_WORLDGEN_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logWorldGenPerformance = IDebugSwitch.LOG_WORLDGEN_PERFORMANCE_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenPerformance = IDebugSwitch.LOG_WORLDGEN_PERFORMANCE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logWorldGenLoadEvent = IDebugSwitch.LOG_WORLDGEN_LOAD_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenLoadEvent = IDebugSwitch.LOG_WORLDGEN_LOAD_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logLodBuilderEvent = IDebugSwitch.LOG_LODBUILDER_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logLodBuilderEvent = IDebugSwitch.LOG_LODBUILDER_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logRendererBufferEvent = IDebugSwitch.LOG_RENDERER_BUFFER_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logRendererBufferEvent = IDebugSwitch.LOG_RENDERER_BUFFER_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logRendererGLEvent = IDebugSwitch.LOG_RENDERER_GL_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logRendererGLEvent = IDebugSwitch.LOG_RENDERER_GL_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logFileReadWriteEvent = IDebugSwitch.LOG_FILE_READWRITE_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logFileReadWriteEvent = IDebugSwitch.LOG_FILE_READWRITE_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logFileSubDimEvent = IDebugSwitch.LOG_FILE_SUB_DIM_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logFileSubDimEvent = IDebugSwitch.LOG_FILE_SUB_DIM_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logNetworkEvent = IDebugSwitch.LOG_NETWORK_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logNetworkEvent = IDebugSwitch.LOG_NETWORK_EVENT_DEFAULT;
}
public static class Buffers {
public static class Buffers
{
@ConfigAnnotations.FileComment
public static String _gpuUploadMethod = IBuffers.GPU_UPLOAD_METHOD_DESC;
@ConfigAnnotations.Entry
public static GpuUploadMethod gpuUploadMethod = IBuffers.GPU_UPLOAD_METHOD_DEFAULT;
@ConfigAnnotations.FileComment
public static String _gpuUploadPerMegabyteInMilliseconds = IBuffers.GPU_UPLOAD_PER_MEGABYTE_IN_MILLISECONDS_DESC;
@ConfigAnnotations.Entry(minValue = 0, maxValue = 5000)
@ConfigAnnotations.Entry(minValue = 0, maxValue = 50)
public static int gpuUploadPerMegabyteInMilliseconds = IBuffers.GPU_UPLOAD_PER_MEGABYTE_IN_MILLISECONDS_DEFAULT.defaultValue;
@ConfigAnnotations.FileComment
public static String _rebuildTimes = IBuffers.REBUILD_TIMES_DESC;
@ConfigAnnotations.Entry
@@ -15,7 +15,7 @@ public class LodCommonMain {
public static LodForgeMethodCaller forgeMethodCaller;
public static NetworkInterface networkInterface;
public static void startup(LodForgeMethodCaller caller, boolean serverSided) {
public static void startup(LodForgeMethodCaller caller, boolean serverSided, NetworkInterface networkInterface) {
LodCommonMain.serverSided = serverSided;
if (caller != null) {
LodCommonMain.forge = true;
@@ -23,13 +23,17 @@ public class LodCommonMain {
}
DependencySetup.createInitialBindings();
LodCommonMain.networkInterface = networkInterface;
if (!serverSided) {
networkInterface.register_Client();
} else {
networkInterface.register_Server();
}
}
public static void initConfig() {
ConfigGui.init(Config.class);
}
public static void registerNetworking(NetworkInterface networkInterface) {
LodCommonMain.networkInterface = networkInterface;
}
}
@@ -2,7 +2,6 @@ package com.seibel.lod.common.forge;
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
@@ -17,5 +16,4 @@ import java.util.Random;
*/
public interface LodForgeMethodCaller {
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random);
int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y);
}
@@ -0,0 +1,30 @@
package com.seibel.lod.common.networking;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
/**
* This is packet handler for our mod
* It basically handles the packets sent from the server & client
*
* @author Ran
*/
public class NetworkHandler {
// If you need the response sender then tell me
// I'll add extra code to get the response sender
public static void receivePacketClient(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf) {
// TODO: Server sided stuff here
// You can make client execute something by using client.execute(Runnable)
// In the fabric docs it says that client.execute is ran on the render thread?
}
// If you need the response sender then tell me
// I'll add extra code to get the response sender
public static void receivePacketServer(MinecraftServer server, ServerPlayer client, ServerGamePacketListenerImpl handler, FriendlyByteBuf buf) {
// TODO: Server sided stuff here
}
}
@@ -1,12 +1,9 @@
package com.seibel.lod.common.networking;
import net.minecraft.network.FriendlyByteBuf;
/**
* @author Ran
*/
public interface NetworkInterface {
void send(FriendlyByteBuf packetByteBuf);
FriendlyByteBuf receive();
void register_Client();
void register_Server();
}
@@ -1,20 +1,100 @@
package com.seibel.lod.common.networking;
import com.seibel.lod.core.ModInfo;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import java.util.Objects;
/**
* This class holds most of the networking code for the mod.
* @author Ran
*/
public class Networking {
// public void example(int packetId) {
// FriendlyByteBuf packetByteBuf = Networking.createNew();
// packetByteBuf.writeInt(packetId);
// LodCommonMain.networkInterface.send(packetByteBuf);
// }
public static final ResourceLocation resourceLocation_meow = new ResourceLocation("lod", "meow");
public static FriendlyByteBuf createNew() {
return new FriendlyByteBuf(Unpooled.buffer());
// TODO: Probably replace the Unpooled.buffer()
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
buf.writeInt(ModInfo.PROTOCOL_VERSION);
return buf;
}
/*
* All code below is from the fabric api and might have been modified to work with Distant Horizons
* Which is licensed under the Apache License 2.0
*/
/**
* Sends a packet to a player.
*
* @param player the player to send the packet to
* @param buf the payload of the packet.
*/
public static void send(ServerPlayer player, FriendlyByteBuf buf) {
Objects.requireNonNull(player, "Server player entity cannot be null");
Objects.requireNonNull(resourceLocation_meow, "Channel name cannot be null");
Objects.requireNonNull(buf, "Packet byte buf cannot be null");
player.connection.send(createS2CPacket(resourceLocation_meow, buf));
}
/**
* Sends a packet to the connected server.
*
* @param buf the payload of the packet
* @throws IllegalStateException if the client is not connected to a server
*/
public static void send(FriendlyByteBuf buf) throws IllegalStateException {
// You cant send without a client player, so this is fine
if (Minecraft.getInstance().getConnection() != null) {
Minecraft.getInstance().getConnection().send(createC2SPacket(resourceLocation_meow, buf));
return;
}
throw new IllegalStateException("Cannot send packets when not in game!");
}
/**
* Creates a packet which may be sent to the connected client.
*
* @param channelName the channel name
* @param buf the packet byte buf which represents the payload of the packet
* @return a new packet
*/
public static Packet<?> createS2CPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
Objects.requireNonNull(channelName, "Channel cannot be null");
Objects.requireNonNull(buf, "Buf cannot be null");
return createPlayS2CPacket(channelName, buf);
}
public static Packet<?> createPlayS2CPacket(ResourceLocation channel, FriendlyByteBuf buf) {
return new ClientboundCustomPayloadPacket(channel, buf);
}
/**
* Creates a packet which may be sent to a the connected server.
*
* @param channelName the channel name
* @param buf the packet byte buf which represents the payload of the packet
* @return a new packet
*/
public static Packet<?> createC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
Objects.requireNonNull(channelName, "Channel name cannot be null");
Objects.requireNonNull(buf, "Buf cannot be null");
return createPlayC2SPacket(channelName, buf);
}
public static Packet<?> createPlayC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
return new ServerboundCustomPayloadPacket(channelName, buf);
}
}
@@ -1,15 +1,15 @@
package com.seibel.lod.common.wrappers;
import com.seibel.lod.common.LodCommonMain;
import com.seibel.lod.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.lod.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.lod.core.handlers.IReflectionHandler;
import com.seibel.lod.core.handlers.ReflectionHandler;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
/**
* Binds all necessary dependencies, so we
@@ -22,13 +22,16 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
* @version 12-1-2021
*/
public class DependencySetup {
public static void createInitialBindings() {
public static void createInitialBindings()
{
SingletonHandler.bind(IVersionConstants.class, VersionConstants.INSTANCE);
if (!LodCommonMain.serverSided) {
if (!LodCommonMain.serverSided)
{
SingletonHandler.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
SingletonHandler.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
SingletonHandler.bind(IReflectionHandler.class, ReflectionHandler.createSingleton(MinecraftClientWrapper.INSTANCE.getOptions().getClass().getDeclaredFields(), MinecraftClientWrapper.INSTANCE.getOptions()));
}
SingletonHandler.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
DependencySetupDoneCheck.isDone = true;
}
@@ -2,7 +2,9 @@ package com.seibel.lod.common.wrappers;
import java.util.function.Supplier;
public class DependencySetupDoneCheck {
public class DependencySetupDoneCheck
{
public static boolean isDone = false;
public static Supplier<Boolean> getIsCurrentThreadDistantGeneratorThread = (() -> {return false;});
}
@@ -22,6 +22,7 @@ package com.seibel.lod.common.wrappers;
import java.nio.FloatBuffer;
import com.mojang.math.Matrix4f;
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.objects.math.Mat4f;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
@@ -52,20 +53,21 @@ public class McObjectConverter
static final Direction[] directions;
static final LodDirection[] lodDirections;
static {
LodDirection[] lodDirs = LodDirection.values();
directions = new Direction[lodDirs.length];
lodDirections = new LodDirection[lodDirs.length];
for (LodDirection lodDir : lodDirs) {
Direction dir = Direction.byName(lodDir.name());
directions[lodDir.ordinal()] = dir;
lodDirections[dir.ordinal()] = lodDir;
}
LodDirection[] lodDirs = LodDirection.values();
directions = new Direction[lodDirs.length];
lodDirections = new LodDirection[lodDirs.length];
for (LodDirection lodDir : lodDirs) {
Direction dir = Direction.byName(lodDir.name());
directions[lodDir.ordinal()] = dir;
lodDirections[dir.ordinal()] = lodDir;
}
}
public static BlockPos Convert(AbstractBlockPosWrapper wrappedPos) {
return new BlockPos(wrappedPos.getX(),wrappedPos.getY(), wrappedPos.getZ());
return new BlockPos(wrappedPos.getX(),wrappedPos.getY(), wrappedPos.getZ());
}
public static Direction Convert(LodDirection lodDirection)
{
return directions[lodDirection.ordinal()];
@@ -1,3 +1,4 @@
package com.seibel.lod.common.wrappers;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
@@ -5,26 +6,30 @@ import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
/**
* @author James Seibel
* @version 3-3-2022
* @version 12-11-2021
*/
public class VersionConstants implements IVersionConstants {
public static final VersionConstants INSTANCE = new VersionConstants();
public class VersionConstants implements IVersionConstants
{
public static final VersionConstants INSTANCE = new VersionConstants();
private VersionConstants()
{
}
@Override
public int getMinimumWorldHeight()
{
return 0;
}
private VersionConstants() {
}
@Override
public int getMinimumWorldHeight() {
return 0;
}
@Override
public int getWorldGenerationCountPerThread() {
return 1;
}
@Override
public int getWorldGenerationCountPerThread()
{
return 1;
}
@Override
public boolean isVanillaRenderedChunkSquare()
@@ -36,48 +36,59 @@ import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment
* @author James Seibel
* @version 11-20-2021
*/
public class WrapperFactory implements IWrapperFactory {
public static final WrapperFactory INSTANCE = new WrapperFactory();
@Override
public AbstractBlockPosWrapper createBlockPos() {
return new BlockPosWrapper();
}
@Override
public AbstractBlockPosWrapper createBlockPos(int x, int y, int z) {
return new BlockPosWrapper(x, y, z);
}
@Override
public AbstractChunkPosWrapper createChunkPos() {
return new ChunkPosWrapper();
}
@Override
public AbstractChunkPosWrapper createChunkPos(long xAndZPositionCombined) {
return new ChunkPosWrapper(xAndZPositionCombined);
}
@Override
public AbstractChunkPosWrapper createChunkPos(int x, int z) {
return new ChunkPosWrapper(x, z);
}
@Override
public AbstractChunkPosWrapper createChunkPos(AbstractChunkPosWrapper newChunkPos) {
return new ChunkPosWrapper(newChunkPos);
}
@Override
public AbstractChunkPosWrapper createChunkPos(AbstractBlockPosWrapper blockPos) {
return new ChunkPosWrapper(blockPos);
}
@Override
public AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(LodBuilder newLodBuilder,
LodDimension newLodDimension, IWorldWrapper worldWrapper) {
public class WrapperFactory implements IWrapperFactory
{
public static final WrapperFactory INSTANCE = new WrapperFactory();
@Override
public AbstractBlockPosWrapper createBlockPos()
{
return new BlockPosWrapper();
}
@Override
public AbstractBlockPosWrapper createBlockPos(int x, int y, int z)
{
return new BlockPosWrapper(x, y, z);
}
@Override
public AbstractChunkPosWrapper createChunkPos()
{
return new ChunkPosWrapper();
}
@Override
public AbstractChunkPosWrapper createChunkPos(long xAndZPositionCombined)
{
return new ChunkPosWrapper(xAndZPositionCombined);
}
@Override
public AbstractChunkPosWrapper createChunkPos(int x, int z)
{
return new ChunkPosWrapper(x, z);
}
@Override
public AbstractChunkPosWrapper createChunkPos(AbstractChunkPosWrapper newChunkPos)
{
return new ChunkPosWrapper(newChunkPos);
}
@Override
public AbstractChunkPosWrapper createChunkPos(AbstractBlockPosWrapper blockPos)
{
return new ChunkPosWrapper(blockPos);
}
public AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(LodBuilder newLodBuilder,
LodDimension newLodDimension, IWorldWrapper worldWrapper)
{
return new BatchGenerationEnvironment(worldWrapper, newLodBuilder, newLodDimension);
}
}
@@ -1,26 +1,27 @@
package com.seibel.lod.common.wrappers.block;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.state.BlockState;
import java.util.concurrent.ConcurrentHashMap;
public class BlockDetailMap
{
private static ConcurrentHashMap<BlockState, BlockDetailWrapper> map = new ConcurrentHashMap<BlockState, BlockDetailWrapper>();
private BlockDetailMap() {}
public static BlockDetailWrapper getOrMakeBlockDetailCache(BlockState bs, BlockPos pos, LevelReader getter) {
BlockDetailWrapper cache = map.get(bs);
if (cache != null) return cache;
if (bs.getFluidState().isEmpty()) {
cache = BlockDetailWrapper.make(bs, pos, getter);
} else {
cache = BlockDetailWrapper.make(bs.getFluidState().createLegacyBlock(), pos, getter);
}
BlockDetailWrapper cacheCAS = map.putIfAbsent(bs, cache);
return cacheCAS==null ? cache : cacheCAS;
}
private static ConcurrentHashMap<BlockState, BlockDetailWrapper> map = new ConcurrentHashMap<BlockState, BlockDetailWrapper>();
private BlockDetailMap() {}
public static BlockDetailWrapper getOrMakeBlockDetailCache(BlockState bs, BlockPos pos, LevelReader getter) {
BlockDetailWrapper cache = map.get(bs);
if (cache != null) return cache;
if (bs.getFluidState().isEmpty()) {
cache = BlockDetailWrapper.make(bs, pos, getter);
} else {
cache = BlockDetailWrapper.make(bs.getFluidState().createLegacyBlock(), pos, getter);
}
BlockDetailWrapper cacheCAS = map.putIfAbsent(bs, cache);
return cacheCAS==null ? cache : cacheCAS;
}
}
@@ -52,275 +52,275 @@ import org.jetbrains.annotations.Nullable;
public class BlockDetailWrapper extends IBlockDetailWrapper
{
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
public static final int FLOWER_COLOR_SCALE = 5;
public static final int FLOWER_COLOR_SCALE = 5;
public static final Random random = new Random(0);
public static final Random random = new Random(0);
enum ColorMode {
Default,
Flower,
Leaves;
static ColorMode getColorMode(Block b) {
if (b instanceof LeavesBlock) return Leaves;
if (b instanceof FlowerBlock) return Flower;
return Default;
}
}
//TODO: Perhaps make this not just use the first frame?
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) {
int count = 0;
double alpha = 0;
double red = 0;
double green = 0;
double blue = 0;
int tempColor;
{
// textures normally use u and v instead of x and y
for (int u = 0; u < texture.getWidth(); u++)
{
for (int v = 0; v < texture.getHeight(); v++)
{
//note: Minecraft color format is: 0xAA BB GG RR
//________ DH mod color format is: 0xAA RR GG BB
//OpenGL RGBA format native order: 0xRR GG BB AA
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
double r = ((tempColor & 0x000000FF) )/255.;
double g = ((tempColor & 0x0000FF00) >>> 8)/255.;
double b = ((tempColor & 0x00FF0000) >>> 16)/255.;
double a = ((tempColor & 0xFF000000) >>> 24)/255.;
int scale = 1;
if (colorMode == ColorMode.Leaves) {
r *= a;
g *= a;
b *= a;
a = 1.;
} else if (a==0.) {
continue;
} else if (colorMode == ColorMode.Flower && (g+0.1<b || g+0.1<r)) {
scale = FLOWER_COLOR_SCALE;
}
count += scale;
alpha += a*a*scale;
red += r*r*scale;
green += g*g*scale;
blue += b*b*scale;
}
}
}
if (count == 0)
// this block is entirely transparent
tempColor = ColorUtil.rgbToInt(255,255,0,255);
else
{
// determine the average color
tempColor = ColorUtil.rgbToInt(
(int) (Math.sqrt(alpha/count)*255.),
(int) (Math.sqrt(red / count)*255.),
(int) (Math.sqrt(green / count)*255.),
(int) (Math.sqrt(blue / count)*255.));
}
// TODO: Remove this when transparency is added!
double colorAlpha = ColorUtil.getAlpha(tempColor)/255.;
tempColor = ColorUtil.rgbToInt(
ColorUtil.getAlpha(tempColor),
(int)(ColorUtil.getRed(tempColor) * colorAlpha),
(int)(ColorUtil.getGreen(tempColor) * colorAlpha),
(int)(ColorUtil.getBlue(tempColor) * colorAlpha)
);
return tempColor;
}
enum ColorMode {
Default,
Flower,
Leaves;
static ColorMode getColorMode(Block b) {
if (b instanceof LeavesBlock) return Leaves;
if (b instanceof FlowerBlock) return Flower;
return Default;
}
}
//TODO: Perhaps make this not just use the first frame?
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) {
int count = 0;
double alpha = 0;
double red = 0;
double green = 0;
double blue = 0;
int tempColor;
{
// textures normally use u and v instead of x and y
for (int u = 0; u < texture.getWidth(); u++)
{
for (int v = 0; v < texture.getHeight(); v++)
{
//note: Minecraft color format is: 0xAA BB GG RR
//________ DH mod color format is: 0xAA RR GG BB
//OpenGL RGBA format native order: 0xRR GG BB AA
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
double r = ((tempColor & 0x000000FF) )/255.;
double g = ((tempColor & 0x0000FF00) >>> 8)/255.;
double b = ((tempColor & 0x00FF0000) >>> 16)/255.;
double a = ((tempColor & 0xFF000000) >>> 24)/255.;
int scale = 1;
if (colorMode == ColorMode.Leaves) {
r *= a;
g *= a;
b *= a;
a = 1.;
} else if (a==0.) {
continue;
} else if (colorMode == ColorMode.Flower && (g+0.1<b || g+0.1<r)) {
scale = FLOWER_COLOR_SCALE;
}
count += scale;
alpha += a*a*scale;
red += r*r*scale;
green += g*g*scale;
blue += b*b*scale;
}
}
}
if (count == 0)
// this block is entirely transparent
tempColor = ColorUtil.rgbToInt(255,255,0,255);
else
{
// determine the average color
tempColor = ColorUtil.rgbToInt(
(int) (Math.sqrt(alpha/count)*255.),
(int) (Math.sqrt(red / count)*255.),
(int) (Math.sqrt(green / count)*255.),
(int) (Math.sqrt(blue / count)*255.));
}
// TODO: Remove this when transparency is added!
double colorAlpha = ColorUtil.getAlpha(tempColor)/255.;
tempColor = ColorUtil.rgbToInt(
ColorUtil.getAlpha(tempColor),
(int)(ColorUtil.getRed(tempColor) * colorAlpha),
(int)(ColorUtil.getGreen(tempColor) * colorAlpha),
(int)(ColorUtil.getBlue(tempColor) * colorAlpha)
);
return tempColor;
}
private static final Block[] BLOCK_TO_AVOID = {Blocks.AIR, Blocks.CAVE_AIR, Blocks.BARRIER};
private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
private static boolean isBlockToBeAvoid(Block b) {
for (Block bta : BLOCK_TO_AVOID)
if (bta==b) return true;
return false;
}
final BlockState state;
final BlockPos samplePos;
final LevelReader sampleGetter;
boolean isShapeResolved = false;
boolean[] dontOccludeFaces = null;
boolean noCollision = false;
boolean noFullFace = false;
boolean isColorResolved = false;
int baseColor = 0; //TODO: Impl per-face color
boolean needShade = true;
boolean needPostTinting = false;
int tintIndex = 0;
public static BlockDetailWrapper NULL_BLOCK_DETAIL = new BlockDetailWrapper();
public BlockDetailWrapper(BlockState state, BlockPos pos, LevelReader getter) {
this.state = state;
this.samplePos = pos;
this.sampleGetter = getter;
}
private BlockDetailWrapper() {
this.state = null;
this.samplePos = null;
this.sampleGetter = null;
}
private static final Block[] BLOCK_TO_AVOID = {Blocks.AIR, Blocks.CAVE_AIR, Blocks.BARRIER};
private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
private static boolean isBlockToBeAvoid(Block b) {
for (Block bta : BLOCK_TO_AVOID)
if (bta==b) return true;
return false;
}
final BlockState state;
final BlockPos samplePos;
final LevelReader sampleGetter;
boolean isShapeResolved = false;
boolean[] dontOccludeFaces = null;
boolean noCollision = false;
boolean noFullFace = false;
boolean isColorResolved = false;
int baseColor = 0; //TODO: Impl per-face color
boolean needShade = true;
boolean needPostTinting = false;
int tintIndex = 0;
public static BlockDetailWrapper NULL_BLOCK_DETAIL = new BlockDetailWrapper();
public BlockDetailWrapper(BlockState state, BlockPos pos, LevelReader getter) {
this.state = state;
this.samplePos = pos;
this.sampleGetter = getter;
}
private BlockDetailWrapper() {
this.state = null;
this.samplePos = null;
this.sampleGetter = null;
}
static BlockDetailWrapper make(BlockState bs, BlockPos pos, LevelReader getter) {
if(!bs.getFluidState().isEmpty()) { // Is a fluidBlock
if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL;
if (bs.isAir()) return NULL_BLOCK_DETAIL;
return new BlockDetailWrapper(bs, pos, getter);
} else {
if (bs.getRenderShape() != RenderShape.MODEL) return NULL_BLOCK_DETAIL;
if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL;
return new BlockDetailWrapper(bs, pos, getter);
}
}
private void resolveShapes() {
if (isShapeResolved) return;
if (state.getFluidState().isEmpty()) {
noCollision = state.getCollisionShape(sampleGetter, samplePos).isEmpty();
dontOccludeFaces = new boolean[6];
if (state.canOcclude()) {
static BlockDetailWrapper make(BlockState bs, BlockPos pos, LevelReader getter) {
if(!bs.getFluidState().isEmpty()) { // Is a fluidBlock
if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL;
if (bs.isAir()) return NULL_BLOCK_DETAIL;
return new BlockDetailWrapper(bs, pos, getter);
} else {
if (bs.getRenderShape() != RenderShape.MODEL) return NULL_BLOCK_DETAIL;
if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL;
return new BlockDetailWrapper(bs, pos, getter);
}
}
private void resolveShapes() {
if (isShapeResolved) return;
if (state.getFluidState().isEmpty()) {
noCollision = state.getCollisionShape(sampleGetter, samplePos).isEmpty();
dontOccludeFaces = new boolean[6];
if (state.canOcclude()) {
/* FIXME: Figure out how or if needed to impl per-face culling?
for (Direction dir : Direction.values()) {
dontOccludeFaces[McObjectConverter.Convert(dir).ordinal()]
= state.getFaceOcclusionShape(sampleGetter, samplePos, dir).isEmpty();
}*/
} else {
Arrays.fill(dontOccludeFaces, true);
}
VoxelShape voxelShape = state.getShape(sampleGetter, samplePos);
} else {
Arrays.fill(dontOccludeFaces, true);
}
VoxelShape voxelShape = state.getShape(sampleGetter, samplePos);
if (voxelShape.isEmpty()) {
noFullFace = true;
noFullFace = true;
} else {
AABB bbox = voxelShape.bounds();
double xWidth = (bbox.maxX - bbox.minX);
double yWidth = (bbox.maxY - bbox.minY);
double zWidth = (bbox.maxZ - bbox.minZ);
noFullFace = xWidth < 1 && zWidth < 1 && yWidth < 1;
AABB bbox = voxelShape.bounds();
double xWidth = (bbox.maxX - bbox.minX);
double yWidth = (bbox.maxY - bbox.minY);
double zWidth = (bbox.maxZ - bbox.minZ);
noFullFace = xWidth < 1 && zWidth < 1 && yWidth < 1;
}
} else { // Liquid Block
dontOccludeFaces = new boolean[6];
}
isShapeResolved = true;
}
} else { // Liquid Block
dontOccludeFaces = new boolean[6];
}
isShapeResolved = true;
}
private void resolveColors() {
if (isColorResolved) return;
if (state.getFluidState().isEmpty()) {
List<BakedQuad> quads = null;
for (Direction direction : DIRECTION_ORDER)
{
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(state).getQuads(state, direction, random);
if (!quads.isEmpty() &&
!(state.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
break;
};
if (quads == null || quads.isEmpty()) {
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(state).getQuads(state, null, random);
}
private void resolveColors() {
if (isColorResolved) return;
if (state.getFluidState().isEmpty()) {
List<BakedQuad> quads = null;
for (Direction direction : DIRECTION_ORDER)
{
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(state).getQuads(state, direction, random);
if (!quads.isEmpty() &&
!(state.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
break;
};
if (quads == null || quads.isEmpty()) {
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(state).getQuads(state, null, random);
}
if (quads != null && !quads.isEmpty()) {
needPostTinting = quads.get(0).isTinted();
needShade = quads.get(0).isShade();
tintIndex = quads.get(0).getTintIndex();
baseColor = calculateColorFromTexture(quads.get(0).getSprite(),
ColorMode.getColorMode(state.getBlock()));
} else { // Backup method.
needPostTinting = false;
needShade = false;
tintIndex = 0;
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
ColorMode.getColorMode(state.getBlock()));
}
} else { // Liquid Block
needPostTinting = true;
needShade = false;
tintIndex = 0;
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
ColorMode.getColorMode(state.getBlock()));
}
isColorResolved = true;
}
private BlockAndTintGetter wrapColorResolver(LevelReader level) {
int blendDistance = CONFIG.client().graphics().quality().getLodBiomeBlending();
if (blendDistance == 0) {
return new TintGetterOverrideFast(level);
} else {
return new TintGetterOverrideSmooth(level, blendDistance);
}
}
@Override
public int getAndResolveFaceColor(LodDirection dir, IChunkWrapper chunk, AbstractBlockPosWrapper blockPos)
{
// FIXME: impl per-face colors
resolveColors();
if (!needPostTinting) return baseColor;
int tintColor = Minecraft.getInstance().getBlockColors()
.getColor(state, wrapColorResolver(((ChunkWrapper)chunk).getColorResolver()),
McObjectConverter.Convert(blockPos), tintIndex);
if (tintColor == -1) return baseColor;
return ColorUtil.multiplyARGBwithRGB(baseColor, tintColor);
}
if (quads != null && !quads.isEmpty()) {
needPostTinting = quads.get(0).isTinted();
needShade = quads.get(0).isShade();
tintIndex = quads.get(0).getTintIndex();
baseColor = calculateColorFromTexture(quads.get(0).getSprite(),
ColorMode.getColorMode(state.getBlock()));
} else { // Backup method.
needPostTinting = false;
needShade = false;
tintIndex = 0;
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
ColorMode.getColorMode(state.getBlock()));
}
} else { // Liquid Block
@Override
public boolean hasFaceCullingFor(LodDirection dir)
{
resolveShapes();
return !dontOccludeFaces[dir.ordinal()];
}
needPostTinting = true;
needShade = false;
tintIndex = 0;
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
ColorMode.getColorMode(state.getBlock()));
@Override
public boolean hasNoCollision()
{
resolveShapes();
return noCollision;
}
}
isColorResolved = true;
}
@Override
public boolean noFaceIsFullFace()
{
resolveShapes();
return noFullFace;
}
private BlockAndTintGetter wrapColorResolver(LevelReader level) {
int blendDistance = CONFIG.client().graphics().quality().getLodBiomeBlending();
if (blendDistance == 0) {
return new TintGetterOverrideFast(level);
} else {
return new TintGetterOverrideSmooth(level, blendDistance);
}
}
@Override
public int getAndResolveFaceColor(LodDirection dir, IChunkWrapper chunk, AbstractBlockPosWrapper blockPos)
{
// FIXME: impl per-face colors
resolveColors();
if (!needPostTinting) return baseColor;
int tintColor = Minecraft.getInstance().getBlockColors()
.getColor(state, wrapColorResolver(((ChunkWrapper)chunk).getColorResolver()),
McObjectConverter.Convert(blockPos), tintIndex);
if (tintColor == -1) return baseColor;
return ColorUtil.multiplyARGBwithRGB(baseColor, tintColor);
}
@Override
public boolean hasFaceCullingFor(LodDirection dir)
{
resolveShapes();
return !dontOccludeFaces[dir.ordinal()];
}
@Override
public boolean hasNoCollision()
{
resolveShapes();
return noCollision;
}
@Override
public boolean noFaceIsFullFace()
{
resolveShapes();
return noFullFace;
}
@Override
public String serialize()
{
// FIXME: Impl this for the blockState Storage stuff
return null;
}
@Override
protected boolean isSame(IBlockDetailWrapper iBlockDetail)
{
return ((BlockDetailWrapper)iBlockDetail).state.getBlock().equals(state.getBlock());
}
@Override
public String serialize()
{
// FIXME: Impl this for the blockState Storage stuff
return null;
}
@Override
protected boolean isSame(IBlockDetailWrapper iBlockDetail)
{
return ((BlockDetailWrapper)iBlockDetail).state.getBlock().equals(state.getBlock());
}
}
@@ -14,7 +14,7 @@ import net.minecraft.core.BlockPos;
*/
public class BlockPosWrapper extends AbstractBlockPosWrapper
{
private BlockPos.MutableBlockPos blockPos;
private final BlockPos.MutableBlockPos blockPos;
public BlockPosWrapper()
@@ -27,25 +27,23 @@ import java.util.stream.Stream;
public class TintGetterOverrideFast implements BlockAndTintGetter {
LevelReader parent;
private final Object2ObjectArrayMap<ColorResolver, ConcurrentHashMap<Biome, Integer>> tintCaches;
public TintGetterOverrideFast(LevelReader parent) {
this.parent = parent;
this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> {
object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new ConcurrentHashMap<Biome, Integer>());
object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new ConcurrentHashMap<Biome, Integer>());
object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new ConcurrentHashMap<Biome, Integer>());
});
}
private Biome _getBiome(BlockPos pos) {
return parent.getBiome(pos);
#if MC_VERSION_1_18_2
return parent.getBiome(pos).value();
#elif MC_VERSION_1_18_1
return parent.getBiome(pos);
#endif
}
@Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
Biome b = _getBiome(blockPos);
return tintCaches.get(colorResolver).computeIfAbsent(b, (key) -> colorResolver.getColor(b, blockPos.getX(), blockPos.getZ()));
return colorResolver.getColor(b, blockPos.getX(), blockPos.getZ());
}
@Override
@@ -26,21 +26,19 @@ import java.util.stream.Stream;
public class TintGetterOverrideSmooth implements BlockAndTintGetter {
LevelReader parent;
private final Object2ObjectArrayMap<ColorResolver, BlockTintCache> tintCaches;
public int smoothingRange;
public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange) {
this.parent = parent;
this.smoothingRange = smoothingRange;
this.tintCaches = Util.make(new Object2ObjectArrayMap<>(3), object2ObjectArrayMap -> {
object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.GRASS_COLOR_RESOLVER)));
object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.FOLIAGE_COLOR_RESOLVER)));
object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.WATER_COLOR_RESOLVER)));
});
}
private Biome _getBiome(BlockPos pos) {
return parent.getBiome(pos);
#if MC_VERSION_1_18_2
return parent.getBiome(pos).value();
#elif MC_VERSION_1_18_1
return parent.getBiome(pos);
#endif
}
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
@@ -67,8 +65,7 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter {
@Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
BlockTintCache blockTintCache = this.tintCaches.get(colorResolver);
return blockTintCache.getColor(blockPos, null); //FIXME
return calculateBlockTint(blockPos, colorResolver);
}
@Override
@@ -18,7 +18,7 @@ import net.minecraft.world.level.ChunkPos;
*/
public class ChunkPosWrapper extends AbstractChunkPosWrapper
{
private net.minecraft.world.level.ChunkPos chunkPos;
private final net.minecraft.world.level.ChunkPos chunkPos;
public ChunkPosWrapper()
{
@@ -45,9 +45,8 @@ public class ChunkPosWrapper extends AbstractChunkPosWrapper
this.chunkPos = new ChunkPos(chunkX, chunkZ);
}
public ChunkPosWrapper(long l)
{
this.chunkPos = new ChunkPos(l);
public ChunkPosWrapper(long l) {
this.chunkPos = new ChunkPos(l);
}
@@ -94,21 +93,21 @@ public class ChunkPosWrapper extends AbstractChunkPosWrapper
{
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.z, LodUtil.REGION_DETAIL_LEVEL);
}
@Override
public long getLong() {
return chunkPos.toLong();
}
public ChunkPos getChunkPos()
{
return chunkPos;
}
@Override
public long getLong() {
return chunkPos.toLong();
}
@Override
public boolean equals(Object o)
{
// If the object is compared with itself then return true
// If the object is compared with itself then return true
if (o == this) {
return true;
}
@@ -134,5 +133,4 @@ public class ChunkPosWrapper extends AbstractChunkPosWrapper
return new BlockPosWrapper(blockPos.getX(), blockPos.getY(), blockPos.getZ());
}
}
@@ -33,52 +33,57 @@ import net.minecraft.world.level.levelgen.Heightmap;
*/
public class ChunkWrapper implements IChunkWrapper
{
private final ChunkAccess chunk;
private final LevelReader lightSource;
public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource)
{
this.chunk = chunk;
this.lightSource = lightSource;
}
@Override
public int getHeight(){
return chunk.getHeight();
}
@Override
public int getMinBuildHeight()
{
return chunk.getMinBuildHeight();
}
@Override
public int getMaxBuildHeight()
{
return chunk.getMaxBuildHeight();
}
@Override
public int getHeightMapValue(int xRel, int zRel)
{
return chunk.getOrCreateHeightmapUnprimed(WrapperUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
}
@Override
public IBiomeWrapper getBiome(int x, int y, int z)
{
return BiomeWrapper.getBiomeWrapper(chunk.getBiomes().getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
}
@Override
public IBlockDetailWrapper getBlockDetail(int x, int y, int z) {
BlockPos pos = new BlockPos(x,y,z);
BlockState blockState = chunk.getBlockState(pos);
IBlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource);
return blockDetail == BlockDetailWrapper.NULL_BLOCK_DETAIL ? null : blockDetail;
}
private final ChunkAccess chunk;
private final LevelReader lightSource;
public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource)
{
this.chunk = chunk;
this.lightSource = lightSource;
}
@Override
public int getHeight(){
return chunk.getHeight();
}
@Override
public int getMinBuildHeight()
{
return chunk.getMinBuildHeight();
}
@Override
public int getMaxBuildHeight()
{
return chunk.getMaxBuildHeight();
}
@Override
public int getHeightMapValue(int xRel, int zRel)
{
return chunk.getOrCreateHeightmapUnprimed(WrapperUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
}
@Override
public IBiomeWrapper getBiome(int x, int y, int z)
{
#if MC_VERSION_1_18_2
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)).value());
#elif MC_VERSION_1_18_1
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
#endif
}
@Override
public IBlockDetailWrapper getBlockDetail(int x, int y, int z) {
BlockPos pos = new BlockPos(x,y,z);
BlockState blockState = chunk.getBlockState(pos);
IBlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource);
return blockDetail == BlockDetailWrapper.NULL_BLOCK_DETAIL ? null : blockDetail;
}
@Override
public IBlockDetailWrapper getBlockDetailAtFace(int x, int y, int z, LodDirection dir) {
@@ -92,113 +97,112 @@ public class ChunkWrapper implements IChunkWrapper
blockState = lightSource.getBlockState(pos);
}
if (blockState == null || blockState.isAir()) return null;
IBlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource);
IBlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource);
return blockDetail == BlockDetailWrapper.NULL_BLOCK_DETAIL ? null : blockDetail;
}
public ChunkAccess getChunk() {
return chunk;
}
@Override
public int getChunkPosX(){
return chunk.getPos().x;
}
@Override
public int getChunkPosZ(){
return chunk.getPos().z;
}
@Override
public int getRegionPosX(){
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, LodUtil.REGION_DETAIL_LEVEL);
}
@Override
public int getRegionPosZ(){
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().z, LodUtil.REGION_DETAIL_LEVEL);
}
@Override
public int getMaxY(int x, int z) {
return chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, Math.floorMod(x, 16), Math.floorMod(z, 16));
}
@Override
public int getMaxX(){
return chunk.getPos().getMaxBlockX();
}
@Override
public int getMaxZ(){
return chunk.getPos().getMaxBlockZ();
}
@Override
public int getMinX(){
return chunk.getPos().getMinBlockX();
}
@Override
public int getMinZ() {
return chunk.getPos().getMinBlockZ();
}
@Override
public long getLongChunkPos() {
return chunk.getPos().toLong();
}
@Override
public boolean isLightCorrect(){
return true;
// TODO
// if (chunk instanceof LevelChunk) {
// return ((LevelChunk) chunk).isClientLightReady();
// }
// return chunk.isLightCorrect();
}
public boolean isWaterLogged(int x, int y, int z)
{
BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
//This type of block is always in water
return (!(blockState.getBlock() instanceof LiquidBlockContainer) && (blockState.getBlock() instanceof SimpleWaterloggedBlock))
&& (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED));
}
@Override
public int getEmittedBrightness(int x, int y, int z)
{
return chunk.getLightEmission(new BlockPos(x,y,z));
}
@Override
public int getBlockLight(int x, int y, int z) {
if (lightSource == null) return -1;
return lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
}
@Override
public int getSkyLight(int x, int y, int z) {
if (lightSource == null) return -1;
return lightSource.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
}
@Override
public boolean doesNearbyChunksExist() {
if (lightSource instanceof LightedWorldGenRegion) return true;
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
if (dx==0 && dz==0) continue;
if (lightSource.getChunk(dx+getChunkPosX(), dz+getChunkPosZ(), ChunkStatus.BIOMES, false) == null) return false;
}
}
return true;
}
public LevelReader getColorResolver()
{
return lightSource;
}
public ChunkAccess getChunk() {
return chunk;
}
@Override
public int getChunkPosX(){
return chunk.getPos().x;
}
@Override
public int getChunkPosZ(){
return chunk.getPos().z;
}
@Override
public int getRegionPosX(){
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, LodUtil.REGION_DETAIL_LEVEL);
}
@Override
public int getRegionPosZ(){
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().z, LodUtil.REGION_DETAIL_LEVEL);
}
@Override
public int getMaxY(int x, int z) {
return chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, Math.floorMod(x, 16), Math.floorMod(z, 16));
}
@Override
public int getMaxX(){
return chunk.getPos().getMaxBlockX();
}
@Override
public int getMaxZ(){
return chunk.getPos().getMaxBlockZ();
}
@Override
public int getMinX(){
return chunk.getPos().getMinBlockX();
}
@Override
public int getMinZ() {
return chunk.getPos().getMinBlockZ();
}
@Override
public long getLongChunkPos() {
return chunk.getPos().toLong();
}
@Override
public boolean isLightCorrect(){
//return true;
if (chunk instanceof LevelChunk) {
return ((LevelChunk) chunk).isClientLightReady();
}
return chunk.isLightCorrect();
}
public boolean isWaterLogged(int x, int y, int z)
{
BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
//This type of block is always in water
return (!(blockState.getBlock() instanceof LiquidBlockContainer) && (blockState.getBlock() instanceof SimpleWaterloggedBlock))
&& (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED));
}
@Override
public int getEmittedBrightness(int x, int y, int z)
{
return chunk.getLightEmission(new BlockPos(x,y,z));
}
@Override
public int getBlockLight(int x, int y, int z) {
if (lightSource == null) return -1;
return lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
}
@Override
public int getSkyLight(int x, int y, int z) {
if (lightSource == null) return -1;
return lightSource.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
}
@Override
public boolean doesNearbyChunksExist() {
if (lightSource instanceof LightedWorldGenRegion) return true;
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
if (dx==0 && dz==0) continue;
if (lightSource.getChunk(dx+getChunkPosX(), dz+getChunkPosZ(), ChunkStatus.BIOMES, false) == null) return false;
}
}
return true;
}
public LevelReader getColorResolver()
{
return lightSource;
}
}
@@ -379,7 +379,7 @@ public abstract class ConfigGui
// Just put this here for the future
config.setComment("_Version", " DONT TOUCH THIS, IF YOU DO THEN CONFIG FILE WOULD BREAK");
config.set("_Versions", ModInfo.VERSION);
// Puts everything into its variable
for (EntryInfo info : entries) {
@@ -753,10 +753,10 @@ public abstract class ConfigGui
// Only for 1.17 and over
// Remove in 1.16 and below
@Override
public List<? extends NarratableEntry> narratables()
{
return children;
}
@Override
public List<? extends NarratableEntry> narratables()
{
return children;
}
}
}
@@ -15,47 +15,47 @@ import com.seibel.lod.common.Config;
public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
{
public static final LodConfigWrapperSingleton INSTANCE = new LodConfigWrapperSingleton();
private static final Client client = new Client();
@Override
public IClient client()
{
return client;
}
public static class Client implements IClient
{
public final IGraphics graphics;
public final IWorldGenerator worldGenerator;
public final IMultiplayer multiplayer;
public final IAdvanced advanced;
@Override
public IGraphics graphics()
{
return graphics;
}
@Override
public IWorldGenerator worldGenerator()
{
return worldGenerator;
}
@Override
public IMultiplayer multiplayer() {
return multiplayer;
}
@Override
public IAdvanced advanced()
{
return advanced;
}
@Override
public boolean getOptionsButton()
{
@@ -67,8 +67,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("optionsButton").value = newOptionsButton;
ConfigGui.editSingleOption.saveOption("optionsButton");
}
//================//
// Client Configs //
//================//
@@ -79,8 +79,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
multiplayer = new Multiplayer();
advanced = new Advanced();
}
//==================//
// Graphics Configs //
//==================//
@@ -89,36 +89,36 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
public final IQuality quality;
public final IFogQuality fogQuality;
public final IAdvancedGraphics advancedGraphics;
@Override
public IQuality quality()
{
return quality;
}
@Override
public IFogQuality fogQuality()
{
return fogQuality;
}
@Override
public IAdvancedGraphics advancedGraphics()
{
return advancedGraphics;
}
Graphics()
{
quality = new Quality();
fogQuality = new FogQuality();
advancedGraphics = new AdvancedGraphics();
}
public static class Quality implements IQuality
{
@Override
@@ -132,8 +132,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.quality.drawResolution").value = newHorizontalResolution;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.drawResolution");
}
@Override
public int getLodChunkRenderDistance()
{
@@ -145,8 +145,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.quality.lodChunkRenderDistance").value = newLodChunkRenderDistance;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.lodChunkRenderDistance");
}
@Override
public VerticalQuality getVerticalQuality()
{
@@ -158,8 +158,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.quality.verticalQuality").value = newVerticalQuality;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.verticalQuality");
}
@Override
public int getHorizontalScale()
{
@@ -171,8 +171,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.quality.horizontalScale").value = newHorizontalScale;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.horizontalScale");
}
@Override
public HorizontalQuality getHorizontalQuality()
{
@@ -184,7 +184,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.quality.horizontalQuality").value = newHorizontalQuality;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.horizontalQuality");
}
@Override
public DropoffQuality getDropoffQuality() {
return Config.Client.Graphics.Quality.dropoffQuality;
@@ -206,8 +206,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.saveOption("client.graphics.quality.lodBiomeBlending");
}
}
public static class FogQuality implements IFogQuality
{
public final IAdvancedFog advancedFog;
@@ -228,36 +228,36 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogDistance").value = newFogDistance;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogDistance");
}
@Override
public FogDrawMode getFogDrawMode()
{
return Config.Client.Graphics.FogQuality.fogDrawMode;
}
@Override
public void setFogDrawMode(FogDrawMode setFogDrawMode)
{
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogDrawMode").value = setFogDrawMode;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogDrawMode");
}
@Override
public FogColorMode getFogColorMode()
{
return Config.Client.Graphics.FogQuality.fogColorMode;
}
@Override
public void setFogColorMode(FogColorMode newFogColorMode)
{
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogColorMode").value = newFogColorMode;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogColorMode");
}
@Override
public boolean getDisableVanillaFog()
{
@@ -342,7 +342,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
public IHeightFog heightFog() {
return heightFog;
}
public static class HeightFog implements IHeightFog {
@Override
@@ -431,8 +431,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
}
}
public static class AdvancedGraphics implements IAdvancedGraphics
{
@Override
@@ -446,8 +446,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.disableDirectionalCulling").value = newDisableDirectionalCulling;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.disableDirectionalCulling");
}
@Override
public VanillaOverdraw getVanillaOverdraw()
{
@@ -482,7 +482,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.backsideCullingRange").value = newBacksideCullingRange;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.backsideCullingRange");
}*/
@Override
public boolean getUseExtendedNearClipPlane()
{
@@ -494,7 +494,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.useExtendedNearClipPlane").value = newUseExtendedNearClipPlane;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.useExtendedNearClipPlane");
}
@Override
public double getBrightnessMultiplier()
{
@@ -506,7 +506,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.brightnessMultiplier").value = newBrightnessMultiplier;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.brightnessMultiplier");
}
@Override
public double getSaturationMultiplier()
{
@@ -544,10 +544,10 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
}
}
}
//========================//
// WorldGenerator Configs //
//========================//
@@ -564,8 +564,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.worldGenerator.generationPriority").value = newGenerationPriority;
ConfigGui.editSingleOption.saveOption("client.worldGenerator.generationPriority");
}
@Override
public DistanceGenerationMode getDistanceGenerationMode()
{
@@ -590,8 +590,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.worldGenerator.allowUnstableFeatureGeneration").value = newAllowUnstableFeatureGeneration;
ConfigGui.editSingleOption.saveOption("client.worldGenerator.allowUnstableFeatureGeneration");
}*/
@Override
public BlocksToAvoid getBlocksToAvoid()
{
@@ -626,9 +626,9 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.saveOption("client.worldGenerator.lightGenerationMode");
}
}
//=====================//
// Multiplayer Configs //
//=====================//
@@ -645,13 +645,13 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.multiplayer.serverFolderNameMode").value = newServerFolderNameMode;
ConfigGui.editSingleOption.saveOption("client.multiplayer.serverFolderNameMode");
}
@Override
public double getMultiDimensionRequiredSimilarity()
{
return Config.Client.Multiplayer.multiDimensionRequiredSimilarity;
}
@Override
public void setMultiDimensionRequiredSimilarity(double newMultiDimensionMinimumSimilarityPercent)
{
@@ -659,9 +659,9 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.saveOption("client.multiplayer.multiDimensionMinimumSimilarityPercent");
}
}
//============================//
// AdvancedModOptions Configs //
//============================//
@@ -670,22 +670,22 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
public final IThreading threading;
public final IDebugging debugging;
public final IBuffers buffers;
@Override
public IThreading threading()
{
return threading;
}
@Override
public IDebugging debugging()
{
return debugging;
}
@Override
public IBuffers buffers()
{
@@ -699,7 +699,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
debugging = new Debugging();
buffers = new Buffers();
}
public static class Threading implements IThreading
{
@Override
@@ -713,8 +713,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.advanced.threading.numberOfWorldGenerationThreads").value = newNumberOfWorldGenerationThreads;
ConfigGui.editSingleOption.saveOption("client.advanced.threading.numberOfWorldGenerationThreads");
}
@Override
public int getNumberOfBufferBuilderThreads()
{
@@ -727,10 +727,10 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.saveOption("client.advanced.threading.numberOfBufferBuilderThreads");
}
}
//===============//
// Debug Options //
//===============//
@@ -758,7 +758,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.rendererType").value = newRenderType;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.rendererType");
}
@Override
public DebugMode getDebugMode()
{
@@ -770,8 +770,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugMode").value = newDebugMode;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugMode");
}
@Override
public boolean getDebugKeybindingsEnabled()
{
@@ -894,11 +894,11 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
}
}
}
public static class Buffers implements IBuffers
{
@Override
public GpuUploadMethod getGpuUploadMethod()
{
@@ -910,8 +910,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.gpuUploadMethod").value = newDisableVanillaFog;
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.gpuUploadMethod");
}
@Override
public int getGpuUploadPerMegabyteInMilliseconds()
{
@@ -922,8 +922,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.gpuUploadPerMegabyteInMilliseconds").value = newMilliseconds;
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.gpuUploadPerMegabyteInMilliseconds");
}
@Override
public BufferRebuildTimes getRebuildTimes()
{
@@ -27,7 +27,6 @@ import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.platform.Window;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -64,11 +63,10 @@ import net.minecraft.world.level.dimension.DimensionType;
import org.jetbrains.annotations.Nullable;
/**
* A singleton that wraps the Minecraft class
* to allow for easier movement between Minecraft versions.
* A singleton that wraps the Minecraft object.
*
* @author James Seibel
* @version 9-16-2021
* @version 3-5-2022
*/
public class MinecraftClientWrapper implements IMinecraftClientWrapper
{
@@ -199,7 +197,6 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper
//=============//
// Simple gets //
//=============//
@@ -10,12 +10,9 @@ import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.lod.common.wrappers.misc.LightMapWrapper;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.util.LodUtil;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
import net.minecraft.client.renderer.LightTexture;
import com.mojang.math.Vector3f;
@@ -55,96 +52,96 @@ import net.minecraft.world.phys.Vec3;
*/
public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
private static final Minecraft MC = Minecraft.getInstance();
private static final GameRenderer GAME_RENDERER = MC.gameRenderer;
private static final IWrapperFactory FACTORY = WrapperFactory.INSTANCE;
@Override
public Vec3f getLookAtVector()
{
Camera camera = GAME_RENDERER.getMainCamera();
Vector3f cameraDir = camera.getLookVector();
return new Vec3f(cameraDir.x(), cameraDir.y(), cameraDir.z());
}
@Override
public AbstractBlockPosWrapper getCameraBlockPosition()
{
Camera camera = GAME_RENDERER.getMainCamera();
BlockPos blockPos = camera.getBlockPosition();
return new BlockPosWrapper(blockPos.getX(), blockPos.getY(), blockPos.getZ());
}
@Override
public boolean playerHasBlindnessEffect()
{
return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null;
}
@Override
public Vec3d getCameraExactPosition()
{
Camera camera = GAME_RENDERER.getMainCamera();
Vec3 projectedView = camera.getPosition();
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
}
@Override
public Mat4f getDefaultProjectionMatrix(float partialTicks)
{
return McObjectConverter.Convert(GAME_RENDERER.getProjectionMatrix(GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true)));
}
@Override
public double getGamma()
{
return MC.options.gamma;
}
@Override
public Color getFogColor(float partialTicks) {
FogRenderer.setupColor(GAME_RENDERER.getMainCamera(), partialTicks, MC.level, 1, GAME_RENDERER.getDarkenWorldAmount(partialTicks));
float[] colorValues = RenderSystem.getShaderFogColor();
return new Color(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
}
// getSpecialFogColor() is the same as getFogColor()
@Override
public Color getSkyColor() {
if (MC.level.dimensionType().hasSkyLight()) {
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), MC.getFrameTime());
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
} else
return new Color(0, 0, 0);
}
@Override
public double getFov(float partialTicks)
{
return GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true);
}
/** Measured in chunks */
@Override
public int getRenderDistance()
{
return MC.options.renderDistance;
}
@Override
public int getScreenWidth()
{
return MC.getWindow().getWidth();
}
@Override
public int getScreenHeight()
{
return MC.getWindow().getHeight();
}
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
private static final Minecraft MC = Minecraft.getInstance();
private static final GameRenderer GAME_RENDERER = MC.gameRenderer;
private static final IWrapperFactory FACTORY = WrapperFactory.INSTANCE;
@Override
public Vec3f getLookAtVector()
{
Camera camera = GAME_RENDERER.getMainCamera();
Vector3f cameraDir = camera.getLookVector();
return new Vec3f(cameraDir.x(), cameraDir.y(), cameraDir.z());
}
@Override
public AbstractBlockPosWrapper getCameraBlockPosition()
{
Camera camera = GAME_RENDERER.getMainCamera();
BlockPos blockPos = camera.getBlockPosition();
return new BlockPosWrapper(blockPos.getX(), blockPos.getY(), blockPos.getZ());
}
@Override
public boolean playerHasBlindnessEffect()
{
return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null;
}
@Override
public Vec3d getCameraExactPosition()
{
Camera camera = GAME_RENDERER.getMainCamera();
Vec3 projectedView = camera.getPosition();
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
}
@Override
public Mat4f getDefaultProjectionMatrix(float partialTicks)
{
return McObjectConverter.Convert(GAME_RENDERER.getProjectionMatrix(GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true)));
}
@Override
public double getGamma()
{
return MC.options.gamma;
}
@Override
public Color getFogColor(float partialTicks) {
FogRenderer.setupColor(GAME_RENDERER.getMainCamera(), partialTicks, MC.level, 1, GAME_RENDERER.getDarkenWorldAmount(partialTicks));
float[] colorValues = RenderSystem.getShaderFogColor();
return new Color(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
}
// getSpecialFogColor() is the same as getFogColor()
@Override
public Color getSkyColor() {
if (MC.level.dimensionType().hasSkyLight()) {
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), MC.getFrameTime());
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
} else
return new Color(0, 0, 0);
}
@Override
public double getFov(float partialTicks)
{
return GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true);
}
/** Measured in chunks */
@Override
public int getRenderDistance()
{
return MC.options.getEffectiveRenderDistance();
}
@Override
public int getScreenWidth()
{
return MC.getWindow().getWidth();
}
@Override
public int getScreenHeight()
{
return MC.getWindow().getHeight();
}
private RenderTarget getRenderTarget() {
RenderTarget r = null; //MC.levelRenderer.getCloudsTarget();
return r!=null ? r : MC.getMainRenderTarget();
@@ -165,76 +162,81 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
return getRenderTarget().viewHeight;
}
/**
* This method returns the ChunkPos of all chunks that Minecraft
* is going to render this frame. <br><br>
* <p>
*/
/**
* This method returns the ChunkPos of all chunks that Minecraft
* is going to render this frame. <br><br>
* <p>
*/
public boolean usingBackupGetVanillaRenderedChunks = false;
@Override
public HashSet<AbstractChunkPosWrapper> getVanillaRenderedChunks()
{
ISodiumAccessor sodium = ModAccessorHandler.get(ISodiumAccessor.class);
if (sodium != null)
{
return sodium.getNormalRenderedChunks();
}
IOptifineAccessor optifine = ModAccessorHandler.get(IOptifineAccessor.class);
if (optifine != null)
{
HashSet<AbstractChunkPosWrapper> pos = optifine.getNormalRenderedChunks();
if (pos == null)
pos = getMaximumRenderedChunks();
return pos;
}
if (!usingBackupGetVanillaRenderedChunks) {
try {
LevelRenderer levelRenderer = MC.levelRenderer;
ObjectArrayList<LevelRenderer.RenderChunkInfo> chunks = levelRenderer.renderChunks;
return (chunks.stream().map((chunk) -> {
AABB chunkBoundingBox = chunk.chunk.bb;
return FACTORY.createChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
}).collect(Collectors.toCollection(HashSet::new)));
} catch (LinkageError e) {
try {
MinecraftClientWrapper.INSTANCE.sendChatMessage(
"\u00A7e\u00A7l\u00A7uWARNING: Distant Horizons: getVanillaRenderedChunks method failed."
+ " Using Backup Method.");
MinecraftClientWrapper.INSTANCE.sendChatMessage(
"\u00A7eOverdraw prevention will be worse than normal.");
} catch (Exception e2) {}
ApiShared.LOGGER.error("getVanillaRenderedChunks Error: ", e);
usingBackupGetVanillaRenderedChunks = true;
}
}
return getMaximumRenderedChunks();
}
@Override
public HashSet<AbstractChunkPosWrapper> getVanillaRenderedChunks()
{
ISodiumAccessor sodium = ModAccessorHandler.get(ISodiumAccessor.class);
if (sodium != null)
{
return sodium.getNormalRenderedChunks();
}
IOptifineAccessor optifine = ModAccessorHandler.get(IOptifineAccessor.class);
if (optifine != null)
{
HashSet<AbstractChunkPosWrapper> pos = optifine.getNormalRenderedChunks();
if (pos == null)
pos = getMaximumRenderedChunks();
return pos;
}
if (!usingBackupGetVanillaRenderedChunks) {
try {
LevelRenderer levelRenderer = MC.levelRenderer;
LinkedHashSet<LevelRenderer.RenderChunkInfo> chunks = levelRenderer.renderChunkStorage.get().renderChunks;
return (chunks.stream().map((chunk) -> {
#if MC_VERSION_1_18_2
AABB chunkBoundingBox = chunk.chunk.getBoundingBox();
#elif MC_VERSION_1_18_1
AABB chunkBoundingBox = chunk.chunk.bb;
#endif
return FACTORY.createChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
}).collect(Collectors.toCollection(HashSet::new)));
} catch (LinkageError e) {
try {
MinecraftClientWrapper.INSTANCE.sendChatMessage(
"\u00A7e\u00A7l\u00A7uWARNING: Distant Horizons: getVanillaRenderedChunks method failed."
+ " Using Backup Method.");
MinecraftClientWrapper.INSTANCE.sendChatMessage(
"\u00A7eOverdraw prevention will be worse than normal.");
} catch (Exception e2) {}
ApiShared.LOGGER.error("getVanillaRenderedChunks Error: ", e);
usingBackupGetVanillaRenderedChunks = true;
}
}
return getMaximumRenderedChunks();
}
@Override
public int[] getLightmapPixels()
{
LightTexture tex = GAME_RENDERER.lightTexture();
tex.tick(); // This call makes no sense, but it fixes pause menu flicker bug
NativeImage lightMapPixels = tex.lightPixels;
LightMapWrapper lightMap = new LightMapWrapper(lightMapPixels);
int lightMapHeight = getLightmapTextureHeight();
int lightMapWidth = getLightmapTextureWidth();
int[] pixels = new int[lightMapWidth * lightMapHeight];
for (int u = 0; u < lightMapWidth; u++)
{
for (int v = 0; v < lightMapWidth; v++)
{
// this could probably be kept as a int, but
// it is easier to test and see the colors when debugging this way.
// When creating a new release this should be changed to the int version.
int col = lightMap.getLightValue(u, v);
// these should both create a totally white image
@Override
@Deprecated
public int[] getLightmapPixels()
{
LightTexture tex = GAME_RENDERER.lightTexture();
//tex.tick(); // This call makes no sense, but it fixes pause menu flicker bug
NativeImage lightMapPixels = tex.lightTexture.getPixels();
LightMapWrapper lightMap = new LightMapWrapper(lightMapPixels);
int lightMapHeight = getLightmapTextureHeight();
int lightMapWidth = getLightmapTextureWidth();
int[] pixels = new int[lightMapWidth * lightMapHeight];
for (int u = 0; u < lightMapWidth; u++)
{
for (int v = 0; v < lightMapWidth; v++)
{
// this could probably be kept as a int, but
// it is easier to test and see the colors when debugging this way.
// When creating a new release this should be changed to the int version.
int col = lightMap.getLightValue(u, v);
// these should both create a totally white image
// int col =
// Integer.MAX_VALUE;
// int col =
@@ -248,78 +250,88 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
// ((c.getGreen() & 0xFF) << 8) | // green
// ((c.getBlue() & 0xFF)) | // red
// ((c.getAlpha() & 0xFF) << 24); // alpha
// 2D array stored in a 1D array.
// Thank you Tim from College ;)
pixels[u * lightMapWidth + v] = col;
}
}
return pixels;
}
// 2D array stored in a 1D array.
// Thank you Tim from College ;)
pixels[u * lightMapWidth + v] = col;
}
}
return pixels;
}
@Override
public ILightMapWrapper getLightmapWrapper() {
return new LightMapWrapper(GAME_RENDERER.lightTexture());
}
@Override
public int getLightmapTextureHeight()
{
int height = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null)
{
NativeImage tex = lightTexture.lightPixels;
if (tex != null)
{
height = tex.getHeight();
}
}
return height;
}
@Override
public int getLightmapTextureWidth()
{
int width = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null)
{
NativeImage tex = lightTexture.lightPixels;
if (tex != null)
{
width = tex.getWidth();
}
}
return width;
}
@Override
public int getLightmapGLFormat() {
int glFormat = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null) {
NativeImage tex = lightTexture.lightPixels;
if (tex != null) {
glFormat = tex.format().glFormat();
}
}
return glFormat;
}
@Override
public boolean isFogStateSpecial() {
Entity entity = GAME_RENDERER.getMainCamera().getEntity();
boolean isBlind = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
return GAME_RENDERER.getMainCamera().getFluidInCamera() != FogType.NONE || isBlind;
}
@Override
public boolean tryDisableVanillaFog() {
return true; // Handled via MixinFogRenderer in both forge and fabric
}
@Override
@Deprecated
public int getLightmapTextureHeight()
{
int height = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null)
{
NativeImage tex = lightTexture.lightPixels;
if (tex != null)
{
height = tex.getHeight();
}
}
return height;
}
@Override
@Deprecated
public int getLightmapTextureWidth()
{
int width = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null)
{
NativeImage tex = lightTexture.lightPixels;
if (tex != null)
{
width = tex.getWidth();
}
}
return width;
}
@Override
@Deprecated
public int getLightmapGLFormat() {
int glFormat = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null) {
NativeImage tex = lightTexture.lightPixels;
if (tex != null) {
glFormat = tex.format().glFormat();
}
}
return glFormat;
}
@Override
public boolean isFogStateSpecial() {
Entity entity = GAME_RENDERER.getMainCamera().getEntity();
boolean isBlind = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
return GAME_RENDERER.getMainCamera().getFluidInCamera() != FogType.NONE || isBlind;
}
@Override
public boolean tryDisableVanillaFog() {
return true; // Handled via MixinFogRenderer in both forge and fabric
}
}
@@ -2,6 +2,8 @@ package com.seibel.lod.common.wrappers.misc;
import com.mojang.blaze3d.platform.NativeImage;
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
import net.minecraft.client.renderer.LightTexture;
import org.lwjgl.opengl.GL32;
/**
* @author James Seibel
@@ -11,11 +13,17 @@ public class LightMapWrapper implements ILightMapWrapper
{
static NativeImage lightMap = null;
private LightTexture tex;
public LightMapWrapper(NativeImage newLightMap)
{
lightMap = newLightMap;
}
public LightMapWrapper(LightTexture lightTexture) {
tex = lightTexture;
}
public static void setLightMap(NativeImage newLightMap)
{
lightMap = newLightMap;
@@ -26,4 +34,14 @@ public class LightMapWrapper implements ILightMapWrapper
{
return lightMap.getPixelRGBA(skyLight, blockLight);
}
@Override
public void bind() {
GL32.glBindTexture(GL32.GL_TEXTURE_2D, tex.lightTexture.getId());
}
@Override
public void unbind() {
GL32.glBindTexture(GL32.GL_TEXTURE_2D, 0);
}
}
@@ -36,7 +36,7 @@ public class BiomeWrapper implements IBiomeWrapper
{
public static final ConcurrentMap<Biome, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>();
private Biome biome;
private final Biome biome;
public BiomeWrapper(Biome biome)
{
@@ -121,12 +121,12 @@ public class BiomeWrapper implements IBiomeWrapper
return colorInt;
}
@Override
public String getName() {
@Override public String getName()
{
return biome.toString();
}
@Override
public int getGrassTint(int x, int z)
{
@@ -34,7 +34,7 @@ import net.minecraft.world.level.dimension.DimensionType;
public class DimensionTypeWrapper implements IDimensionTypeWrapper
{
private static final ConcurrentMap<DimensionType, DimensionTypeWrapper> dimensionTypeWrapperMap = new ConcurrentHashMap<>();
private DimensionType dimensionType;
private final DimensionType dimensionType;
public DimensionTypeWrapper(DimensionType dimensionType)
{
@@ -51,12 +51,12 @@ public class WorldWrapper implements IWorldWrapper
private static final ConcurrentMap<LevelAccessor, WorldWrapper> worldWrapperMap = new ConcurrentHashMap<>();
private final LevelAccessor world;
public final WorldType worldType;
public WorldWrapper(LevelAccessor newWorld)
{
world = newWorld;
if (world.getClass() == ServerLevel.class)
worldType = WorldType.ServerWorld;
else if (world.getClass() == ClientLevel.class)
@@ -64,8 +64,8 @@ public class WorldWrapper implements IWorldWrapper
else
worldType = WorldType.Unknown;
}
@Nullable
public static WorldWrapper getWorldWrapper(LevelAccessor world)
{
@@ -73,109 +73,109 @@ public class WorldWrapper implements IWorldWrapper
//first we check if the biome has already been wrapped
if(worldWrapperMap.containsKey(world) && worldWrapperMap.get(world) != null)
return worldWrapperMap.get(world);
//if it hasn't been created yet, we create it and save it in the map
WorldWrapper worldWrapper = new WorldWrapper(world);
worldWrapperMap.put(world, worldWrapper);
//we return the newly created wrapper
return worldWrapper;
}
public static void clearMap()
{
worldWrapperMap.clear();
}
@Override
public WorldType getWorldType()
{
return worldType;
}
@Override
public DimensionTypeWrapper getDimensionType()
{
return DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType());
}
@Override
public int getBlockLight(int x, int y, int z)
{
return world.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
}
@Override
public int getSkyLight(int x, int y, int z)
{
return world.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
}
public LevelAccessor getWorld()
{
return world;
}
@Override
public boolean hasCeiling()
{
return world.dimensionType().hasCeiling();
}
@Override
public boolean hasSkyLight()
{
return world.dimensionType().hasSkyLight();
}
@Override
public int getHeight()
{
return world.getHeight();
}
@Override
public short getMinHeight()
{
return (short) world.getMinBuildHeight();
}
/** @throws UnsupportedOperationException if the WorldWrapper isn't for a ServerWorld */
@Override
public File getSaveFolder() throws UnsupportedOperationException
{
if (worldType != WorldType.ServerWorld)
throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds.");
ServerChunkCache chunkSource = ((ServerLevel) world).getChunkSource();
return chunkSource.getDataStorage().dataFolder;
}
/** @throws UnsupportedOperationException if the WorldWrapper isn't for a ServerWorld */
public ServerLevel getServerWorld() throws UnsupportedOperationException
{
if (worldType != WorldType.ServerWorld)
throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds.");
return (ServerLevel) world;
}
@Override
public int getSeaLevel()
{
// TODO this is depreciated, what should we use instead?
return world.getSeaLevel();
}
@Override
public IChunkWrapper tryGetChunk(AbstractChunkPosWrapper pos) {
ChunkAccess chunk = world.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
if (chunk == null) return null;
return new ChunkWrapper(chunk, world);
}
@Override
public boolean hasChunkLoaded(int chunkX, int chunkZ) {
// world.hasChunk(chunkX, chunkZ); THIS DOES NOT WORK FOR CLIENT LEVEL CAUSE MOJANG ALWAYS RETURN TRUE FOR THAT!
@@ -183,5 +183,5 @@ public class WorldWrapper implements IWorldWrapper
return source.hasChunk(chunkX, chunkZ);
}
}
@@ -19,24 +19,21 @@
package com.seibel.lod.common.wrappers.worldGeneration;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.logging.ConfigBasedLogger;
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.enums.config.LightGenerationMode;
import com.seibel.lod.core.logging.ConfigBasedLogger;
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.util.LodThreadFactory;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.util.gridList.ArrayGridList;
import com.seibel.lod.core.util.LodThreadFactory;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
import java.io.IOException;
import java.time.Duration;
import java.util.Iterator;
import java.util.LinkedList;
@@ -71,6 +68,7 @@ import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.levelgen.DebugLevelSource;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.LogManager;
@@ -101,6 +99,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
public static final ConfigBasedLogger LOAD_LOGGER =
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
() -> CONFIG.client().advanced().debugging().debugSwitch().getLogWorldGenLoadEvent());
//TODO: Make actual proper support for StarLight
public static class PrefEvent
@@ -241,7 +240,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
public static final int RANGE_TO_RANGE_EMPTY_EXTENSION = 1;
public int unknownExceptionCount = 0;
public long lastExceptionTriggerTime = 0;
public static final LodThreadFactory threadFactory = new LodThreadFactory("Gen-Worker-Thread", Thread.MIN_PRIORITY);
public static ThreadLocal<Boolean> isDistantGeneratorThread = new ThreadLocal<>();
@@ -256,7 +255,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
public ExecutorService executors = Executors.newFixedThreadPool(
CONFIG.client().advanced().threading().getNumberOfWorldGenerationThreads(), threadFactory);
public <T> T joinSync(CompletableFuture<T> f) {
if (!unsafeThreadingRecorded && !f.isDone()) {
EVENT_LOGGER.error("Unsafe Threading in Chunk Generator: ", new RuntimeException("Concurrent future"));
@@ -265,7 +264,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
return f.join();
}
public void resizeThreadPool(int newThreadCount)
{
executors = Executors.newFixedThreadPool(newThreadCount,
@@ -295,6 +294,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
unknownExceptionCount = 0;
}
}
// Update all current out standing jobs
Iterator<GenerationEvent> iter = events.iterator();
while (iter.hasNext())
@@ -350,11 +350,10 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
generator instanceof FlatLevelSource)) {
EVENT_LOGGER.warn("Unknown Chunk Generator detected: [{}], Distant Generation May Fail!", generator.getClass());
EVENT_LOGGER.warn("If it does crash, set Distant Generation to OFF or Generation Mode to None.");
ApiShared.LOGGER.warn("Unknown Chunk Generator detected: {}", generator.getClass());
}
params = new GlobalParameters((ServerLevel) ((WorldWrapper) serverlevel).getWorld(), lodBuilder, lodDim);
}
@SuppressWarnings("resource")
public static ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, ServerLevel level, LevelLightEngine lightEngine)
{
@@ -369,15 +368,15 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
if (chunkData == null)
{
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level);
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null);
}
else
{
try {
return ChunkLoader.read(level, lightEngine, chunkPos, chunkData);
return ChunkLoader.read(level, lightEngine, chunkPos, chunkData);
} catch (Exception e) {
LOAD_LOGGER.error("DistantHorizons: Couldn't load chunk {}", chunkPos, e);
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level);
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null);
}
}
@@ -396,7 +395,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
int refRange = e.range + RANGE_TO_RANGE_EMPTY_EXTENSION;
int refOffsetX = e.pos.x - refRange;
int refOffsetZ = e.pos.z - refRange;
try
{
adaptor = new LightGetterAdaptor(params.level);
@@ -416,7 +414,8 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// Continue...
}
if (target == null)
target = new ProtoChunk(chunkPos, UpgradeData.EMPTY, params.level);
target = new ProtoChunk(chunkPos, UpgradeData.EMPTY, params.level,
params.biomes, null);
return target;
};
@@ -463,31 +462,39 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
default:
return;
}
for (int oy = 0; oy < genChunks.gridSize; oy++)
{
for (int ox = 0; ox < genChunks.gridSize; ox++)
{
ChunkAccess target = genChunks.get(ox, oy);
target.setLightCorrect(true);
//if (target instanceof LevelChunk)
// ((LevelChunk) target).setClientLightReady(true);
ChunkWrapper wrappedChunk = new ChunkWrapper(target, region);
if (!wrappedChunk.isLightCorrect()) {
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
}
boolean isFull = target.getStatus() == ChunkStatus.FULL || target instanceof LevelChunk;
//boolean isPartial = target.isOldNoiseGeneration();
boolean isPartial = target.isOldNoiseGeneration();
if (isFull)
{
LOAD_LOGGER.info("Detected full existing chunk at {}", target.getPos());
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, new ChunkWrapper(target, region),
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
new LodBuilderConfig(DistanceGenerationMode.FULL), true, e.genAllDetails);
}
else if (isPartial)
{
LOAD_LOGGER.info("Detected old existing chunk at {}", target.getPos());
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
new LodBuilderConfig(generationMode), true, e.genAllDetails);
}
else if (target.getStatus() == ChunkStatus.EMPTY && generationMode == DistanceGenerationMode.NONE)
{
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, new ChunkWrapper(target, region),
params.lodBuilder.generateLodNodeFromChunk(params.lodDim,wrappedChunk,
LodBuilderConfig.getFillVoidConfig(), true, e.genAllDetails);
}
else
{
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, new ChunkWrapper(target, region),
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
new LodBuilderConfig(generationMode), true, e.genAllDetails);
}
if (e.lightMode == LightGenerationMode.FANCY || isFull)
@@ -505,9 +512,9 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
PREF_LOGGER.infoInc("{}", e.tParam.perf);
}
}
public void generateDirect(GenerationEvent e, ArrayGridList<ChunkAccess> subRange, Steps step,
LightedWorldGenRegion region)
LightedWorldGenRegion region)
{
try
{
@@ -551,7 +558,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
stepFeatures.generateGroup(e.tParam, region, subRange);
e.pEvent.featureNano = System.nanoTime();
e.refreshTimeout();
return;
}
finally
{
@@ -565,6 +571,10 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
{
if (p instanceof ProtoChunk)
((ProtoChunk) p).setLightCorrect(true);
if (p instanceof LevelChunk) {
((LevelChunk) p).setLightCorrect(true);
((LevelChunk) p).setClientLightReady(true);
}
});
break;
}
@@ -7,9 +7,9 @@ import java.util.concurrent.TimeUnit;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.PrefEvent;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.LightGenerationMode;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper.Steps;
@@ -70,9 +70,9 @@ public final class GenerationEvent
public boolean terminate()
{
future.cancel(true);
ApiShared.LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
BatchGenerationEnvironment.threadFactory.dumpAllThreadStacks();
future.cancel(true);
return future.isCancelled();
}
@@ -100,6 +100,7 @@ public final class GenerationEvent
public void refreshTimeout()
{
nanotime = System.nanoTime();
LodUtil.checkInterruptsUnchecked();
}
@Override
@@ -11,7 +11,9 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.world.level.storage.WorldData;
@@ -20,7 +22,7 @@ public final class GlobalParameters
{
public final ChunkGenerator generator;
public final StructureManager structures;
//public final BiomeManager biomeManager;
public final BiomeManager biomeManager;
public final WorldGenSettings worldGenSettings;
public final ThreadedLevelLightEngine lightEngine;
public final LodBuilder lodBuilder;
@@ -28,6 +30,7 @@ public final class GlobalParameters
public final Registry<Biome> biomes;
public final RegistryAccess registry;
public final long worldSeed;
public final ChunkScanAccess chunkScanner;
public final ServerLevel level; // TODO: Figure out a way to remove this. Maybe ClientLevel also works?
public final DataFixer fixerUpper;
@@ -43,9 +46,10 @@ public final class GlobalParameters
registry = server.registryAccess();
biomes = registry.registryOrThrow(Registry.BIOME_REGISTRY);
worldSeed = worldGenSettings.seed();
//biomeManager = new BiomeManager(level, BiomeManager.obfuscateSeed(worldSeed));
biomeManager = new BiomeManager(level, BiomeManager.obfuscateSeed(worldSeed));
structures = server.getStructureManager();
generator = level.getChunkSource().getGenerator();
chunkScanner = level.getChunkSource().chunkScanner();
fixerUpper = server.getFixerUpper();
}
}
@@ -7,12 +7,14 @@ import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.WorldGenStruct
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.structure.StructureCheck;
public final class ThreadedParameters
{
private static final ThreadLocal<ThreadedParameters> localParam = new ThreadLocal<ThreadedParameters>();
final ServerLevel level;
public WorldGenStructFeatManager structFeat = null;
public final StructureCheck structCheck;
boolean isValid = true;
public final PerfCalculator perf = new PerfCalculator();
@@ -34,9 +36,13 @@ public final class ThreadedParameters
private ThreadedParameters(GlobalParameters param)
{
level = param.level;
structFeat = new WorldGenStructFeatManager(level, param.worldGenSettings);
structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
param.level.dimension(), param.generator, level, param.generator.getBiomeSource(), param.worldSeed,
param.fixerUpper);
}
public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param) {
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel);
public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param)
{
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel, structCheck);
}
}
@@ -1,74 +1,145 @@
package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Dynamic;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.logging.ConfigBasedLogger;
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 com.seibel.lod.core.logging.ConfigBasedLogger;
#if MC_VERSION_1_18_2
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
#endif
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.ChunkTickList;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.TickList;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.ProtoTickList;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.ticks.LevelChunkTicks;
import org.apache.logging.log4j.Logger;
public class ChunkLoader {
public class ChunkLoader
{
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER;
private static LevelChunkSection[] readSections(WorldGenLevel level, LevelLightEngine lightEngine,
ChunkPos chunkPos, CompoundTag tagLevel) {
boolean isLightOn = tagLevel.getBoolean("isLightOn");
ListTag listTag = tagLevel.getList("Sections", 10);
int i = level.getSectionsCount();
LevelChunkSection[] levelChunkSections = new LevelChunkSection[i];
boolean bl2 = level.getLevel().dimensionType().hasSkyLight();
if (isLightOn)
lightEngine.retainData(chunkPos, true);
for (int j = 0; j < listTag.size(); j++) {
CompoundTag compoundTag3 = listTag.getCompound(j);
int k = compoundTag3.getByte("Y");
if (compoundTag3.contains("Palette", 9) && compoundTag3.contains("BlockStates", 12)) {
LevelChunkSection levelChunkSection = new LevelChunkSection(k << 4);
levelChunkSection.getStates().read(compoundTag3.getList("Palette", 10),
compoundTag3.getLongArray("BlockStates"));
levelChunkSection.recalcBlockCounts();
if (!levelChunkSection.isEmpty())
levelChunkSections[level.getSectionIndexFromSectionY(k)] = levelChunkSection;
}
if (isLightOn) {
if (compoundTag3.contains("BlockLight", 7))
lightEngine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, k),
new DataLayer(compoundTag3.getByteArray("BlockLight")), true);
if (bl2 && compoundTag3.contains("SkyLight", 7))
lightEngine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, k),
new DataLayer(compoundTag3.getByteArray("SkyLight")), true);
}
private static final String TAG_UPGRADE_DATA = "UpgradeData";
private static final String BLOCK_TICKS_TAG = "block_ticks";
private static final String FLUID_TICKS_TAG = "fluid_ticks";
private static BlendingData readBlendingData(CompoundTag chunkData)
{
BlendingData blendingData = null;
if (chunkData.contains("blending_data", 10))
{
@SuppressWarnings({ "unchecked", "rawtypes" })
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial(LOGGER::error).orElse(null);
}
return levelChunkSections;
return blendingData;
}
private static LevelChunkSection[] readSections(LevelAccessor level, LevelLightEngine lightEngine, ChunkPos chunkPos, CompoundTag chunkData)
{
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
#if MC_VERSION_1_18_1
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
#elif MC_VERSION_1_18_2
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#endif
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData) {
int i = level.getSectionsCount();
LevelChunkSection[] chunkSections = new LevelChunkSection[i];
boolean isLightOn = chunkData.getBoolean("isLightOn");
boolean hasSkyLight = level.dimensionType().hasSkyLight();
ListTag tagSections = chunkData.getList("sections", 10);
for (int j = 0; j < tagSections.size(); ++j)
{
CompoundTag tagSection = tagSections.getCompound(j);
byte sectionYPos = tagSection.getByte("Y");
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
if (sectionId >= 0 && sectionId < chunkSections.length)
{
PalettedContainer<BlockState> blockStateContainer;
#if MC_VERSION_1_18_1
PalettedContainer<Biome> biomeContainer;
#elif MC_VERSION_1_18_2
PalettedContainer<Holder<Biome>> biomeContainer;
#endif
blockStateContainer = tagSection.contains("block_states", 10)
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
#if MC_VERSION_1_18_1
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);
#elif MC_VERSION_1_18_2
biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string)).getOrThrow(false, LOGGER::error)
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#endif
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
}
if (!isLightOn)
continue;
if (tagSection.contains("BlockLight", 7))
lightEngine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, sectionYPos), new DataLayer(tagSection.getByteArray("BlockLight")), true);
if (hasSkyLight && tagSection.contains("SkyLight", 7))
lightEngine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, sectionYPos), new DataLayer(tagSection.getByteArray("SkyLight")), true);
}
return chunkSections;
}
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
{
CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps");
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));
@@ -76,74 +147,178 @@ public class ChunkLoader {
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
}
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData) {
#if MC_VERSION_1_18_1
private static Map<StructureFeature<?>, StructureStart<?>> unpackStructureStart(StructurePieceSerializationContext structurePieceSerializationContext, CompoundTag compoundTag, long l)
{
HashMap<StructureFeature<?>, StructureStart<?>> map = Maps.newHashMap();
CompoundTag compoundTag2 = compoundTag.getCompound("starts");
for (String string : compoundTag2.getAllKeys())
{
String string2 = string.toLowerCase(Locale.ROOT);
StructureFeature<?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
if (structureFeature == null)
{
LOGGER.error("Unknown structure start: {}", (Object) string2);
continue;
}
StructureStart<?> structureStart = StructureFeature.loadStaticStart(structurePieceSerializationContext, compoundTag2.getCompound(string), l);
if (structureStart == null)
continue;
map.put(structureFeature, structureStart);
}
return map;
}
private static Map<StructureFeature<?>, LongSet> unpackStructureReferences(ChunkPos chunkPos, CompoundTag compoundTag)
{
HashMap<StructureFeature<?>, LongSet> map = Maps.newHashMap();
CompoundTag compoundTag2 = compoundTag.getCompound("References");
for (String string : compoundTag2.getAllKeys())
{
String string2 = string.toLowerCase(Locale.ROOT);
StructureFeature<?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
if (structureFeature == null)
{
LOGGER.warn("Found reference to unknown structure '{}' in chunk {}, discarding", (Object) string2, (Object) chunkPos);
continue;
}
map.put(structureFeature, new LongOpenHashSet(Arrays.stream(compoundTag2.getLongArray(string)).filter(l ->
{
ChunkPos chunkPos2 = new ChunkPos(l);
if (chunkPos2.getChessboardDistance(chunkPos) > 8)
{
LOGGER.warn("Found invalid structure reference [ {} @ {} ] for chunk {}.", (Object) string2, (Object) chunkPos2, (Object) chunkPos);
return false;
}
return true;
}).toArray()));
}
return map;
}
#elif MC_VERSION_1_18_2
private static Map<ConfiguredStructureFeature<?, ?>, StructureStart> unpackStructureStart(StructurePieceSerializationContext structurePieceSerializationContext, CompoundTag compoundTag, long l) {
Map<ConfiguredStructureFeature<?, ?>, StructureStart> map = Maps.newHashMap();
Registry<ConfiguredStructureFeature<?, ?>> structStartRegistry = structurePieceSerializationContext.registryAccess().registryOrThrow(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY);
CompoundTag compoundTag2 = compoundTag.getCompound("starts");
for (String string : compoundTag2.getAllKeys()) {
ResourceLocation resourceLocation = ResourceLocation.tryParse(string);
ConfiguredStructureFeature<?, ?> structureFeature = structStartRegistry.get(resourceLocation);
// String string2 = string.toLowerCase(Locale.ROOT);
// ConfiguredStructureFeature<?, ?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
if (structureFeature == null) {
LOGGER.error("Unknown structure start: {}", resourceLocation);
continue;
}
StructureStart structureStart = StructureFeature.loadStaticStart(structurePieceSerializationContext, compoundTag2.getCompound(string), l);
if (structureStart == null)
continue;
map.put(structureFeature, structureStart);
}
return map;
}
private static Map<ConfiguredStructureFeature<?, ?>, LongSet> unpackStructureReferences(RegistryAccess registryAccess, ChunkPos chunkPos, CompoundTag compoundTag)
{
Map<ConfiguredStructureFeature<?, ?>, LongSet> map = Maps.newHashMap();
Registry<ConfiguredStructureFeature<?, ?>> structRegistry = registryAccess.registryOrThrow(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY);
CompoundTag compoundTag2 = compoundTag.getCompound("References");
for (String string : compoundTag2.getAllKeys())
{
ResourceLocation resourceLocation = ResourceLocation.tryParse(string);
ConfiguredStructureFeature<?, ?> structureFeature = structRegistry.get(resourceLocation);
// String string2 = string.toLowerCase(Locale.ROOT);
// ConfiguredStructureFeature<?, ?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
if (structureFeature == null)
{
LOGGER.warn("Found reference to unknown structure '{}' in chunk {}, discarding", resourceLocation, chunkPos);
continue;
}
map.put(structureFeature, new LongOpenHashSet(Arrays.stream(compoundTag2.getLongArray(string)).filter(l ->
{
ChunkPos chunkPos2 = new ChunkPos(l);
if (chunkPos2.getChessboardDistance(chunkPos) > 8)
{
LOGGER.warn("Found invalid structure reference [ {} @ {} ] for chunk {}.", resourceLocation, chunkPos2, chunkPos);
return false;
}
return true;
}).toArray()));
}
return map;
}
#endif
private static void readStructures(WorldGenLevel level, LevelChunk chunk, CompoundTag chunkData)
{
CompoundTag tagStructures = chunkData.getCompound("structures");
chunk.setAllStarts(
unpackStructureStart(StructurePieceSerializationContext.fromLevel(level.getLevel()), tagStructures, level.getSeed()));
chunk.setAllReferences(unpackStructureReferences(#if MC_VERSION_1_18_2 level.registryAccess() ,#endif chunk.getPos(), tagStructures));
}
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
{
ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
for (int n = 0; n < tagPostProcessings.size(); ++n) {
for (int n = 0; n < tagPostProcessings.size(); ++n)
{
ListTag listTag3 = tagPostProcessings.getList(n);
for (int o = 0; o < listTag3.size(); ++o) {
for (int o = 0; o < listTag3.size(); ++o)
{
chunk.addPackedPostProcess(listTag3.getShort(o), n);
}
}
}
public static ChunkStatus.ChunkType readChunkType(CompoundTag tagLevel) {
ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
if (chunkStatus != null) {
return chunkStatus.getChunkType();
}
return ChunkStatus.ChunkType.PROTOCHUNK;
public static ChunkStatus.ChunkType readChunkType(CompoundTag compoundTag)
{
return ChunkStatus.byName(compoundTag.getString("Status")).getChunkType();
}
public static LevelChunk read(WorldGenLevel level, LevelLightEngine lightEngine, ChunkPos chunkPos,
CompoundTag chunkData) {
CompoundTag tagLevel = chunkData.getCompound("Level");
ChunkStatus.ChunkType chunkType = readChunkType(tagLevel);
if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
return null;
ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos"));
if (!Objects.equals(chunkPos, actualPos)) {
public static LevelChunk read(WorldGenLevel level, LevelLightEngine lightEngine, ChunkPos chunkPos, CompoundTag chunkData)
{
ChunkPos actualPos = new ChunkPos(chunkData.getInt("xPos"), chunkData.getInt("zPos"));
if (!Objects.equals(chunkPos, actualPos))
{
LOGGER.error("Chunk file at {} is in the wrong location; Ignoring. (Expected {}, got {})", (Object) chunkPos, (Object) chunkPos, (Object) actualPos);
return null;
}
// ====================== Read params for making the LevelChunk
// ============================
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), level, chunkPos,
level.getLevel().getChunkSource().getGenerator().getBiomeSource(),
tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null);
UpgradeData upgradeData = tagLevel.contains("UpgradeData", 10)
? new UpgradeData(tagLevel.getCompound("UpgradeData"), level)
ChunkStatus.ChunkType chunkType = readChunkType(chunkData);
BlendingData blendingData = readBlendingData(chunkData);
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
return null;
// Prepare the light engine
boolean isLightOn = chunkData.getBoolean("isLightOn");
if (isLightOn)
level.getLightEngine().retainData(chunkPos, true);
// Read params for making the LevelChunk
UpgradeData upgradeData = chunkData.contains(TAG_UPGRADE_DATA, 10)
? new UpgradeData(chunkData.getCompound(TAG_UPGRADE_DATA), level)
: UpgradeData.EMPTY;
TickList<Block> blockTicks = tagLevel.contains("TileTicks", 9)
? ChunkTickList.create(tagLevel.getList("TileTicks", 10), Registry.BLOCK::getKey, Registry.BLOCK::get)
: new ProtoTickList<Block>(block -> (block == null || block.defaultBlockState().isAir()), chunkPos,
tagLevel.getList("ToBeTicked", 9), level);
TickList<Fluid> liquidTicks = tagLevel.contains("LiquidTicks", 9)
? ChunkTickList.create(tagLevel.getList("LiquidTicks", 10), Registry.FLUID::getKey, Registry.FLUID::get)
: new ProtoTickList<Fluid>(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos,
tagLevel.getList("LiquidsToBeTicked", 9), level);
long inhabitedTime = tagLevel.getLong("InhabitedTime");
LevelChunkSection[] levelChunkSections = readSections(level, lightEngine, chunkPos, tagLevel);
// ======================== Make the chunk
// ===========================================
LevelChunk chunk = new LevelChunk(level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks,
liquidTicks, inhabitedTime, levelChunkSections, null);
// ========================== Post setup some chunk data
// ==============================
chunk.setLightCorrect(tagLevel.getBoolean("isLightOn"));
readHeightmaps(chunk, tagLevel);
readPostPocessings(chunk, tagLevel);
// ApiShared.LOGGER.info("Loaded chunk @ "+chunk.getPos());
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(chunkData.getList(BLOCK_TICKS_TAG, 10),
string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos);
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(chunkData.getList(FLUID_TICKS_TAG, 10),
string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
long inhabitedTime = chunkData.getLong("InhabitedTime");
LevelChunkSection[] chunkSections = readSections(level, lightEngine, actualPos, chunkData);
// Make chunk
LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks, fluidTicks, inhabitedTime, chunkSections, null, blendingData);
// Set some states after object creation
chunk.setLightCorrect(isLightOn);
readHeightmaps(chunk, chunkData);
readStructures(level, chunk, chunkData);
readPostPocessings(chunk, chunkData);
return chunk;
}
private static void logErrors(ChunkPos chunkPos, int i, String string)
{
LOGGER.error("Distant Horizons: Recoverable errors when loading section [" + chunkPos.x + ", " + i + ", " + chunkPos.z + "]: " + string);
}
}
@@ -1,14 +1,11 @@
package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
import java.util.List;
import java.util.stream.Stream;
import com.seibel.lod.core.api.ApiShared;
import org.jetbrains.annotations.Nullable;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.EmptyChunkGenerator;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.LightGenerationMode;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
@@ -26,6 +23,7 @@ import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.biome.Biome;
@@ -50,13 +48,6 @@ public class LightedWorldGenRegion extends WorldGenRegion {
private final ChunkPos firstPos;
private final List<ChunkAccess> cache;
Long2ObjectOpenHashMap<ChunkAccess> chunkMap = new Long2ObjectOpenHashMap<ChunkAccess>();
private ChunkPos overrideCenterPos = null;
public void setOverrideCenter(ChunkPos pos) {overrideCenterPos = pos;}
@Override
public ChunkPos getCenter() {
return overrideCenterPos==null ? super.getCenter() : overrideCenterPos;
}
public LightedWorldGenRegion(ServerLevel serverLevel, WorldGenLevelLightEngine lightEngine,
List<ChunkAccess> list, ChunkStatus chunkStatus, int i,
@@ -69,12 +60,12 @@ public class LightedWorldGenRegion extends WorldGenRegion {
writeRadius = i;
cache = list;
size = Mth.floor(Math.sqrt(list.size()));
this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> {
object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache());
object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache());
object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache());
});
this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> {
object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.GRASS_COLOR_RESOLVER);}));
object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.FOLIAGE_COLOR_RESOLVER);}));
object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.WATER_COLOR_RESOLVER);}));
});
}
// Bypass BCLib mixin overrides.
@@ -83,11 +74,18 @@ public class LightedWorldGenRegion extends WorldGenRegion {
int i = SectionPos.blockToSectionCoord(blockPos.getX());
int j = SectionPos.blockToSectionCoord(blockPos.getZ());
ChunkPos chunkPos = this.getCenter();
ChunkAccess center = this.getChunk(chunkPos.x, chunkPos.z);
int k = Math.abs(chunkPos.x - i);
int l = Math.abs(chunkPos.z - j);
if (k > this.writeRadius || l > this.writeRadius) {
return false;
}
if (center.isUpgrading()) {
LevelHeightAccessor levelHeightAccessor = center.getHeightAccessorForGeneration();
if (blockPos.getY() < levelHeightAccessor.getMinBuildHeight() || blockPos.getY() >= levelHeightAccessor.getMaxBuildHeight()) {
return false;
}
}
return true;
}
@@ -174,7 +172,7 @@ public class LightedWorldGenRegion extends WorldGenRegion {
public ChunkAccess getChunk(int i, int j, ChunkStatus chunkStatus, boolean bl) {
ChunkAccess chunk = getChunkAccess(i, j, chunkStatus, bl);
if (chunk instanceof LevelChunk) {
chunk = new ImposterProtoChunk((LevelChunk) chunk);
chunk = new ImposterProtoChunk((LevelChunk) chunk, true);
}
return chunk;
}
@@ -239,23 +237,29 @@ public class LightedWorldGenRegion extends WorldGenRegion {
return (getBrightness(LightLayer.SKY, blockPos) >= getMaxLightLevel());
}
private final Object2ObjectArrayMap<ColorResolver, BlockTintCache> tintCaches;
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
{
BlockTintCache blockTintCache = (BlockTintCache) this.tintCaches.get(colorResolver);
return blockTintCache.getColor(blockPos, null); // FIXME[Generator]: Replace this null with something else
return blockTintCache.getColor(blockPos);
}
private Biome _getBiome(BlockPos pos) {
#if MC_VERSION_1_18_2
return getBiome(pos).value();
#elif MC_VERSION_1_18_1
return getBiome(pos);
#endif
}
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
{
int i = (Minecraft.getInstance()).options.biomeBlendRadius;
if (i == 0)
return colorResolver.getColor((Biome) getBiome(blockPos), blockPos.getX(), blockPos.getZ());
return colorResolver.getColor((Biome) _getBiome(blockPos), blockPos.getX(), blockPos.getZ());
int j = (i * 2 + 1) * (i * 2 + 1);
int k = 0;
int l = 0;
@@ -265,11 +269,12 @@ public class LightedWorldGenRegion extends WorldGenRegion {
while (cursor3D.advance())
{
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
int n = colorResolver.getColor((Biome) getBiome((BlockPos) mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
int n = colorResolver.getColor((Biome) _getBiome((BlockPos) mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
k += (n & 0xFF0000) >> 16;
l += (n & 0xFF00) >> 8;
m += n & 0xFF;
}
return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
}
}
@@ -125,10 +125,9 @@ public class WorldGenLevelLightEngine extends LevelLightEngine {
LevelChunkSection[] levelChunkSections = chunkAccess.getSections();
for (int i = 0; i < chunkAccess.getSectionsCount(); ++i) {
LevelChunkSection levelChunkSection = levelChunkSections[i];
if (!LevelChunkSection.isEmpty(levelChunkSection)) {
int j = this.levelHeightAccessor.getSectionYFromSectionIndex(i);
updateSectionStatus(SectionPos.of(chunkPos, j), false);
}
if (levelChunkSection.hasOnlyAir()) continue;
int j = this.levelHeightAccessor.getSectionYFromSectionIndex(i);
updateSectionStatus(SectionPos.of(chunkPos, j), false);
}
enableLightSources(chunkPos, true);
if (needLightBlockUpdate) {
@@ -1,7 +1,17 @@
package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
import java.util.stream.Stream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.ChunkPos;
@@ -11,15 +21,18 @@ import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.levelgen.structure.StructureCheck;
import net.minecraft.world.level.levelgen.structure.StructureStart;
public class WorldGenStructFeatManager extends StructureFeatureManager {
final WorldGenLevel genLevel;
WorldGenSettings worldGenSettings;
StructureCheck structureCheck;
public WorldGenStructFeatManager(WorldGenSettings worldGenSettings,
WorldGenLevel genLevel) {
super(genLevel, worldGenSettings);
WorldGenLevel genLevel, StructureCheck structureCheck) {
super(genLevel, worldGenSettings, structureCheck);
this.genLevel = genLevel;
this.worldGenSettings = worldGenSettings;
}
@@ -28,7 +41,7 @@ public class WorldGenStructFeatManager extends StructureFeatureManager {
public WorldGenStructFeatManager forWorldGenRegion(WorldGenRegion worldGenRegion) {
if (worldGenRegion == genLevel)
return this;
return new WorldGenStructFeatManager(worldGenSettings, worldGenRegion);
return new WorldGenStructFeatManager(worldGenSettings, worldGenRegion, structureCheck);
}
private ChunkAccess _getChunk(int x, int z, ChunkStatus status) {
@@ -37,20 +50,85 @@ public class WorldGenStructFeatManager extends StructureFeatureManager {
}
@Override
public Stream<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos2,
StructureFeature<?> structureFeature) {
if (genLevel == null)
return Stream.empty();
ChunkAccess chunk = genLevel.getChunk(sectionPos2.x(), sectionPos2.z(), ChunkStatus.STRUCTURE_REFERENCES,
false);
if (chunk == null)
return Stream.empty();
return chunk.getReferencesForFeature(structureFeature).stream().map(pos -> {
SectionPos sectPos = SectionPos.of(ChunkPos.getX(pos), 0, ChunkPos.getZ(pos));
ChunkAccess startChunk = genLevel.getChunk(sectPos.x(), sectPos.z(), ChunkStatus.STRUCTURE_STARTS, false);
if (startChunk == null)
return null;
return this.getStartForFeature(sectPos, structureFeature, startChunk);
}).filter(structureStart -> structureStart != null && structureStart.isValid());
public boolean hasAnyStructureAt(BlockPos blockPos) {
SectionPos sectionPos = SectionPos.of(blockPos);
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return false;
return chunk.hasAnyStructureReferences();
}
#if MC_VERSION_1_18_1
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
StructureFeature<?> structureFeature) {
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return List.of();
// Copied from StructureFeatureManager::startsForFeature(...) with slight tweaks
LongSet longSet = chunk.getReferencesForFeature(structureFeature);
ImmutableList.Builder builder = ImmutableList.builder();
LongIterator longIterator = longSet.iterator();
while (longIterator.hasNext()) {
long l = (Long)longIterator.next();
SectionPos sectPos = SectionPos.of(new ChunkPos(l), genLevel.getMinSection());
ChunkAccess startChunk = _getChunk(sectPos.x(), sectPos.z(), ChunkStatus.STRUCTURE_STARTS);
if (startChunk == null) continue;
StructureStart<?> structureStart = this.getStartForFeature(sectPos, structureFeature, startChunk);
if (structureStart == null || !structureStart.isValid()) continue;
builder.add(structureStart);
}
return builder.build();
}
#elif MC_VERSION_1_18_2
@Override
public List<StructureStart> startsForFeature(SectionPos sectionPos, Predicate<ConfiguredStructureFeature<?, ?>> predicate) {
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return List.of();
// Copied from StructureFeatureManager::startsForFeature(...)
Map<ConfiguredStructureFeature<?, ?>, LongSet> map = chunk.getAllReferences();
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
Iterator<Map.Entry<ConfiguredStructureFeature<?, ?>, LongSet>> var5 = map.entrySet().iterator();
while(var5.hasNext()) {
Map.Entry<ConfiguredStructureFeature<?, ?>, LongSet> entry = var5.next();
ConfiguredStructureFeature<?, ?> configuredStructureFeature = entry.getKey();
if (predicate.test(configuredStructureFeature)) {
LongSet var10002 = (LongSet)entry.getValue();
Objects.requireNonNull(builder);
this.fillStartsForFeature(configuredStructureFeature, var10002, builder::add);
}
}
return builder.build();
}
@Override
public List<StructureStart> startsForFeature(SectionPos sectionPos, ConfiguredStructureFeature<?, ?> configuredStructureFeature) {
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return List.of();
// Copied from StructureFeatureManager::startsForFeature(...)
LongSet longSet = chunk.getReferencesForFeature(configuredStructureFeature);
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
Objects.requireNonNull(builder);
this.fillStartsForFeature(configuredStructureFeature, longSet, builder::add);
return builder.build();
}
@Override
public Map<ConfiguredStructureFeature<?, ?>, LongSet> getAllStructuresAt(BlockPos blockPos) {
SectionPos sectionPos = SectionPos.of(blockPos);
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return Map.of();
return chunk.getAllReferences();
}
#endif
}
@@ -3,43 +3,53 @@ package com.seibel.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
import java.util.List;
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
import net.minecraft.core.Registry;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.DebugLevelSource;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.blending.Blender;
public final class StepBiomes {
/**
*
*/
private final BatchGenerationEnvironment envionment;
private final BatchGenerationEnvironment environment;
/**
* @param worldGenerationEnvironment
* @param batchGenerationEnvironment
*/
public StepBiomes(BatchGenerationEnvironment worldGenerationEnvironment) {
envionment = worldGenerationEnvironment;
public StepBiomes(BatchGenerationEnvironment batchGenerationEnvironment)
{
environment = batchGenerationEnvironment;
}
public final ChunkStatus STATUS = ChunkStatus.BIOMES;
public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, List<ChunkAccess> chunks) {
public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion,
List<ChunkAccess> chunks) {
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
for (ChunkAccess chunk : chunks) {
if (chunk.getStatus().isOrAfter(STATUS))
continue;
if (chunk.getStatus().isOrAfter(STATUS)) continue;
((ProtoChunk) chunk).setStatus(STATUS);
chunksToDo.add(chunk);
}
for (ChunkAccess chunk : chunksToDo) {
// System.out.println("StepBiomes: "+chunk.getPos());
envionment.params.generator.createBiomes(envionment.params.biomes, chunk);
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
}
}
}
@@ -2,49 +2,59 @@ package com.seibel.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightedWorldGenRegion;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
import com.seibel.lod.core.util.gridList.ArrayGridList;
import net.minecraft.ReportedException;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.blending.Blender;
public final class StepFeatures {
/**
*
*/
private final BatchGenerationEnvironment envionment;
private final BatchGenerationEnvironment environment;
/**
* @param worldGenerationEnvironment
* @param batchGenerationEnvironment
*/
public StepFeatures(BatchGenerationEnvironment worldGenerationEnvironment) {
envionment = worldGenerationEnvironment;
public StepFeatures(BatchGenerationEnvironment batchGenerationEnvironment)
{
environment = batchGenerationEnvironment;
}
public final ChunkStatus STATUS = ChunkStatus.FEATURES;
public void generateGroup(ThreadedParameters tParams, LightedWorldGenRegion worldGenRegion, ArrayGridList<ChunkAccess> chunks) {
public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion,
ArrayGridList<ChunkAccess> chunks) {
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
for (ChunkAccess chunk : chunks) {
if (chunk.getStatus().isOrAfter(STATUS))
continue;
if (chunk.getStatus().isOrAfter(STATUS)) continue;
((ProtoChunk) chunk).setStatus(STATUS);
chunksToDo.add(chunk);
}
for (ChunkAccess chunk : chunksToDo) {
try {
worldGenRegion.setOverrideCenter(chunk.getPos());
envionment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat);
environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk,
tParams.structFeat.forWorldGenRegion(worldGenRegion));
Blender.generateBorderTicks(worldGenRegion, chunk);
} catch (ReportedException e) {
e.printStackTrace();
// FIXME: Features concurrent modification issue. Something about cocobeans just
// aren't happy
// For now just retry.
}
}
worldGenRegion.setOverrideCenter(null);
}/*
for (ChunkAccess chunk : chunks) {
Heightmap.primeHeightmaps(chunk,
EnumSet.of(Heightmap.Types.MOTION_BLOCKING, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
Heightmap.Types.OCEAN_FLOOR, Heightmap.Types.WORLD_SURFACE));
}*/
}
}
@@ -2,8 +2,8 @@ package com.seibel.lod.common.wrappers.worldGeneration.step;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.WorldGenLevelLightEngine;
import com.seibel.lod.core.util.gridList.ArrayGridList;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
@@ -28,7 +28,7 @@ public final class StepLight {
public final ChunkStatus STATUS = ChunkStatus.LIGHT;
public void generateGroup(LightEventListener lightEngine,
ArrayGridList<ChunkAccess> chunks) {
ArrayGridList<ChunkAccess> chunks) {
//ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
for (ChunkAccess chunk : chunks) {
@@ -52,6 +52,7 @@ public final class StepLight {
} catch (Exception e) {
e.printStackTrace();
}
if (chunk instanceof LevelChunk) ((LevelChunk)chunk).setClientLightReady(true);
chunk.setLightCorrect(true);
}
lightEngine.runUpdates(Integer.MAX_VALUE, true, true);
@@ -3,14 +3,15 @@ package com.seibel.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import com.google.common.collect.Sets;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
import net.minecraft.core.QuartPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.util.Mth;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
@@ -18,6 +19,7 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseSettings;
import net.minecraft.world.level.levelgen.blending.Blender;
public final class StepNoise {
/**
@@ -48,8 +50,8 @@ public final class StepNoise {
for (ChunkAccess chunk : chunksToDo) {
// System.out.println("StepNoise: "+chunk.getPos());
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
}
}
}
@@ -53,6 +53,14 @@ public final class StepStructureStart {
// System.out.println("StepStructureStart: "+chunk.getPos());
environment.params.generator.createStructures(environment.params.registry, tParams.structFeat, chunk, environment.params.structures,
environment.params.worldSeed);
try {
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
} catch (ArrayIndexOutOfBoundsException e) {
// There's a rare issue with StructStart where it throws ArrayIndexOutOfBounds
// This means the structFeat is corrupted (For some reason) and I need to reset it.
// TODO: Figure out in the future why this happens even though I am using new structFeat
throw new StepStructureStart.StructStartCorruptedException(e);
}
}
}
}
@@ -39,7 +39,8 @@ public final class StepSurface {
for (ChunkAccess chunk : chunksToDo) {
// System.out.println("StepSurface: "+chunk.getPos());
environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk);
}
}
}
+8 -11
View File
@@ -8,17 +8,15 @@ accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I
accessible field com/mojang/blaze3d/vertex/VertexBuffer vertextBufferId I
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
# pre-render setup
accessible field net/minecraft/client/renderer/LevelRenderer renderChunks Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
# used for grabbing vanilla rendered chunks
accessible field net/minecraft/client/renderer/LevelRenderer renderChunkStorage Ljava/util/concurrent/atomic/AtomicReference;
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkStorage
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
# lighting
accessible field net/minecraft/client/renderer/LightTexture lightPixels Lcom/mojang/blaze3d/platform/NativeImage;
accessible field net/minecraft/client/renderer/LightTexture lightTexture Lnet/minecraft/client/renderer/texture/DynamicTexture;
accessible field net/minecraft/world/level/lighting/LevelLightEngine blockEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
@@ -27,26 +25,25 @@ accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V
accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings;
accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecraft/world/level/biome/Biome$BiomeCategory;
# accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Ljava/util/function/Supplier;
accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doFill (Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;II)Lnet/minecraft/world/level/chunk/ChunkAccess;
#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 doFill (Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;II)Lnet/minecraft/world/level/chunk/ChunkAccess;
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/world/level/chunk/ChunkGenerator biomeSource Lnet/minecraft/world/level/biome/BiomeSource;
# lod generation from save file
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
accessible method net/minecraft/server/level/ChunkMap readChunk (Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/nbt/CompoundTag;
# grabbing textures
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite animatedTexture Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture;
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite width I
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite height I
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite mainImage [Lcom/mojang/blaze3d/platform/NativeImage;
accessible class net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture getFrameX (I)I
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture getFrameY (I)I
extendable class com/mojang/math/Matrix4f
# hacky stuff
accessible field net/minecraft/world/level/chunk/PalettedContainer lock Ljava/util/concurrent/Semaphore;
mutable field net/minecraft/world/level/chunk/PalettedContainer lock Ljava/util/concurrent/Semaphore;
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
+1 -1
Submodule core updated: 4bac38c99f...02b0637adc
+16 -7
View File
@@ -1,5 +1,5 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.0.0"
id "com.github.johnrengelman.shadow" version "7.1.0"
}
version = rootProject.mod_version+"-"+rootProject.minecraft_version+"-"+new Date().format("yyyy_MM_dd_HH_mm")
@@ -45,20 +45,29 @@ dependencies {
addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version))
// Mod Menu
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}") {
exclude(group: "net.fabricmc.fabric-api")
}
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}")
// Starlight
addMod("curse.maven:starlight-521783:${rootProject.starlight_version_fabric}", rootProject.enable_starlight)
// Phosphor
addMod("curse.maven:phosphor-372124:${rootProject.phosphor_version_fabric}", rootProject.enable_phosphor)
// Sodium
addMod("curse.maven:sodium-394468:${rootProject.sodium_version}", rootProject.enable_sodium)
implementation "org.joml:joml:1.10.2"
// Lithium
modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version))
modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version))
// Lithium
addMod("maven.modrinth:lithium:${rootProject.lithium_version}", rootProject.enable_lithium)
// Iris
addMod("maven.modrinth:iris:${rootProject.iris_version}", rootProject.enable_iris)
// BCLib
addMod("com.github.paulevsGitch:BCLib:${rootProject.bclib_version}", rootProject.enable_bclib)
// Immersive Portals
/*
modImplementation("com.github.qouteall.ImmersivePortalsMod:build:${rootProject.immersive_portals_version}") {
@@ -73,7 +82,7 @@ dependencies {
exclude(group: "net.fabricmc.fabric-api")
transitive(false)
}
*/
*/
@@ -22,19 +22,20 @@ package com.seibel.lod.fabric;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.api.EventApi;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.mojang.blaze3d.platform.InputConstants;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.common.wrappers.world.DimensionTypeWrapper;
import com.seibel.lod.common.wrappers.world.WorldWrapper;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents;
import com.seibel.lod.fabric.mixins.MixinUtilBackgroudThread;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
@@ -43,6 +44,7 @@ import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.chunk.LevelChunk;
import java.util.HashSet;
import java.util.List;
import java.util.function.Supplier;
import org.lwjgl.glfw.GLFW;
@@ -50,7 +52,7 @@ import org.lwjgl.glfw.GLFW;
/**
* This handles all events sent to the client,
* and is the starting point for most of the mod.
*
*
* @author coolGi2007
* @author Ran
* @version 11-23-2021
@@ -67,8 +69,6 @@ public class ClientProxy
* @author Ran
*/
public void registerEvents() {
// TODO: Fix this if it's wrong
/* Registor the mod accessor*/
/* World Events */
@@ -77,12 +77,12 @@ public class ClientProxy
/* World Events */
//ServerChunkEvents.CHUNK_LOAD.register(this::chunkLoadEvent);
ClientChunkEvents.CHUNK_LOAD.register(this::chunkLoadEvent);
//ClientChunkEvents.CHUNK_LOAD.register(this::chunkLoadEvent);
/* World Events */
ServerWorldEvents.LOAD.register((server, level) -> this.worldLoadEvent(level));
ServerWorldEvents.UNLOAD.register((server, level) -> this.worldUnloadEvent(level));
/* The Client World Events are in the mixins
Client world load event is in MixinClientLevel
Client world unload event is in MixinMinecraft */
@@ -93,6 +93,7 @@ public class ClientProxy
if (client.player != null) onKeyInput();
});
isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread;
}
@@ -111,7 +112,7 @@ public class ClientProxy
{
eventApi.worldSaveEvent();
}
/** This is also called when a new dimension loads */
public void worldLoadEvent(Level level)
{
@@ -154,8 +155,8 @@ public class ClientProxy
// recreate the LOD where the blocks were changed
eventApi.blockChangeEvent(chunk, dimType);
}
private static final int[] KEY_TO_CHECK_FOR = {GLFW.GLFW_KEY_F6, GLFW.GLFW_KEY_F8};
private static final List<Integer> KEY_TO_CHECK_FOR = List.of(GLFW.GLFW_KEY_F6, GLFW.GLFW_KEY_F8);
HashSet<Integer> previousKeyDown = new HashSet<Integer>();
@@ -168,7 +169,7 @@ public class ClientProxy
// Note: Minecraft's InputConstants is same as GLFW Key values
//TODO: Use mixin to hook directly into the GLFW Keyboard event in minecraft KeyboardHandler
// Check all keys we need
for (int i = GLFW.GLFW_KEY_A; i <= GLFW.GLFW_KEY_Z; i++) {
for (int i = InputConstants.KEY_A; i <= InputConstants.KEY_Z; i++) {
if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), i)) {
currectKeyDown.add(i);
}
@@ -28,10 +28,13 @@ import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.lod.fabric.wrappers.FabricDependencySetup;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
import com.seibel.lod.fabric.networking.NetworkHandler;
import com.seibel.lod.fabric.wrappers.modAccessor.ModChecker;
import com.seibel.lod.fabric.wrappers.modAccessor.OptifineAccessor;
import com.seibel.lod.fabric.wrappers.modAccessor.SodiumAccessor;
import com.seibel.lod.fabric.wrappers.modAccessor.StarlightAccessor;
import com.seibel.lod.fabric.wrappers.FabricDependencySetup;
import net.fabricmc.api.ClientModInitializer;
@@ -39,14 +42,14 @@ import net.fabricmc.api.ClientModInitializer;
* Initialize and setup the Mod. <br>
* If you are looking for the real start of the mod
* check out the ClientProxy.
*
*
* @author coolGi2007
* @author Ran
* @version 12-1-2021
*/
public class Main implements ClientModInitializer
{
// This is a client mod, so it should implement ClientModInitializer and in fabric.mod.json it should have "environment": "client"
// This is a client mod so it should implement ClientModInitializer and in fabric.mod.json it should have "environment": "client"
// Once it works on servers change the implement to ModInitializer and in fabric.mod.json it should be "environment": "*"
public static ClientProxy client_proxy;
@@ -62,7 +65,7 @@ public class Main implements ClientModInitializer
// This loads the mod after minecraft loads which doesn't causes a lot of issues
public static void init() {
LodCommonMain.initConfig();
LodCommonMain.startup(null, false);
LodCommonMain.startup(null, false, new NetworkHandler());
FabricDependencySetup.createInitialBindings();
FabricDependencySetup.finishBinding();
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
@@ -73,6 +76,9 @@ public class Main implements ClientModInitializer
if (SingletonHandler.get(IModChecker.class).isModLoaded("sodium")) {
ModAccessorHandler.bind(ISodiumAccessor.class, new SodiumAccessor());
}
if (SingletonHandler.get(IModChecker.class).isModLoaded("starlight")) {
ModAccessorHandler.bind(IStarlightAccessor.class, new StarlightAccessor());
}
if (SingletonHandler.get(IModChecker.class).isModLoaded("optifine")) {
ModAccessorHandler.bind(IOptifineAccessor.class, new OptifineAccessor());
}
@@ -82,7 +88,7 @@ public class Main implements ClientModInitializer
public static void initServer() {
LodCommonMain.initConfig();
LodCommonMain.startup(null, true);
LodCommonMain.startup(null, true, new NetworkHandler());
FabricDependencySetup.createInitialBindings();
FabricDependencySetup.finishBinding();
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
@@ -1,29 +0,0 @@
package com.seibel.lod.fabric.mixins;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.WorldgenRandom;
@Mixin(ChunkGenerator.class)
public class MixinChunkGenerator {
@Redirect(method = "applyBiomeDecoration", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/biome/Biome;generate(Lnet/minecraft/world/level/StructureFeatureManager;"
+ "Lnet/minecraft/world/level/chunk/ChunkGenerator;Lnet/minecraft/server/level/WorldGenRegion;J"
+ "Lnet/minecraft/world/level/levelgen/WorldgenRandom;Lnet/minecraft/core/BlockPos;)V"
))
private void wrapBiomeGenerateCall(Biome biome, StructureFeatureManager structFeatManager, ChunkGenerator generator,
WorldGenRegion genRegion, long l, WorldgenRandom random, BlockPos pos) {
synchronized((ChunkGenerator)(Object)this) {
biome.generate(structFeatManager, (ChunkGenerator)(Object)this, genRegion, l, random, pos);
}
}
}
@@ -0,0 +1,16 @@
package com.seibel.lod.fabric.mixins;
import com.seibel.lod.fabric.Main;
import net.minecraft.server.dedicated.DedicatedServer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(DedicatedServer.class)
public class MixinDedicatedServer {
@Inject(method = "initServer", at = @At("TAIL"))
public void initServer(CallbackInfoReturnable<Boolean> cir) {
Main.initServer();
}
}
@@ -19,8 +19,8 @@ import net.minecraft.world.level.material.FogType;
@Mixin(FogRenderer.class)
public class MixinFogRenderer {
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
// Using this instead of Float.MAX_VALUE because Sodium don't like it.
private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
@@ -22,7 +22,7 @@ import java.util.Objects;
*
* @author coolGi2007
* @version 12-02-2021
*/
*/
@Mixin(OptionsScreen.class)
public class MixinOptionsScreen extends Screen {
// Get the texture for the button
@@ -35,18 +35,18 @@ public class MixinOptionsScreen extends Screen {
private void lodconfig$init(CallbackInfo ci) {
if (SingletonHandler.get(ILodConfigWrapperSingleton.class).client().getOptionsButton())
this.addRenderableWidget(new TexturedButtonWidget(
// Where the button is on the screen
this.width / 2 - 180, this.height / 6 - 12,
// Width and height of the button
20, 20,
// Offset
0, 0,
// Some textuary stuff
20, ICON_TEXTURE, 20, 40,
// Create the button and tell it where to go
// For now it goes to the client option by default
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, "client")),
// Add a title to the screen
new TranslatableComponent("text.autoconfig." + ModInfo.ID + ".title")));
// Where the button is on the screen
this.width / 2 - 180, this.height / 6 - 12,
// Width and height of the button
20, 20,
// Offset
0, 0,
// Some textuary stuff
20, ICON_TEXTURE, 20, 40,
// Create the button and tell it where to go
// For now it goes to the client option by default
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, "client")),
// Add a title to the screen
new TranslatableComponent("text.autoconfig." + ModInfo.ID + ".title")));
}
}
@@ -1,6 +1,7 @@
package com.seibel.lod.fabric.mixins;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
import com.seibel.lod.fabric.ClientProxy;
import org.spongepowered.asm.mixin.Mixin;
@@ -8,23 +9,13 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.seibel.lod.common.wrappers.DependencySetupDoneCheck;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.util.DummyRunExecutorService;
import net.minecraft.Util;
@Mixin(Util.class)
public class MixinUtilBackgroudThread
{
private static boolean doTriggerOverride() {
try {
return DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get();
} catch (NullPointerException e) {
return false;
}
}
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/lang/Runnable;)Ljava/lang/Runnable;",
at = @At("HEAD"), cancellable = true)
@@ -32,18 +23,28 @@ public class MixinUtilBackgroudThread
{
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
{
// ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
ci.setReturnValue(r);
}
}
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<Executor> ci)
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;",
at = @At("HEAD"), cancellable = true)
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
{
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
{
// ApiShared.LOGGER.info("util backgroundExecutor triggered");
ci.setReturnValue(Runnable::run);
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
ci.setReturnValue(r);
}
}
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
{
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
{
//ApiShared.LOGGER.info("util backgroundExecutor triggered");
ci.setReturnValue(new DummyRunExecutorService());
}
}
}
@@ -25,6 +25,7 @@ import com.seibel.lod.common.Config;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.objects.math.Mat4f;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.RenderType;
import org.spongepowered.asm.mixin.Mixin;
@@ -61,6 +62,21 @@ public class MixinWorldRenderer
previousPartialTicks = tickDelta;
}
/* Inject rendering at renderSky
// HEAD or RETURN
@Inject(at = @At("RETURN"),
method = "renderSky",
cancellable = true)
private void renderLod(PoseStack modelViewMatrixStack, Matrix4f projectionMatrix, float f,
#if MC_VERSION_1_18_2 Camera camera, boolean bl,#endif Runnable r, CallbackInfo callback) {
Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
ClientApi.INSTANCE.renderLods(mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks);
}*/
// Inject rendering at first call to renderChunkLayer
// HEAD or RETURN
@Inject(at = @At("HEAD"),
@@ -18,11 +18,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
*/
@Mixin(ClientboundBlockUpdatePacket.class)
public abstract class MixinBlockUpdate {
@Shadow
public abstract BlockPos getPos();
@Shadow public abstract BlockPos getPos();
@Inject(method = "handle(Lnet/minecraft/network/protocol/game/ClientGamePacketListener;)V", at = @At("TAIL"))
private void onBlockUpdate(ClientGamePacketListener clientGamePacketListener, CallbackInfo ci) {
Main.client_proxy.blockChangeEvent(Minecraft.getInstance().player.clientLevel, this.getPos());
}
}
}
@@ -4,9 +4,11 @@ import com.seibel.lod.fabric.Main;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.renderer.LevelRenderer;
#if MC_VERSION_1_18_2
import net.minecraft.core.Holder;
#endif
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.dimension.DimensionType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -19,10 +21,26 @@ import java.util.function.Supplier;
* This class is used for world loading events
* @author Ran
*/
@Mixin(ClientLevel.class)
public class MixinClientLevel {
#if MC_VERSION_1_18_2
@Inject(method = "<init>", at = @At("TAIL"))
private void loadWorldEvent(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey<Level> resourceKey, DimensionType dimensionType, int i, Supplier<ProfilerFiller> supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
private void loadWorldEvent(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey resourceKey, Holder holder, int i, int j, Supplier supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
Main.client_proxy.worldLoadEvent((ClientLevel) (Object) this);
}
#elif MC_VERSION_1_18_1
@Inject(method = "<init>", at = @At("TAIL"))
private void loadWorldEvent(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey resourceKey, DimensionType dimensionType, int i, int j, Supplier supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
Main.client_proxy.worldLoadEvent((ClientLevel) (Object) this);
}
#endif
@Inject(method = "setLightReady", at = @At("HEAD"))
private void onChunkLightReady(int x, int z, CallbackInfo ci) {
ClientLevel l = (ClientLevel) (Object) this;
LevelChunk chunk = l.getChunkSource().getChunk(x, z, false);
if (chunk!=null && !chunk.isClientLightReady())
Main.client_proxy.chunkLoadEvent(l, chunk);
}
}
@@ -1,8 +1,9 @@
package com.seibel.lod.fabric.mixins.unsafe;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.util.ThreadingDetector;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -10,14 +11,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.concurrent.Semaphore;
/**
* NOTE: THIS IS NOT A FIX TO THE PROBLEM.
* TODO: Do/Find an actual fix to this
*
* @author Ran
* Why does this exist? But okay! (Will be probably removed when the experimental generator is done)
*/
@Mixin(PalettedContainer.class)
public class MixinPalettedContainer {
@Mixin(ThreadingDetector.class)
public class MixinThreadingDectector {
@Mutable
@Shadow
private Semaphore lock;
@Inject(method = "<init>", at = @At("RETURN"))
@@ -0,0 +1,25 @@
package com.seibel.lod.fabric.networking;
import com.seibel.lod.common.networking.NetworkInterface;
import com.seibel.lod.common.networking.Networking;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
/**
* @author Ran
*/
public class NetworkHandler implements NetworkInterface {
@Override
public void register_Client() {
ClientPlayNetworking.registerGlobalReceiver(Networking.resourceLocation_meow, (client, handler, buf, responseSender) -> {
com.seibel.lod.common.networking.NetworkHandler.receivePacketClient(client, handler, buf);
});
}
@Override
public void register_Server() {
ServerPlayNetworking.registerGlobalReceiver(Networking.resourceLocation_meow, (server, player, handler, buf, responseSender) -> {
com.seibel.lod.common.networking.NetworkHandler.receivePacketServer(server, player, handler, buf);
});
}
}
@@ -14,7 +14,7 @@ import com.seibel.lod.fabric.wrappers.modAccessor.ModChecker;
*
* @author James Seibel
* @author Ran
* @version 12-1-2021
* @version 3-5-2022
*/
public class FabricDependencySetup
{
@@ -1,4 +1,3 @@
package com.seibel.lod.fabric.wrappers.modAccessor;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
@@ -8,17 +8,17 @@ import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
public class OptifineAccessor implements IOptifineAccessor
{
@Override
public String getModName()
{
return "Optifine-Fabric-1.18.X";
}
@Override
public HashSet<AbstractChunkPosWrapper> getNormalRenderedChunks()
{
// TODO: Impl proper methods here
return null;
}
@Override
public String getModName()
{
return "Optifine-Fabric-1.18.X";
}
@Override
public HashSet<AbstractChunkPosWrapper> getNormalRenderedChunks()
{
// TODO: Impl proper methods here
return null;
}
}
@@ -4,33 +4,39 @@ import java.util.HashSet;
import java.util.stream.Collectors;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.world.level.LevelHeightAccessor;
public class SodiumAccessor implements ISodiumAccessor {
private final IMinecraftRenderWrapper MC_RENDER = SingletonHandler.get(IMinecraftRenderWrapper.class);
IWrapperFactory factory = SingletonHandler.get(IWrapperFactory.class);
@Override
public String getModName() {
return "Sodium-Fabric-1.17.1";
@Override
public String getModName() {
return "Sodium-Fabric-1.18.X";
}
@Override
public HashSet<AbstractChunkPosWrapper> getNormalRenderedChunks() {
SodiumWorldRenderer renderer = SodiumWorldRenderer.instance();
LevelHeightAccessor height = Minecraft.getInstance().level;
// TODO: Maybe use a mixin to make this more efficient
return MC_RENDER.getMaximumRenderedChunks().stream().filter((AbstractChunkPosWrapper chunk) -> {
return (renderer.isBoxVisible(
chunk.getMinBlockX()+1, height.getMinBuildHeight()+1, chunk.getMinBlockZ()+1,
chunk.getMinBlockX()+15, height.getMaxBuildHeight()-1, chunk.getMinBlockZ()+15));
}).collect(Collectors.toCollection(HashSet::new));
LevelHeightAccessor height = Minecraft.getInstance().level;
// 0b11 = Lighted chunk & loaded chunk
return renderer.getChunkTracker().getChunks(0b00).filter(
(long l) -> {
return true;
//for (int i = height.getMinSection(); i<height.getMaxSection(); i++) {
// SectionPos p = SectionPos.of(new ChunkPos(l), i);
// if (renderer.isBoxVisible(p.minBlockX()+1, p.minBlockY()+1, p.minBlockZ()+1,
// p.maxBlockX()-1, p.maxBlockY()-1, p.maxBlockZ()-1)) return true;
//}
//return false;
}).mapToObj((long l) -> {
return (AbstractChunkPosWrapper)factory.createChunkPos(l);
}).collect(Collectors.toCollection(HashSet::new));
}
}
@@ -0,0 +1,16 @@
package com.seibel.lod.fabric.wrappers.modAccessor;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
public class StarlightAccessor implements IStarlightAccessor {
@Override
public String getModName() {
return "Starlight-Fabric-1.18.X";
}
public StarlightAccessor() {
}
}
@@ -455,4 +455,4 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
@@ -2,12 +2,11 @@
"required": true,
"minVersion": "0.8",
"package": "com.seibel.lod.fabric.mixins",
"compatibilityLevel": "JAVA_16",
"compatibilityLevel": "JAVA_17",
"mixins": [
"events.MixinServerLevel",
"unsafe.MixinPalettedContainer",
"MixinChunkGenerator",
"MixinUtilBackgroudThread"
"unsafe.MixinThreadingDectector",
"MixinUtilBackgroudThread",
"events.MixinServerLevel"
],
"client": [
"MixinMinecraft",
@@ -18,8 +17,10 @@
"events.MixinMinecraft",
"events.MixinBlockUpdate"
],
"server": [],
"server": [
"MixinDedicatedServer"
],
"injectors": {
"defaultRequire": 1
}
}
}
+12 -10
View File
@@ -1,5 +1,5 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.0.0"
id "com.github.johnrengelman.shadow" version "7.1.0"
}
version = rootProject.mod_version+"-"+rootProject.minecraft_version+"-"+new Date().format("yyyy_MM_dd_HH_mm")
@@ -19,6 +19,12 @@ architectury {
forge()
}
configurations {
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentForge.extendsFrom common
}
def addMod(path, enabled) {
if (enabled == "2")
dependencies { modImplementation(path) }
@@ -26,21 +32,16 @@ def addMod(path, enabled) {
dependencies { modCompileOnly(path) }
}
configurations {
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentForge.extendsFrom common
}
dependencies {
// Forge loader
forge "net.minecraftforge:forge:${rootProject.minecraft_version}-${rootProject.forge_version}"
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowMe(project(path: ":common", configuration: "transformProductionForge")) { transitive = false }
// Starlight
addMod("curse.maven:starlight-forge-526854:${rootProject.starlight_version_forge}", rootProject.enable_starlight_forge)
annotationProcessor "org.spongepowered:mixin:0.8.4:processor"
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowMe(project(path: ":common", configuration: "transformProductionForge")) { transitive = false }
// forgeDependencies(project(":core")) { transitive false }
@@ -48,6 +49,7 @@ dependencies {
// Toml
shadowMe("com.electronwill.night-config:toml:${rootProject.toml_version}") {}
// Compression
forgeDependencies('org.tukaani:xz:1.9')
forgeDependencies('org.apache.commons:commons-compress:1.21')
shadowMe 'org.tukaani:xz:1.9'
@@ -23,6 +23,8 @@ import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.api.EventApi;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.entity.player.Player;
import org.lwjgl.glfw.GLFW;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
@@ -40,7 +42,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
/**
* This handles all events sent to the client,
* and is the starting point for most of the mod.
*
*
* @author James_Seibel
* @version 11-12-2021
*/
@@ -48,28 +50,28 @@ public class ForgeClientProxy
{
private final EventApi eventApi = EventApi.INSTANCE;
private final ClientApi clientApi = ClientApi.INSTANCE;
@SubscribeEvent
public void serverTickEvent(TickEvent.ServerTickEvent event)
{
if (event.phase != TickEvent.Phase.START) return;
eventApi.serverTickEvent();
}
@SubscribeEvent
public void chunkLoadEvent(ChunkEvent.Load event)
{
clientApi.clientChunkLoadEvent(new ChunkWrapper(event.getChunk(), event.getWorld()), WorldWrapper.getWorldWrapper(event.getWorld()));
}
@SubscribeEvent
public void worldSaveEvent(WorldEvent.Save event)
{
eventApi.worldSaveEvent();
}
/** This is also called when a new dimension loads */
@SubscribeEvent
public void worldLoadEvent(WorldEvent.Load event)
@@ -78,13 +80,13 @@ public class ForgeClientProxy
eventApi.worldLoadEvent(WorldWrapper.getWorldWrapper(event.getWorld()));
}
}
@SubscribeEvent
public void worldUnloadEvent(WorldEvent.Unload event)
{
eventApi.worldUnloadEvent(WorldWrapper.getWorldWrapper(event.getWorld()));
}
@SubscribeEvent
public void blockChangeEvent(BlockEvent event)
{
@@ -97,12 +99,12 @@ public class ForgeClientProxy
{
IChunkWrapper chunk = new ChunkWrapper(event.getWorld().getChunk(event.getPos()), event.getWorld());
DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(event.getWorld().dimensionType());
// recreate the LOD where the blocks were changed
eventApi.blockChangeEvent(chunk, dimType);
}
}
@SubscribeEvent
public void onKeyInput(InputEvent.KeyInputEvent event)
{
@@ -110,5 +112,7 @@ public class ForgeClientProxy
if (event.getAction() != GLFW.GLFW_PRESS) return;
clientApi.keyPressedEvent(event.getKey());
}
}
@@ -25,22 +25,20 @@ import com.seibel.lod.common.wrappers.config.ConfigGui;
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
import com.seibel.lod.core.handlers.ReflectionHandler;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.lod.forge.networking.NetworkHandler;
import com.seibel.lod.forge.wrappers.ForgeDependencySetup;
import com.seibel.lod.forge.wrappers.modAccessor.ModChecker;
import com.seibel.lod.forge.wrappers.modAccessor.OptifineAccessor;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.ConfigGuiHandler;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
@@ -48,7 +46,6 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fmlclient.ConfigGuiHandler;
import java.util.List;
import java.util.Random;
@@ -57,7 +54,7 @@ import java.util.Random;
* Initialize and setup the Mod. <br>
* If you are looking for the real start of the mod
* check out the ClientProxy.
*
*
* @author James Seibel
* @version 11-21-2021
*/
@@ -65,25 +62,22 @@ import java.util.Random;
public class ForgeMain implements LodForgeMethodCaller
{
public static ForgeClientProxy forgeClientProxy;
private void init(final FMLCommonSetupEvent event)
{
// make sure the dependencies are set up before the mod needs them
LodCommonMain.initConfig();
LodCommonMain.startup(this, !FMLLoader.getDist().isClient());
LodCommonMain.startup(this, !FMLLoader.getDist().isClient(), new NetworkHandler());
ForgeDependencySetup.createInitialBindings();
ForgeDependencySetup.finishBinding();
ApiShared.LOGGER.info("Distant Horizons initializing...");
}
public ForgeMain()
{
// Register the methods
// Register the methods for server and other game events we are interested in
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientStart);
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
}
private void onClientStart(final FMLClientSetupEvent event)
@@ -91,9 +85,9 @@ public class ForgeMain implements LodForgeMethodCaller
if (ReflectionHandler.instance.optifinePresent()) {
ModAccessorHandler.bind(IOptifineAccessor.class, new OptifineAccessor());
}
ModAccessorHandler.finishBinding();
ModAccessorHandler.finishBinding();
@@ -103,15 +97,9 @@ public class ForgeMain implements LodForgeMethodCaller
MinecraftForge.EVENT_BUS.register(forgeClientProxy);
}
private ModelDataMap dataMap = new ModelDataMap.Builder().build();
private final ModelDataMap dataMap = new ModelDataMap.Builder().build();
@Override
public List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random) {
return mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, dataMap);
}
@Override
public int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y) {
return sprite.getPixelRGBA(frameIndex, x, y);
}
}
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.client.networking.v1;
import java.util.List;
import com.seibel.lod.forge.fabric.api.event.Event;
import com.seibel.lod.forge.fabric.api.event.EventFactory;
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.resources.ResourceLocation;
/**
* Offers access to events related to the indication of a connected server's ability to receive packets in certain channels.
*/
public final class C2SPlayChannelEvents {
/**
* An event for the client play network handler receiving an update indicating the connected server's ability to receive packets in certain channels.
* This event may be invoked at any time after login and up to disconnection.
*/
public static final Event<Register> REGISTER = EventFactory.createArrayBacked(Register.class, callbacks -> (handler, sender, client, channels) -> {
for (Register callback : callbacks) {
callback.onChannelRegister(handler, sender, client, channels);
}
});
/**
* An event for the client play network handler receiving an update indicating the connected server's lack of ability to receive packets in certain channels.
* This event may be invoked at any time after login and up to disconnection.
*/
public static final Event<Unregister> UNREGISTER = EventFactory.createArrayBacked(Unregister.class, callbacks -> (handler, sender, client, channels) -> {
for (Unregister callback : callbacks) {
callback.onChannelUnregister(handler, sender, client, channels);
}
});
private C2SPlayChannelEvents() {
}
/**
* @see C2SPlayChannelEvents#REGISTER
*/
@FunctionalInterface
public interface Register {
void onChannelRegister(ClientPacketListener handler, PacketSender sender, Minecraft client, List<ResourceLocation> channels);
}
/**
* @see C2SPlayChannelEvents#UNREGISTER
*/
@FunctionalInterface
public interface Unregister {
void onChannelUnregister(ClientPacketListener handler, PacketSender sender, Minecraft client, List<ResourceLocation> channels);
}
}
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.client.networking.v1;
import com.seibel.lod.forge.fabric.api.event.Event;
import com.seibel.lod.forge.fabric.api.event.EventFactory;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
import net.minecraft.resources.ResourceLocation;
/**
* Offers access to events related to the connection to a server on the client while the server is processing the client's login request.
*/
public final class ClientLoginConnectionEvents {
/**
* Event indicating a connection entered the LOGIN state, ready for registering query request handlers.
* This event may be used by mods to prepare their client side state.
* This event does not guarantee that a login attempt will be successful.
*
* @see ClientLoginNetworking#registerReceiver(ResourceLocation, ClientLoginNetworking.LoginQueryRequestHandler)
*/
public static final Event<Init> INIT = EventFactory.createArrayBacked(Init.class, callbacks -> (handler, client) -> {
for (Init callback : callbacks) {
callback.onLoginStart(handler, client);
}
});
/**
* An event for when the client has started receiving login queries.
* A client can only start receiving login queries when a server has sent the first login query.
* Vanilla servers will typically never make the client enter this login phase, but it is not a guarantee that the
* connected server is a vanilla server since a modded server or proxy may have no login queries to send to the client
* and therefore bypass the login query phase.
* If this event is fired then it is a sign that a server is not a vanilla server or the server is behind a proxy which
* is capable of handling login queries.
*
* <p>This event may be used to {@link ClientLoginNetworking.LoginQueryRequestHandler register login query handlers}
* which may be used to send a response to a server.
*
* <p>No packets should be sent when this event is invoked.
*/
public static final Event<QueryStart> QUERY_START = EventFactory.createArrayBacked(QueryStart.class, callbacks -> (handler, client) -> {
for (QueryStart callback : callbacks) {
callback.onLoginQueryStart(handler, client);
}
});
/**
* An event for when the client's login process has ended due to disconnection.
*
* <p>No packets should be sent when this event is invoked.
*/
public static final Event<Disconnect> DISCONNECT = EventFactory.createArrayBacked(Disconnect.class, callbacks -> (handler, client) -> {
for (Disconnect callback : callbacks) {
callback.onLoginDisconnect(handler, client);
}
});
private ClientLoginConnectionEvents() {
}
/**
* @see ClientLoginConnectionEvents#INIT
*/
@FunctionalInterface
public interface Init {
void onLoginStart(ClientHandshakePacketListenerImpl handler, Minecraft client);
}
/**
* @see ClientLoginConnectionEvents#QUERY_START
*/
@FunctionalInterface
public interface QueryStart {
void onLoginQueryStart(ClientHandshakePacketListenerImpl handler, Minecraft client);
}
/**
* @see ClientLoginConnectionEvents#DISCONNECT
*/
@FunctionalInterface
public interface Disconnect {
void onLoginDisconnect(ClientHandshakePacketListenerImpl handler, Minecraft client);
}
}
@@ -0,0 +1,161 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.client.networking.v1;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.jetbrains.annotations.Nullable;
import com.seibel.lod.forge.fabric.api.networking.v1.ServerLoginNetworking;
import com.seibel.lod.forge.fabric.impl.networking.client.ClientNetworkingImpl;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
import net.minecraft.network.Connection;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.PacketListener;
import net.minecraft.resources.ResourceLocation;
/**
* Offers access to login stage client-side networking functionalities.
*
* <p>The Minecraft login protocol only allows the client to respond to a server's request, but not initiate one of its own.
*
* @see ClientPlayNetworking
* @see ServerLoginNetworking
*/
public final class ClientLoginNetworking {
/**
* Registers a handler to a query request channel.
* A global receiver is registered to all connections, in the present and future.
*
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
* Use {@link #unregisterGlobalReceiver(ResourceLocation)} to unregister the existing handler.
*
* @param channelName the id of the channel
* @param queryHandler the handler
* @return false if a handler is already registered to the channel
* @see ClientLoginNetworking#unregisterGlobalReceiver(ResourceLocation)
* @see ClientLoginNetworking#registerReceiver(ResourceLocation, LoginQueryRequestHandler)
*/
public static boolean registerGlobalReceiver(ResourceLocation channelName, LoginQueryRequestHandler queryHandler) {
return ClientNetworkingImpl.LOGIN.registerGlobalReceiver(channelName, queryHandler);
}
/**
* Removes the handler of a query request channel.
* A global receiver is registered to all connections, in the present and future.
*
* <p>The {@code channel} is guaranteed not to have a handler after this call.
*
* @param channelName the id of the channel
* @return the previous handler, or {@code null} if no handler was bound to the channel
* @see ClientLoginNetworking#registerGlobalReceiver(ResourceLocation, LoginQueryRequestHandler)
* @see ClientLoginNetworking#unregisterReceiver(ResourceLocation)
*/
@Nullable
public static ClientLoginNetworking.LoginQueryRequestHandler unregisterGlobalReceiver(ResourceLocation channelName) {
return ClientNetworkingImpl.LOGIN.unregisterGlobalReceiver(channelName);
}
/**
* Gets all query request channel names which global receivers are registered for.
* A global receiver is registered to all connections, in the present and future.
*
* @return all channel names which global receivers are registered for.
*/
public static Set<ResourceLocation> getGlobalReceivers() {
return ClientNetworkingImpl.LOGIN.getChannels();
}
/**
* Registers a handler to a query request channel.
*
* <p>If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made.
* Use {@link #unregisterReceiver(ResourceLocation)} to unregister the existing handler.
*
* @param channelName the id of the channel
* @param queryHandler the handler
* @return false if a handler is already registered to the channel name
* @throws IllegalStateException if the client is not logging in
*/
public static boolean registerReceiver(ResourceLocation channelName, LoginQueryRequestHandler queryHandler) throws IllegalStateException {
final Connection connection = ClientNetworkingImpl.getLoginConnection();
if (connection != null) {
final PacketListener packetListener = connection.getPacketListener();
if (packetListener instanceof ClientHandshakePacketListenerImpl) {
return ClientNetworkingImpl.getAddon(((ClientHandshakePacketListenerImpl) packetListener)).registerChannel(channelName, queryHandler);
}
}
throw new IllegalStateException("Cannot register receiver while client is not logging in!");
}
/**
* Removes the handler of a query request channel.
*
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
*
* @param channelName the id of the channel
* @return the previous handler, or {@code null} if no handler was bound to the channel name
* @throws IllegalStateException if the client is not logging in
*/
@Nullable
public static LoginQueryRequestHandler unregisterReceiver(ResourceLocation channelName) throws IllegalStateException {
final Connection connection = ClientNetworkingImpl.getLoginConnection();
if (connection != null) {
final PacketListener packetListener = connection.getPacketListener();
if (packetListener instanceof ClientHandshakePacketListenerImpl) {
return ClientNetworkingImpl.getAddon(((ClientHandshakePacketListenerImpl) packetListener)).unregisterChannel(channelName);
}
}
throw new IllegalStateException("Cannot unregister receiver while client is not logging in!");
}
private ClientLoginNetworking() {
}
@FunctionalInterface
public interface LoginQueryRequestHandler {
/**
* Handles an incoming query request from a server.
*
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
* Modification to the game should be {@linkplain net.minecraft.util.thread.BlockableEventLoop#submit(Runnable) scheduled} using the provided Minecraft client instance.
*
* <p>The return value of this method is a completable future that may be used to delay the login process to the server until a task {@link CompletableFuture#isDone() is done}.
* The future should complete in reasonably time to prevent disconnection by the server.
* If your request processes instantly, you may use {@link CompletableFuture#completedFuture(Object)} to wrap your response for immediate sending.
*
* @param client the client
* @param handler the network handler that received this packet
* @param buf the payload of the packet
* @param listenerAdder listeners to be called when the response packet is sent to the server
* @return a completable future which contains the payload to respond to the server with.
* If the future contains {@code null}, then the server will be notified that the client did not understand the query.
*/
CompletableFuture<@Nullable FriendlyByteBuf> receive(Minecraft client, ClientHandshakePacketListenerImpl handler, FriendlyByteBuf buf, Consumer<GenericFutureListener<? extends Future<? super Void>>> listenerAdder);
}
}
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.client.networking.v1;
import com.seibel.lod.forge.fabric.api.event.Event;
import com.seibel.lod.forge.fabric.api.event.EventFactory;
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.resources.ResourceLocation;
/**
* Offers access to events related to the connection to a server on a logical client.
*/
public final class ClientPlayConnectionEvents {
/**
* Event indicating a connection entered the PLAY state, ready for registering channel handlers.
*
* @see ClientPlayNetworking#registerReceiver(ResourceLocation, ClientPlayNetworking.PlayChannelHandler)
*/
public static final Event<Init> INIT = EventFactory.createArrayBacked(Init.class, callbacks -> (handler, client) -> {
for (Init callback : callbacks) {
callback.onPlayInit(handler, client);
}
});
/**
* An event for notification when the client play network handler is ready to send packets to the server.
*
* <p>At this stage, the network handler is ready to send packets to the server.
* Since the client's local state has been setup.
*/
public static final Event<Join> JOIN = EventFactory.createArrayBacked(Join.class, callbacks -> (handler, sender, client) -> {
for (Join callback : callbacks) {
callback.onPlayReady(handler, sender, client);
}
});
/**
* An event for the disconnection of the client play network handler.
*
* <p>No packets should be sent when this event is invoked.
*/
public static final Event<Disconnect> DISCONNECT = EventFactory.createArrayBacked(Disconnect.class, callbacks -> (handler, client) -> {
for (Disconnect callback : callbacks) {
callback.onPlayDisconnect(handler, client);
}
});
private ClientPlayConnectionEvents() {
}
@FunctionalInterface
public interface Init {
void onPlayInit(ClientPacketListener handler, Minecraft client);
}
@FunctionalInterface
public interface Join {
void onPlayReady(ClientPacketListener handler, PacketSender sender, Minecraft client);
}
@FunctionalInterface
public interface Disconnect {
void onPlayDisconnect(ClientPacketListener handler, Minecraft client);
}
}
@@ -0,0 +1,256 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.client.networking.v1;
import java.util.Objects;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
import com.seibel.lod.forge.fabric.api.networking.v1.ServerPlayNetworking;
import com.seibel.lod.forge.fabric.impl.networking.client.ClientNetworkingImpl;
import com.seibel.lod.forge.fabric.impl.networking.client.ClientPlayNetworkAddon;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
/**
* Offers access to play stage client-side networking functionalities.
*
* <p>Client-side networking functionalities include receiving clientbound packets,
* sending serverbound packets, and events related to client-side network handlers.
*
* <p>This class should be only used on the physical client and for the logical client.
*
* @see ClientLoginNetworking
* @see ServerPlayNetworking
*/
public final class ClientPlayNetworking {
/**
* Registers a handler to a channel.
* A global receiver is registered to all connections, in the present and future.
*
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
* Use {@link #unregisterGlobalReceiver(ResourceLocation)} to unregister the existing handler.
*
* @param channelName the id of the channel
* @param channelHandler the handler
* @return false if a handler is already registered to the channel
* @see ClientPlayNetworking#unregisterGlobalReceiver(ResourceLocation)
* @see ClientPlayNetworking#registerReceiver(ResourceLocation, PlayChannelHandler)
*/
public static boolean registerGlobalReceiver(ResourceLocation channelName, PlayChannelHandler channelHandler) {
return ClientNetworkingImpl.PLAY.registerGlobalReceiver(channelName, channelHandler);
}
/**
* Removes the handler of a channel.
* A global receiver is registered to all connections, in the present and future.
*
* <p>The {@code channel} is guaranteed not to have a handler after this call.
*
* @param channelName the id of the channel
* @return the previous handler, or {@code null} if no handler was bound to the channel
* @see ClientPlayNetworking#registerGlobalReceiver(ResourceLocation, PlayChannelHandler)
* @see ClientPlayNetworking#unregisterReceiver(ResourceLocation)
*/
@Nullable
public static PlayChannelHandler unregisterGlobalReceiver(ResourceLocation channelName) {
return ClientNetworkingImpl.PLAY.unregisterGlobalReceiver(channelName);
}
/**
* Gets all channel names which global receivers are registered for.
* A global receiver is registered to all connections, in the present and future.
*
* @return all channel names which global receivers are registered for.
*/
public static Set<ResourceLocation> getGlobalReceivers() {
return ClientNetworkingImpl.PLAY.getChannels();
}
/**
* Registers a handler to a channel.
*
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
* Use {@link #unregisterReceiver(ResourceLocation)} to unregister the existing handler.
*
* <p>For example, if you only register a receiver using this method when a {@linkplain ClientLoginNetworking#registerGlobalReceiver(ResourceLocation, ClientLoginNetworking.LoginQueryRequestHandler)}
* login query has been received, you should use {@link ClientPlayConnectionEvents#INIT} to register the channel handler.
*
* @param channelName the id of the channel
* @return false if a handler is already registered to the channel
* @throws IllegalStateException if the client is not connected to a server
* @see ClientPlayConnectionEvents#INIT
*/
public static boolean registerReceiver(ResourceLocation channelName, PlayChannelHandler channelHandler) {
final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon();
if (addon != null) {
return addon.registerChannel(channelName, channelHandler);
}
throw new IllegalStateException("Cannot register receiver while not in game!");
}
/**
* Removes the handler of a channel.
*
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
*
* @param channelName the id of the channel
* @return the previous handler, or {@code null} if no handler was bound to the channel
* @throws IllegalStateException if the client is not connected to a server
*/
@Nullable
public static PlayChannelHandler unregisterReceiver(ResourceLocation channelName) throws IllegalStateException {
final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon();
if (addon != null) {
return addon.unregisterChannel(channelName);
}
throw new IllegalStateException("Cannot unregister receiver while not in game!");
}
/**
* Gets all the channel names that the client can receive packets on.
*
* @return All the channel names that the client can receive packets on
* @throws IllegalStateException if the client is not connected to a server
*/
public static Set<ResourceLocation> getReceived() throws IllegalStateException {
final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon();
if (addon != null) {
return addon.getReceivableChannels();
}
throw new IllegalStateException("Cannot get a list of channels the client can receive packets on while not in game!");
}
/**
* Gets all channel names that the connected server declared the ability to receive a packets on.
*
* @return All the channel names the connected server declared the ability to receive a packets on
* @throws IllegalStateException if the client is not connected to a server
*/
public static Set<ResourceLocation> getSendable() throws IllegalStateException {
final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon();
if (addon != null) {
return addon.getSendableChannels();
}
throw new IllegalStateException("Cannot get a list of channels the server can receive packets on while not in game!");
}
/**
* Checks if the connected server declared the ability to receive a packet on a specified channel name.
*
* @param channelName the channel name
* @return True if the connected server has declared the ability to receive a packet on the specified channel.
* False if the client is not in game.
*/
public static boolean canSend(ResourceLocation channelName) throws IllegalArgumentException {
// You cant send without a client player, so this is fine
if (Minecraft.getInstance().getConnection() != null) {
return ClientNetworkingImpl.getAddon(Minecraft.getInstance().getConnection()).getSendableChannels().contains(channelName);
}
return false;
}
/**
* Creates a packet which may be sent to a the connected server.
*
* @param channelName the channel name
* @param buf the packet byte buf which represents the payload of the packet
* @return a new packet
*/
public static Packet<?> createC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
Objects.requireNonNull(channelName, "Channel name cannot be null");
Objects.requireNonNull(buf, "Buf cannot be null");
return ClientNetworkingImpl.createPlayC2SPacket(channelName, buf);
}
/**
* Gets the packet sender which sends packets to the connected server.
*
* @return the client's packet sender
* @throws IllegalStateException if the client is not connected to a server
*/
public static PacketSender getSender() throws IllegalStateException {
// You cant send without a client player, so this is fine
if (Minecraft.getInstance().getConnection() != null) {
return ClientNetworkingImpl.getAddon(Minecraft.getInstance().getConnection());
}
throw new IllegalStateException("Cannot get packet sender when not in game!");
}
/**
* Sends a packet to the connected server.
*
* @param channelName the channel of the packet
* @param buf the payload of the packet
* @throws IllegalStateException if the client is not connected to a server
*/
public static void send(ResourceLocation channelName, FriendlyByteBuf buf) throws IllegalStateException {
// You cant send without a client player, so this is fine
if (Minecraft.getInstance().getConnection() != null) {
Minecraft.getInstance().getConnection().send(createC2SPacket(channelName, buf));
return;
}
throw new IllegalStateException("Cannot send packets when not in game!");
}
private ClientPlayNetworking() {
}
@FunctionalInterface
public interface PlayChannelHandler {
/**
* Handles an incoming packet.
*
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
* Modification to the game should be {@linkplain net.minecraft.util.thread.BlockableEventLoop#submit(Runnable) scheduled} using the provided Minecraft client instance.
*
* <p>An example usage of this is to display an overlay message:
* <pre>{@code
* ClientPlayNetworking.registerReceiver(new Identifier("mymod", "overlay"), (client, handler, buf, responseSender) -&rt; {
* String message = buf.readString(32767);
*
* // All operations on the server or world must be executed on the server thread
* client.execute(() -&rt; {
* client.inGameHud.setOverlayMessage(message, true);
* });
* });
* }</pre>
* @param client the client
* @param handler the network handler that received this packet
* @param buf the payload of the packet
* @param responseSender the packet sender
*/
void receive(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender);
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The Networking API (client side), version 1.
*
* <p>For login stage networking see {@link net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking}.
* For play stage networking see {@link net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking}.
*
* <p>For events related to connection to a server see {@link net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents} for login stage
* or {@link net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents} for play stage.
*
* <p>For events related to the ability of a server to receive packets on a channel of a specific name see {@link net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents}.
*/
package com.seibel.lod.forge.fabric.api.client.networking.v1;
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.event;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates that this {@link Event} is auto-invoking:
* it calls the event callback implemented by a context parameter type automatically and without registration.
*
* <p>This means that this event can be listened to in two ways:
* <ul>
* <li>If the consumer is the context parameter and it implements the callback, it will be automatically invoked, don't register manually.
* <li>Otherwise, there is no invocation and the listener needs manual registration as usual.
* </ul>
*
* <p>Do note that there may be more than one context parameter.
*
* <p>A typical use case is feature augmentation, for example to expose raw clicks to slots.
* The event callback has a slot parameter - the context parameter - and the event itself is carrying this annotation.
* All the slot needs to receive slot clicks is to implement {@code SlotClickCallback} on itself.
* It shouldn't do any explicit event registration like {@code SLOT_CLICK_EVENT.register(this::onSlotClick)},
* otherwise it will see extraneous callback invocations.
*
* <p>In general, an auto-invoking event bridges the gap between the flexibility of an event with global reach,
* and the convenience of implementing an interface that gets detected automatically.
*
* <p>This is a documentation-only annotation, the event factory has to implement the functionality explicitly by checking the parameter type and invoking it.
* On top of adding this annotation, the event field or method should document which parameters are context parameters,
* and under which circumstances they are invoked.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface AutoInvokingEvent {
}
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.event;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.resources.ResourceLocation;
/**
* Base class for Fabric's event implementations.
*
* @param <T> The listener type.
* @see EventFactory
*/
@ApiStatus.NonExtendable // Should only be extended by fabric API.
public abstract class Event<T> {
/**
* The invoker field. This should be updated by the implementation to
* always refer to an instance containing all code that should be
* executed upon event emission.
*/
protected volatile T invoker;
/**
* Returns the invoker instance.
*
* <p>An "invoker" is an object which hides multiple registered
* listeners of type T under one instance of type T, executing
* them and leaving early as necessary.
*
* @return The invoker instance.
*/
public final T invoker() {
return invoker;
}
/**
* Register a listener to the event, in the default phase.
* Have a look at {@link #addPhaseOrdering} for an explanation of event phases.
*
* @param listener The desired listener.
*/
public abstract void register(T listener);
/**
* The ResourceLocation of the default phase.
* Have a look at {@link EventFactory#createWithPhases} for an explanation of event phases.
*/
public static final ResourceLocation DEFAULT_PHASE = new ResourceLocation("fabric", "default");
/**
* Register a listener to the event for the specified phase.
* Have a look at {@link EventFactory#createWithPhases} for an explanation of event phases.
*
* @param phase ResourceLocation of the phase this listener should be registered for. It will be created if it didn't exist yet.
* @param listener The desired listener.
*/
public void register(ResourceLocation phase, T listener) {
// This is done to keep compatibility with existing Event subclasses, but they should really not be subclassing Event.
register(listener);
}
/**
* Request that listeners registered for one phase be executed before listeners registered for another phase.
* Relying on the default phases supplied to {@link EventFactory#createWithPhases} should be preferred over manually
* registering phase ordering dependencies.
*
* <p>Incompatible ordering constraints such as cycles will lead to inconsistent behavior:
* some constraints will be respected and some will be ignored. If this happens, a warning will be logged.
*
* @param firstPhase The ResourceLocation of the phase that should run before the other. It will be created if it didn't exist yet.
* @param secondPhase The ResourceLocation of the phase that should run after the other. It will be created if it didn't exist yet.
*/
public void addPhaseOrdering(ResourceLocation firstPhase, ResourceLocation secondPhase) {
// This is not abstract to avoid breaking existing Event subclasses, but they should really not be subclassing Event.
}
}
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.event;
import java.util.function.Function;
import net.minecraft.resources.ResourceLocation;
import com.seibel.lod.forge.fabric.impl.base.event.EventFactoryImpl;
/**
* Helper for creating {@link Event} classes.
*/
public final class EventFactory {
private static boolean profilingEnabled = true;
private EventFactory() { }
/**
* @return True if events are supposed to be profiled.
*/
public static boolean isProfilingEnabled() {
return profilingEnabled;
}
/**
* Invalidate and re-create all existing "invoker" instances across
* events created by this EventFactory. Use this if, for instance,
* the profilingEnabled field changes.
*/
// TODO: Turn this into an event?
public static void invalidate() {
EventFactoryImpl.invalidate();
}
/**
* Create an "array-backed" Event instance.
*
* <p>If your factory simply delegates to the listeners without adding custom behavior,
* consider using {@linkplain #createArrayBacked(Class, Object, Function) the other overload}
* if performance of this event is critical.
*
* @param type The listener class type.
* @param invokerFactory The invoker factory, combining multiple listeners into one instance.
* @param <T> The listener type.
* @return The Event instance.
*/
public static <T> Event<T> createArrayBacked(Class<? super T> type, Function<T[], T> invokerFactory) {
return EventFactoryImpl.createArrayBacked(type, invokerFactory);
}
/**
* Create an "array-backed" Event instance with a custom empty invoker,
* for an event whose {@code invokerFactory} only delegates to the listeners.
* <ul>
* <li>If there is no listener, the custom empty invoker will be used.</li>
* <li><b>If there is only one listener, that one will be used as the invoker
* and the factory will not be called.</b></li>
* <li>Only when there are at least two listeners will the factory be used.</li>
* </ul>
*
* <p>Having a custom empty invoker (of type (...) -&gt; {}) increases performance
* relative to iterating over an empty array; however, it only really matters
* if the event is executed thousands of times a second.
*
* @param type The listener class type.
* @param emptyInvoker The custom empty invoker.
* @param invokerFactory The invoker factory, combining multiple listeners into one instance.
* @param <T> The listener type.
* @return The Event instance.
*/
public static <T> Event<T> createArrayBacked(Class<T> type, T emptyInvoker, Function<T[], T> invokerFactory) {
return createArrayBacked(type, listeners -> {
if (listeners.length == 0) {
return emptyInvoker;
} else if (listeners.length == 1) {
return listeners[0];
} else {
return invokerFactory.apply(listeners);
}
});
}
/**
* Create an array-backed event with a list of default phases that get invoked in order.
* Exposing the ResourceLocations of the default phases as {@code public static final} constants is encouraged.
*
* <p>An event phase is a named group of listeners, which may be ordered before or after other groups of listeners.
* This allows some listeners to take priority over other listeners.
* Adding separate events should be considered before making use of multiple event phases.
*
* <p>Phases may be freely added to events created with any of the factory functions,
* however using this function is preferred for widely used event phases.
* If more phases are necessary, discussion with the author of the Event is encouraged.
*
* <p>Refer to {@link Event#addPhaseOrdering} for an explanation of event phases.
*
* @param type The listener class type.
* @param invokerFactory The invoker factory, combining multiple listeners into one instance.
* @param defaultPhases The default phases of this event, in the correct order. Must contain {@link Event#DEFAULT_PHASE}.
* @param <T> The listener type.
* @return The Event instance.
*/
public static <T> Event<T> createWithPhases(Class<? super T> type, Function<T[], T> invokerFactory, ResourceLocation... defaultPhases) {
EventFactoryImpl.ensureContainsDefault(defaultPhases);
EventFactoryImpl.ensureNoDuplicates(defaultPhases);
Event<T> event = createArrayBacked(type, invokerFactory);
for (int i = 1; i < defaultPhases.length; ++i) {
event.addPhaseOrdering(defaultPhases[i-1], defaultPhases[i]);
}
return event;
}
/**
* Get the listener object name. This can be used in debugging/profiling
* scenarios.
*
* @param handler The listener object.
* @return The listener name.
*/
public static String getHandlerName(Object handler) {
return handler.getClass().getName();
}
}
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import com.seibel.lod.forge.fabric.api.event.Event;
import com.seibel.lod.forge.fabric.api.event.EventFactory;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
/**
* Events related to a tracking entities within a player's view distance.
*/
public final class EntityTrackingEvents {
/**
* An event that is called before player starts tracking an entity.
* Typically this occurs when an entity enters a client's view distance.
* This event is called before the player's client is sent the entity's {@link Entity#getAddEntityPacket() spawn packet}.
*/
public static final Event<StartTracking> START_TRACKING = EventFactory.createArrayBacked(StartTracking.class, callbacks -> (trackedEntity, player) -> {
for (StartTracking callback : callbacks) {
callback.onStartTracking(trackedEntity, player);
}
});
/**
* An event that is called after a player has stopped tracking an entity.
* The client at this point was sent a packet to {@link net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket destroy} the entity on the client.
* The entity still exists on the server.
*/
public static final Event<StopTracking> STOP_TRACKING = EventFactory.createArrayBacked(StopTracking.class, callbacks -> (trackedEntity, player) -> {
for (StopTracking callback : callbacks) {
callback.onStopTracking(trackedEntity, player);
}
});
@FunctionalInterface
public interface StartTracking {
/**
* Called before an entity starts getting tracked by a player.
*
* @param trackedEntity the entity that will be tracked
* @param player the player that will track the entity
*/
void onStartTracking(Entity trackedEntity, ServerPlayer player);
}
@FunctionalInterface
public interface StopTracking {
/**
* Called after an entity stops getting tracked by a player.
*
* @param trackedEntity the entity that is no longer being tracked
* @param player the player that is no longer tracking the entity
*/
void onStopTracking(Entity trackedEntity, ServerPlayer player);
}
private EntityTrackingEvents() {
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import java.util.Objects;
import net.minecraft.network.FriendlyByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalServerChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.GenericFutureListener;
/**
* Utilities for working with netty's future listeners.
* @see FutureListener
* @see ChannelFutureListener
*/
public final class FutureListeners {
/**
* Returns a future listener that releases a packet byte buf when the buffer has been sent to a remote connection.
*
* @param buf the buffer
* @return the future listener
*/
public static ChannelFutureListener free(FriendlyByteBuf buf) {
Objects.requireNonNull(buf, "PacketByteBuf cannot be null");
return (future) -> {
if (!isLocalChannel(future.channel())) {
buf.release();
}
};
}
/**
* Returns whether a netty channel performs local transportation, or if the message objects in the channel are directly passed than written to and read from a byte buf.
*
* @param channel the channel to check
* @return whether the channel is local
*/
public static boolean isLocalChannel(Channel channel) {
return channel instanceof LocalServerChannel || channel instanceof LocalChannel;
}
/**
* Combines two future listeners.
*
* @param first the first future listener
* @param second the second future listener
* @param <A> the future type of the first listener, used for casting
* @param <B> the future type of the second listener, used for casting
* @return the combined future listener.
*/
// A, B exist just to allow casting
@SuppressWarnings("unchecked")
public static <A extends Future<? super Void>, B extends Future<? super Void>> GenericFutureListener<? extends Future<? super Void>> union(GenericFutureListener<A> first, GenericFutureListener<B> second) {
// Return an empty future listener in the case of both parameters somehow being null
if (first == null && second == null) {
return future -> { };
}
if (first == null) {
return second;
}
if (second == null) {
return first;
}
return future -> {
first.operationComplete((A) future);
second.operationComplete((B) future);
};
}
private FutureListeners() {
}
}
@@ -0,0 +1,204 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import java.util.Objects;
import net.minecraft.network.FriendlyByteBuf;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
* Helper methods for working with and creating {@link FriendlyByteBuf}s.
*/
public final class PacketByteBufs {
private static final FriendlyByteBuf EMPTY_PACKET_BYTE_BUF = new FriendlyByteBuf(Unpooled.EMPTY_BUFFER);
/**
* Returns an empty instance of packet byte buf.
*
* @return an empty buf
*/
public static FriendlyByteBuf empty() {
return EMPTY_PACKET_BYTE_BUF;
}
/**
* Returns a new heap memory-backed instance of packet byte buf.
*
* @return a new buf
*/
public static FriendlyByteBuf create() {
return new FriendlyByteBuf(Unpooled.buffer());
}
// Convenience methods for byte buf methods that return a new byte buf
/**
* Wraps the newly created buf from {@code buf.readBytes} in a packet byte buf.
*
* @param buf the original buf
* @param length the number of bytes to transfer
* @return the transferred bytes
* @see ByteBuf#readBytes(int)
*/
public static FriendlyByteBuf readBytes(ByteBuf buf, int length) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.readBytes(length));
}
/**
* Wraps the newly created buf from {@code buf.readSlice} in a packet byte buf.
*
* @param buf the original buf
* @param length the size of the new slice
* @return the newly created slice
* @see ByteBuf#readSlice(int)
*/
public static FriendlyByteBuf readSlice(ByteBuf buf, int length) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.readSlice(length));
}
/**
* Wraps the newly created buf from {@code buf.readRetainedSlice} in a packet byte buf.
*
* @param buf the original buf
* @param length the size of the new slice
* @return the newly created slice
* @see ByteBuf#readRetainedSlice(int)
*/
public static FriendlyByteBuf readRetainedSlice(ByteBuf buf, int length) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.readRetainedSlice(length));
}
/**
* Wraps the newly created buf from {@code buf.copy} in a packet byte buf.
*
* @param buf the original buf
* @return a copy of the buf
* @see ByteBuf#copy()
*/
public static FriendlyByteBuf copy(ByteBuf buf) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.copy());
}
/**
* Wraps the newly created buf from {@code buf.copy} in a packet byte buf.
*
* @param buf the original buf
* @param index the starting index
* @param length the size of the copy
* @return a copy of the buf
* @see ByteBuf#copy(int, int)
*/
public static FriendlyByteBuf copy(ByteBuf buf, int index, int length) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.copy(index, length));
}
/**
* Wraps the newly created buf from {@code buf.slice} in a packet byte buf.
*
* @param buf the original buf
* @return a slice of the buf
* @see ByteBuf#slice()
*/
public static FriendlyByteBuf slice(ByteBuf buf) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.slice());
}
/**
* Wraps the newly created buf from {@code buf.retainedSlice} in a packet byte buf.
*
* @param buf the original buf
* @return a slice of the buf
* @see ByteBuf#retainedSlice()
*/
public static FriendlyByteBuf retainedSlice(ByteBuf buf) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.retainedSlice());
}
/**
* Wraps the newly created buf from {@code buf.slice} in a packet byte buf.
*
* @param buf the original buf
* @param index the starting index
* @param length the size of the copy
* @return a slice of the buf
* @see ByteBuf#slice(int, int)
*/
public static FriendlyByteBuf slice(ByteBuf buf, int index, int length) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.slice(index, length));
}
/**
* Wraps the newly created buf from {@code buf.retainedSlice} in a packet byte buf.
*
* @param buf the original buf
* @param index the starting index
* @param length the size of the copy
* @return a slice of the buf
* @see ByteBuf#retainedSlice(int, int)
*/
public static FriendlyByteBuf retainedSlice(ByteBuf buf, int index, int length) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.retainedSlice(index, length));
}
/**
* Wraps the newly created buf from {@code buf.duplicate} in a packet byte buf.
*
* @param buf the original buf
* @return a duplicate of the buf
* @see ByteBuf#duplicate()
*/
public static FriendlyByteBuf duplicate(ByteBuf buf) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.duplicate());
}
/**
* Wraps the newly created buf from {@code buf.retainedDuplicate} in a packet byte buf.
*
* @param buf the original buf
* @return a duplicate of the buf
* @see ByteBuf#retainedDuplicate()
*/
public static FriendlyByteBuf retainedDuplicate(ByteBuf buf) {
Objects.requireNonNull(buf, "ByteBuf cannot be null");
return new FriendlyByteBuf(buf.retainedDuplicate());
}
private PacketByteBufs() {
}
}
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import java.util.Objects;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
import io.netty.channel.ChannelFutureListener;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.jetbrains.annotations.Nullable;
/**
* Represents something that supports sending packets to channels.
* @see PacketByteBufs
*/
public interface PacketSender {
/**
* Makes a packet for a channel.
*
* @param channelName the id of the channel
* @param buf the content of the packet
*/
Packet<?> createPacket(ResourceLocation channelName, FriendlyByteBuf buf);
/**
* Sends a packet.
*
* @param packet the packet
*/
void sendPacket(Packet<?> packet);
/**
* Sends a packet.
*
* @param packet the packet
* @param callback an optional callback to execute after the packet is sent, may be {@code null}. The callback may also accept a {@link ChannelFutureListener}.
*/
void sendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback);
/**
* Sends a packet to a channel.
*
* @param channel the id of the channel
* @param buf the content of the packet
*/
default void sendPacket(ResourceLocation channel, FriendlyByteBuf buf) {
Objects.requireNonNull(channel, "Channel cannot be null");
Objects.requireNonNull(buf, "Payload cannot be null");
this.sendPacket(this.createPacket(channel, buf));
}
/**
* Sends a packet to a channel.
*
* @param channel the id of the channel
* @param buf the content of the packet
* @param callback an optional callback to execute after the packet is sent, may be {@code null}
*/
// the generic future listener can accept ChannelFutureListener
default void sendPacket(ResourceLocation channel, FriendlyByteBuf buf, @Nullable GenericFutureListener<? extends Future<? super Void>> callback) {
Objects.requireNonNull(channel, "Channel cannot be null");
Objects.requireNonNull(buf, "Payload cannot be null");
this.sendPacket(this.createPacket(channel, buf), callback);
}
}
@@ -0,0 +1,199 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.stream.Collectors;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerPlayerConnection;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.phys.Vec3;
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.EntityTrackerAccessor;
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.ThreadedAnvilChunkStorageAccessor;
/**
* For example, a block entity may use the methods in this class to send a packet to all clients which can see the block entity in order notify clients about a change.
*
* <p>The word "tracking" means that an entity/chunk on the server is known to a player's client (within in view distance) and the (block) entity should notify tracking clients of changes.
*
* <p>These methods should only be called on the server thread and only be used on logical a server.
*/
public final class PlayerLookup {
/**
* Gets all the players on the minecraft server.
*
* <p>The returned collection is immutable.
*
* @param server the server
* @return all players on the server
*/
public static Collection<ServerPlayer> all(MinecraftServer server) {
Objects.requireNonNull(server, "The server cannot be null");
// return an immutable collection to guard against accidental removals.
if (server.getPlayerList() != null) {
return Collections.unmodifiableCollection(server.getPlayerList().getPlayers());
}
return Collections.emptyList();
}
/**
* Gets all the players in a server world.
*
* <p>The returned collection is immutable.
*
* @param world the server world
* @return the players in the server world
*/
public static Collection<ServerPlayer> world(ServerLevel world) {
Objects.requireNonNull(world, "The world cannot be null");
// return an immutable collection to guard against accidental removals.
return Collections.unmodifiableCollection(world.players());
}
/**
* Gets all players tracking a chunk in a server world.
*
* @param world the server world
* @param pos the chunk in question
* @return the players tracking the chunk
*/
public static Collection<ServerPlayer> tracking(ServerLevel world, ChunkPos pos) {
Objects.requireNonNull(world, "The world cannot be null");
Objects.requireNonNull(pos, "The chunk pos cannot be null");
return world.getChunkSource().chunkMap.getPlayers(pos, false);
}
/**
* Gets all players tracking an entity in a server world.
*
* <p>The returned collection is immutable.
*
* <p><b>Warning</b>: If the provided entity is a player, it is not
* guaranteed by the contract that said player is included in the
* resulting stream.
*
* @param entity the entity being tracked
* @return the players tracking the entity
* @throws IllegalArgumentException if the entity is not in a server world
*/
public static Collection<ServerPlayer> tracking(Entity entity) {
Objects.requireNonNull(entity, "Entity cannot be null");
ChunkSource manager = entity.level.getChunkSource();
if (manager instanceof ServerChunkCache) {
ChunkMap storage = ((ServerChunkCache) manager).chunkMap;
EntityTrackerAccessor tracker = ((ThreadedAnvilChunkStorageAccessor) storage).getEntityMap().get(entity.getId());
// return an immutable collection to guard against accidental removals.
if (tracker != null) {
return Collections.unmodifiableCollection(tracker.getPlayersTracking()
.stream().map(ServerPlayerConnection::getPlayer).collect(Collectors.toSet()));
}
return Collections.emptySet();
}
throw new IllegalArgumentException("Only supported on server worlds!");
}
/**
* Gets all players tracking a block entity in a server world.
*
* @param blockEntity the block entity
* @return the players tracking the block position
* @throws IllegalArgumentException if the block entity is not in a server world
*/
public static Collection<ServerPlayer> tracking(BlockEntity blockEntity) {
Objects.requireNonNull(blockEntity, "BlockEntity cannot be null");
//noinspection ConstantConditions - IJ intrinsics don't know hasWorld == true will result in no null
if (!blockEntity.hasLevel() || blockEntity.getLevel().isClientSide()) {
throw new IllegalArgumentException("Only supported on server worlds!");
}
return tracking((ServerLevel) blockEntity.getLevel(), blockEntity.getBlockPos());
}
/**
* Gets all players tracking a block position in a server world.
*
* @param world the server world
* @param pos the block position
* @return the players tracking the block position
*/
public static Collection<ServerPlayer> tracking(ServerLevel world, BlockPos pos) {
Objects.requireNonNull(pos, "BlockPos cannot be null");
return tracking(world, new ChunkPos(pos));
}
/**
* Gets all players around a position in a world.
*
* <p>The distance check is done in the three-dimensional space instead of in the horizontal plane.
*
* @param world the world
* @param pos the position
* @param radius the maximum distance from the position in blocks
* @return the players around the position
*/
public static Collection<ServerPlayer> around(ServerLevel world, Vec3 pos, double radius) {
double radiusSq = radius * radius;
return world(world)
.stream()
.filter((p) -> p.distanceToSqr(pos) <= radiusSq)
.collect(Collectors.toList());
}
/**
* Gets all players around a position in a world.
*
* <p>The distance check is done in the three-dimensional space instead of in the horizontal plane.
*
* @param world the world
* @param pos the position (can be a block pos)
* @param radius the maximum distance from the position in blocks
* @return the players around the position
*/
public static Collection<ServerPlayer> around(ServerLevel world, Vec3i pos, double radius) {
double radiusSq = radius * radius;
return world(world)
.stream()
.filter((p) -> p.distanceToSqr(pos.getX(), pos.getY(), pos.getZ()) <= radiusSq)
.collect(Collectors.toList());
}
private PlayerLookup() {
}
}
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import java.util.List;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import com.seibel.lod.forge.fabric.api.event.Event;
import com.seibel.lod.forge.fabric.api.event.EventFactory;
/**
* Offers access to events related to the indication of a connected client's ability to receive packets in certain channels.
*/
public final class S2CPlayChannelEvents {
/**
* An event for the server play network handler receiving an update indicating the connected client's ability to receive packets in certain channels.
* This event may be invoked at any time after login and up to disconnection.
*/
public static final Event<Register> REGISTER = EventFactory.createArrayBacked(Register.class, callbacks -> (handler, sender, server, channels) -> {
for (Register callback : callbacks) {
callback.onChannelRegister(handler, sender, server, channels);
}
});
/**
* An event for the server play network handler receiving an update indicating the connected client's lack of ability to receive packets in certain channels.
* This event may be invoked at any time after login and up to disconnection.
*/
public static final Event<Unregister> UNREGISTER = EventFactory.createArrayBacked(Unregister.class, callbacks -> (handler, sender, server, channels) -> {
for (Unregister callback : callbacks) {
callback.onChannelUnregister(handler, sender, server, channels);
}
});
private S2CPlayChannelEvents() {
}
/**
* @see S2CPlayChannelEvents#REGISTER
*/
@FunctionalInterface
public interface Register {
void onChannelRegister(ServerGamePacketListenerImpl handler, PacketSender sender, MinecraftServer server, List<ResourceLocation> channels);
}
/**
* @see S2CPlayChannelEvents#UNREGISTER
*/
@FunctionalInterface
public interface Unregister {
void onChannelUnregister(ServerGamePacketListenerImpl handler, PacketSender sender, MinecraftServer server, List<ResourceLocation> channels);
}
}
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
import com.seibel.lod.forge.fabric.api.event.Event;
import com.seibel.lod.forge.fabric.api.event.EventFactory;
/**
* Offers access to events related to the connection to a client on a logical server while a client is logging in.
*/
public final class ServerLoginConnectionEvents {
/**
* Event indicating a connection entered the LOGIN state, ready for registering query response handlers.
*
* @see ServerLoginNetworking#registerReceiver(ServerLoginPacketListenerImpl, ResourceLocation, ServerLoginNetworking.LoginQueryResponseHandler)
*/
public static final Event<Init> INIT = EventFactory.createArrayBacked(Init.class, callbacks -> (handler, server) -> {
for (Init callback : callbacks) {
callback.onLoginInit(handler, server);
}
});
/**
* An event for the start of login queries of the server login network handler.
* This event may be used to register {@link ServerLoginNetworking.LoginQueryResponseHandler login query response handlers}
* using {@link ServerLoginNetworking#registerReceiver(ServerLoginPacketListenerImpl, ResourceLocation, ServerLoginNetworking.LoginQueryResponseHandler)}
* since this event is fired just before the first login query response is processed.
*
* <p>You may send login queries to the connected client using the provided {@link PacketSender}.
*/
public static final Event<QueryStart> QUERY_START = EventFactory.createArrayBacked(QueryStart.class, callbacks -> (handler, server, sender, synchronizer) -> {
for (QueryStart callback : callbacks) {
callback.onLoginStart(handler, server, sender, synchronizer);
}
});
/**
* An event for the disconnection of the server login network handler.
*
* <p>No packets should be sent when this event is invoked.
*/
public static final Event<Disconnect> DISCONNECT = EventFactory.createArrayBacked(Disconnect.class, callbacks -> (handler, server) -> {
for (Disconnect callback : callbacks) {
callback.onLoginDisconnect(handler, server);
}
});
private ServerLoginConnectionEvents() {
}
/**
* @see ServerLoginConnectionEvents#INIT
*/
@FunctionalInterface
public interface Init {
void onLoginInit(ServerLoginPacketListenerImpl handler, MinecraftServer server);
}
/**
* @see ServerLoginConnectionEvents#QUERY_START
*/
@FunctionalInterface
public interface QueryStart {
void onLoginStart(ServerLoginPacketListenerImpl handler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer synchronizer);
}
/**
* @see ServerLoginConnectionEvents#DISCONNECT
*/
@FunctionalInterface
public interface Disconnect {
void onLoginDisconnect(ServerLoginPacketListenerImpl handler, MinecraftServer server);
}
}
@@ -0,0 +1,196 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Future;
import org.jetbrains.annotations.Nullable;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientLoginNetworking;
import com.seibel.lod.forge.fabric.impl.networking.server.ServerNetworkingImpl;
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.ServerLoginNetworkHandlerAccessor;
/**
* Offers access to login stage server-side networking functionalities.
*
* <p>Server-side networking functionalities include receiving serverbound query responses and sending clientbound query requests.
*
* @see ServerPlayNetworking
* @see ClientLoginNetworking
*/
public final class ServerLoginNetworking {
/**
* Registers a handler to a query response channel.
* A global receiver is registered to all connections, in the present and future.
*
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
* Use {@link #unregisterGlobalReceiver(ResourceLocation)} to unregister the existing handler.
*
* @param channelName the id of the channel
* @param channelHandler the handler
* @return false if a handler is already registered to the channel
* @see ServerLoginNetworking#unregisterGlobalReceiver(ResourceLocation)
* @see ServerLoginNetworking#registerReceiver(ServerLoginPacketListenerImpl, ResourceLocation, LoginQueryResponseHandler)
*/
public static boolean registerGlobalReceiver(ResourceLocation channelName, LoginQueryResponseHandler channelHandler) {
return ServerNetworkingImpl.LOGIN.registerGlobalReceiver(channelName, channelHandler);
}
/**
* Removes the handler of a query response channel.
* A global receiver is registered to all connections, in the present and future.
*
* <p>The {@code channel} is guaranteed not to have a handler after this call.
*
* @param channelName the id of the channel
* @return the previous handler, or {@code null} if no handler was bound to the channel
* @see ServerLoginNetworking#registerGlobalReceiver(ResourceLocation, LoginQueryResponseHandler)
* @see ServerLoginNetworking#unregisterReceiver(ServerLoginPacketListenerImpl, ResourceLocation)
*/
@Nullable
public static ServerLoginNetworking.LoginQueryResponseHandler unregisterGlobalReceiver(ResourceLocation channelName) {
return ServerNetworkingImpl.LOGIN.unregisterGlobalReceiver(channelName);
}
/**
* Gets all channel names which global receivers are registered for.
* A global receiver is registered to all connections, in the present and future.
*
* @return all channel names which global receivers are registered for.
*/
public static Set<ResourceLocation> getGlobalReceivers() {
return ServerNetworkingImpl.LOGIN.getChannels();
}
/**
* Registers a handler to a query response channel.
*
* <p>If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made.
* Use {@link #unregisterReceiver(ServerLoginPacketListenerImpl, ResourceLocation)} to unregister the existing handler.
*
* @param networkHandler the handler
* @param channelName the id of the channel
* @param responseHandler the handler
* @return false if a handler is already registered to the channel name
*/
public static boolean registerReceiver(ServerLoginPacketListenerImpl networkHandler, ResourceLocation channelName, LoginQueryResponseHandler responseHandler) {
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(channelName, responseHandler);
}
/**
* Removes the handler of a query response channel.
*
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
*
* @param channelName the id of the channel
* @return the previous handler, or {@code null} if no handler was bound to the channel name
*/
@Nullable
public static ServerLoginNetworking.LoginQueryResponseHandler unregisterReceiver(ServerLoginPacketListenerImpl networkHandler, ResourceLocation channelName) {
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
return ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(channelName);
}
// Helper methods
/**
* Returns the <i>Minecraft</i> Server of a server login network handler.
*
* @param handler the server login network handler
*/
public static MinecraftServer getServer(ServerLoginPacketListenerImpl handler) {
Objects.requireNonNull(handler, "Network handler cannot be null");
return ((ServerLoginNetworkHandlerAccessor) handler).getServer();
}
private ServerLoginNetworking() {
}
@FunctionalInterface
public interface LoginQueryResponseHandler {
/**
* Handles an incoming query response from a client.
*
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
* Modification to the game should be {@linkplain net.minecraft.util.thread.BlockableEventLoop#submit(Runnable) scheduled} using the provided Minecraft client instance.
*
* <p><b>Whether the client understood the query should be checked before reading from the payload of the packet.</b>
* @param server the server
* @param handler the network handler that received this packet, representing the player/client who sent the response
* @param understood whether the client understood the packet
* @param buf the payload of the packet
* @param synchronizer the synchronizer which may be used to delay log-in till a {@link Future} is completed.
* @param responseSender the packet sender
*/
void receive(MinecraftServer server, ServerLoginPacketListenerImpl handler, boolean understood, FriendlyByteBuf buf, LoginSynchronizer synchronizer, PacketSender responseSender);
}
/**
* Allows blocking client log-in until all all futures passed into {@link LoginSynchronizer#waitFor(Future)} are completed.
*
* @apiNote this interface is not intended to be implemented by users of api.
*/
@FunctionalInterface
public interface LoginSynchronizer {
/**
* Allows blocking client log-in until the {@code future} is {@link Future#isDone() done}.
*
* <p>Since packet reception happens on netty's event loops, this allows handlers to
* perform logic on the Server Thread, etc. For instance, a handler can prepare an
* upcoming query request or check necessary login data on the server thread.</p>
*
* <p>Here is an example where the player log-in is blocked so that a credential check and
* building of a followup query request can be performed properly on the logical server
* thread before the player successfully logs in:
* <pre>{@code
* ServerLoginNetworking.registerGlobalReceiver(CHECK_CHANNEL, (server, handler, understood, buf, synchronizer, responseSender) -&gt; {
* if (!understood) {
* handler.disconnect(new LiteralText("Only accept clients that can check!"));
* return;
* }
*
* String checkMessage = buf.readString(32767);
*
* // Just send the CompletableFuture returned by the server's submit method
* synchronizer.waitFor(server.submit(() -&gt; {
* LoginInfoChecker checker = LoginInfoChecker.get(server);
*
* if (!checker.check(handler.getConnectionInfo(), checkMessage)) {
* handler.disconnect(new LiteralText("Invalid credentials!"));
* return;
* }
*
* responseSender.send(UPCOMING_CHECK, checker.buildSecondQueryPacket(handler, checkMessage));
* }));
* });
* }</pre>
* Usually it is enough to pass the return value for {@link net.minecraft.util.thread.BlockableEventLoop#submit(Runnable)} for {@code future}.</p>
*
* @param future the future that must be done before the player can log in
*/
void waitFor(Future<?> future);
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import com.seibel.lod.forge.fabric.api.event.Event;
import com.seibel.lod.forge.fabric.api.event.EventFactory;
/**
* Offers access to events related to the connection to a client on a logical server while a client is in game.
*/
public final class ServerPlayConnectionEvents {
/**
* Event indicating a connection entered the PLAY state, ready for registering channel handlers.
*
* @see ServerPlayNetworking#registerReceiver(ServerGamePacketListenerImpl, ResourceLocation, ServerPlayNetworking.PlayChannelHandler)
*/
public static final Event<Init> INIT = EventFactory.createArrayBacked(Init.class, callbacks -> (handler, server) -> {
for (Init callback : callbacks) {
callback.onPlayInit(handler, server);
}
});
/**
* An event for notification when the server play network handler is ready to send packets to the client.
*
* <p>At this stage, the network handler is ready to send packets to the client.
*/
public static final Event<Join> JOIN = EventFactory.createArrayBacked(Join.class, callbacks -> (handler, sender, server) -> {
for (Join callback : callbacks) {
callback.onPlayReady(handler, sender, server);
}
});
/**
* An event for the disconnection of the server play network handler.
*
* <p>No packets should be sent when this event is invoked.
*/
public static final Event<Disconnect> DISCONNECT = EventFactory.createArrayBacked(Disconnect.class, callbacks -> (handler, server) -> {
for (Disconnect callback : callbacks) {
callback.onPlayDisconnect(handler, server);
}
});
private ServerPlayConnectionEvents() {
}
@FunctionalInterface
public interface Init {
void onPlayInit(ServerGamePacketListenerImpl handler, MinecraftServer server);
}
@FunctionalInterface
public interface Join {
void onPlayReady(ServerGamePacketListenerImpl handler, PacketSender sender, MinecraftServer server);
}
@FunctionalInterface
public interface Disconnect {
void onPlayDisconnect(ServerGamePacketListenerImpl handler, MinecraftServer server);
}
}
@@ -0,0 +1,295 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
import java.util.Objects;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientPlayNetworking;
import com.seibel.lod.forge.fabric.impl.networking.server.ServerNetworkingImpl;
/**
* Offers access to play stage server-side networking functionalities.
*
* <p>Server-side networking functionalities include receiving serverbound packets, sending clientbound packets, and events related to server-side network handlers.
*
* <p>This class should be only used for the logical server.
*
* @see ServerLoginNetworking
* @see ClientPlayNetworking
*/
public final class ServerPlayNetworking {
/**
* Registers a handler to a channel.
* A global receiver is registered to all connections, in the present and future.
*
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
* Use {@link #unregisterReceiver(ServerGamePacketListenerImpl, ResourceLocation)} to unregister the existing handler.
*
* @param channelName the id of the channel
* @param channelHandler the handler
* @return false if a handler is already registered to the channel
* @see ServerPlayNetworking#unregisterGlobalReceiver(ResourceLocation)
* @see ServerPlayNetworking#registerReceiver(ServerGamePacketListenerImpl, ResourceLocation, PlayChannelHandler)
*/
public static boolean registerGlobalReceiver(ResourceLocation channelName, PlayChannelHandler channelHandler) {
return ServerNetworkingImpl.PLAY.registerGlobalReceiver(channelName, channelHandler);
}
/**
* Removes the handler of a channel.
* A global receiver is registered to all connections, in the present and future.
*
* <p>The {@code channel} is guaranteed not to have a handler after this call.
*
* @param channelName the id of the channel
* @return the previous handler, or {@code null} if no handler was bound to the channel
* @see ServerPlayNetworking#registerGlobalReceiver(ResourceLocation, PlayChannelHandler)
* @see ServerPlayNetworking#unregisterReceiver(ServerGamePacketListenerImpl, ResourceLocation)
*/
@Nullable
public static PlayChannelHandler unregisterGlobalReceiver(ResourceLocation channelName) {
return ServerNetworkingImpl.PLAY.unregisterGlobalReceiver(channelName);
}
/**
* Gets all channel names which global receivers are registered for.
* A global receiver is registered to all connections, in the present and future.
*
* @return all channel names which global receivers are registered for.
*/
public static Set<ResourceLocation> getGlobalReceivers() {
return ServerNetworkingImpl.PLAY.getChannels();
}
/**
* Registers a handler to a channel.
* This method differs from {@link ServerPlayNetworking#registerGlobalReceiver(ResourceLocation, PlayChannelHandler)} since
* the channel handler will only be applied to the player represented by the {@link ServerGamePacketListenerImpl}.
*
* <p>For example, if you only register a receiver using this method when a {@linkplain ServerLoginNetworking#registerGlobalReceiver(ResourceLocation, ServerLoginNetworking.LoginQueryResponseHandler)}
* login response has been received, you should use {@link ServerPlayConnectionEvents#INIT} to register the channel handler.
*
* <p>If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made.
* Use {@link #unregisterReceiver(ServerGamePacketListenerImpl, ResourceLocation)} to unregister the existing handler.
*
* @param networkHandler the handler
* @param channelName the id of the channel
* @param channelHandler the handler
* @return false if a handler is already registered to the channel name
* @see ServerPlayConnectionEvents#INIT
*/
public static boolean registerReceiver(ServerGamePacketListenerImpl networkHandler, ResourceLocation channelName, PlayChannelHandler channelHandler) {
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(channelName, channelHandler);
}
/**
* Removes the handler of a channel.
*
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
*
* @param channelName the id of the channel
* @return the previous handler, or {@code null} if no handler was bound to the channel name
*/
@Nullable
public static PlayChannelHandler unregisterReceiver(ServerGamePacketListenerImpl networkHandler, ResourceLocation channelName) {
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
return ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(channelName);
}
/**
* Gets all the channel names that the server can receive packets on.
*
* @param player the player
* @return All the channel names that the server can receive packets on
*/
public static Set<ResourceLocation> getReceived(ServerPlayer player) {
Objects.requireNonNull(player, "Server player entity cannot be null");
return getReceived(player.connection);
}
/**
* Gets all the channel names that the server can receive packets on.
*
* @param handler the network handler
* @return All the channel names that the server can receive packets on
*/
public static Set<ResourceLocation> getReceived(ServerGamePacketListenerImpl handler) {
Objects.requireNonNull(handler, "Server play network handler cannot be null");
return ServerNetworkingImpl.getAddon(handler).getReceivableChannels();
}
/**
* Gets all channel names that the connected client declared the ability to receive a packets on.
*
* @param player the player
* @return All the channel names the connected client declared the ability to receive a packets on
*/
public static Set<ResourceLocation> getSendable(ServerPlayer player) {
Objects.requireNonNull(player, "Server player entity cannot be null");
return getSendable(player.connection);
}
/**
* Gets all channel names that a the connected client declared the ability to receive a packets on.
*
* @param handler the network handler
* @return True if the connected client has declared the ability to receive a packet on the specified channel
*/
public static Set<ResourceLocation> getSendable(ServerGamePacketListenerImpl handler) {
Objects.requireNonNull(handler, "Server play network handler cannot be null");
return ServerNetworkingImpl.getAddon(handler).getSendableChannels();
}
/**
* Checks if the connected client declared the ability to receive a packet on a specified channel name.
*
* @param player the player
* @param channelName the channel name
* @return True if the connected client has declared the ability to receive a packet on the specified channel
*/
public static boolean canSend(ServerPlayer player, ResourceLocation channelName) {
Objects.requireNonNull(player, "Server player entity cannot be null");
return canSend(player.connection, channelName);
}
/**
* Checks if the connected client declared the ability to receive a packet on a specified channel name.
*
* @param handler the network handler
* @param channelName the channel name
* @return True if the connected client has declared the ability to receive a packet on the specified channel
*/
public static boolean canSend(ServerGamePacketListenerImpl handler, ResourceLocation channelName) {
Objects.requireNonNull(handler, "Server play network handler cannot be null");
Objects.requireNonNull(channelName, "Channel name cannot be null");
return ServerNetworkingImpl.getAddon(handler).getSendableChannels().contains(channelName);
}
/**
* Creates a packet which may be sent to a the connected client.
*
* @param channelName the channel name
* @param buf the packet byte buf which represents the payload of the packet
* @return a new packet
*/
public static Packet<?> createS2CPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
Objects.requireNonNull(channelName, "Channel cannot be null");
Objects.requireNonNull(buf, "Buf cannot be null");
return ServerNetworkingImpl.createPlayC2SPacket(channelName, buf);
}
/**
* Gets the packet sender which sends packets to the connected client.
*
* @param player the player
* @return the packet sender
*/
public static PacketSender getSender(ServerPlayer player) {
Objects.requireNonNull(player, "Server player entity cannot be null");
return getSender(player.connection);
}
/**
* Gets the packet sender which sends packets to the connected client.
*
* @param handler the network handler, representing the connection to the player/client
* @return the packet sender
*/
public static PacketSender getSender(ServerGamePacketListenerImpl handler) {
Objects.requireNonNull(handler, "Server play network handler cannot be null");
return ServerNetworkingImpl.getAddon(handler);
}
/**
* Sends a packet to a player.
*
* @param player the player to send the packet to
* @param channelName the channel of the packet
* @param buf the payload of the packet.
*/
public static void send(ServerPlayer player, ResourceLocation channelName, FriendlyByteBuf buf) {
Objects.requireNonNull(player, "Server player entity cannot be null");
Objects.requireNonNull(channelName, "Channel name cannot be null");
Objects.requireNonNull(buf, "Packet byte buf cannot be null");
player.connection.send(createS2CPacket(channelName, buf));
}
// Helper methods
/**
* Returns the <i>Minecraft</i> Server of a server play network handler.
*
* @param handler the server play network handler
*/
public static MinecraftServer getServer(ServerGamePacketListenerImpl handler) {
Objects.requireNonNull(handler, "Network handler cannot be null");
return handler.player.server;
}
private ServerPlayNetworking() {
}
@FunctionalInterface
public interface PlayChannelHandler {
/**
* Handles an incoming packet.
*
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
* Modification to the game should be {@linkplain net.minecraft.util.thread.BlockableEventLoop#submit(Runnable) scheduled} using the provided Minecraft server instance.
*
* <p>An example usage of this is to create an explosion where the player is looking:
* <pre>{@code
* ServerPlayNetworking.registerReceiver(new Identifier("mymod", "boom"), (server, player, handler, buf, responseSender) -&rt; {
* boolean fire = buf.readBoolean();
*
* // All operations on the server or world must be executed on the server thread
* server.execute(() -&rt; {
* ModPacketHandler.createExplosion(player, fire);
* });
* });
* }</pre>
* @param server the server
* @param player the player
* @param handler the network handler that received this packet, representing the player/client who sent the packet
* @param buf the payload of the packet
* @param responseSender the packet sender
*/
void receive(MinecraftServer server, ServerPlayer player, ServerGamePacketListenerImpl handler, FriendlyByteBuf buf, PacketSender responseSender);
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The Networking API, version 1.
*
* <p>For login stage networking see {@link net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking}.
* For play stage networking see {@link net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking}.
*
* <p>For events related to the connection to a client see {@link net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents} for login stage
* or {@link net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents} for play stage.
*
* <p>For events related to the ability of a client to receive packets on a channel of a specific name see {@link net.fabricmc.fabric.api.networking.v1.S2CPlayChannelEvents}.
*/
package com.seibel.lod.forge.fabric.api.networking.v1;
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.util;
/**
* Represents a function that accepts an boolean-valued argument and produces a result.
*
* <p>This is the {@code boolean}-consuming primitive specialization for {@link java.util.function.Function}.
*/
@FunctionalInterface
public interface BooleanFunction<R> {
/**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
R apply(boolean value);
}
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.util;
/**
* NBT type ID constants. Useful for filtering by value type in a few cases.
*
* <p>For the current list of types, check with {@link NbtElement#TYPES}.
*
* @see NbtCompound#contains(String, int)
* @see net.minecraft.nbt.NbtTypes#byId(int)
*/
public final class NbtType {
public static final int END = 0;
public static final int BYTE = 1;
public static final int SHORT = 2;
public static final int INT = 3;
public static final int LONG = 4;
public static final int FLOAT = 5;
public static final int DOUBLE = 6;
public static final int BYTE_ARRAY = 7;
public static final int STRING = 8;
public static final int LIST = 9;
public static final int COMPOUND = 10;
public static final int INT_ARRAY = 11;
public static final int LONG_ARRAY = 12;
/**
* Any numeric value: byte, short, int, long, float, double.
*
* @see NbtCompound#contains(String, int)
*/
public static final int NUMBER = 99;
private NbtType() { }
}
@@ -0,0 +1,139 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.api.util;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
/**
* Represents a boolean value which can be true, false or refer to a default value.
*/
public enum TriState {
/**
* Represents the boolean value of {@code false}.
*/
FALSE,
/**
* Represents a value that refers to a "default" value, often as a fallback.
*/
DEFAULT,
/**
* Represents the boolean value of {@code true}.
*/
TRUE;
/**
* Gets the corresponding tri-state from a boolean value.
*
* @param bool the boolean value
* @return {@link TriState#TRUE} or {@link TriState#FALSE} depending on the value of the boolean.
*/
public static TriState of(boolean bool) {
return bool ? TRUE : FALSE;
}
/**
* Gets a tri-state from a nullable boxed boolean.
*
* @param bool the boolean value
* @return {@link TriState#DEFAULT} if {@code null}.
* Otherwise {@link TriState#TRUE} or {@link TriState#FALSE} depending on the value of the boolean.
*/
public static TriState of(@Nullable Boolean bool) {
return bool == null ? DEFAULT : of(bool.booleanValue());
}
/**
* Gets the value of the tri-state.
*
* @return true if the tri-state is {@link TriState#TRUE}.
* Otherwise false.
*/
public boolean get() {
return this == TRUE;
}
/**
* Gets the value of the tri-state as a boxed, nullable boolean.
*
* @return {@code null} if {@link TriState#DEFAULT}.
* Otherwise {@code true} if {@link TriState#TRUE} or {@code false} if {@link TriState#FALSE}.
*/
@Nullable
public Boolean getBoxed() {
return this == DEFAULT ? null : this.get();
}
/**
* Gets the value of this tri-state.
* If the value is {@link TriState#DEFAULT} then use the supplied value.
*
* @param value the value to fallback to
* @return the value of the tri-state or the supplied value if {@link TriState#DEFAULT}.
*/
public boolean orElse(boolean value) {
return this == DEFAULT ? value : this.get();
}
/**
* Gets the value of this tri-state.
* If the value is {@link TriState#DEFAULT} then use the supplied value.
*
* @param supplier the supplier used to get the value to fallback to
* @return the value of the tri-state or the value of the supplier if the tri-state is {@link TriState#DEFAULT}.
*/
public boolean orElseGet(BooleanSupplier supplier) {
return this == DEFAULT ? supplier.getAsBoolean() : this.get();
}
/**
* Maps the boolean value of this tri-state if it is {@link TriState#TRUE} or {@link TriState#FALSE}.
*
* @param mapper the mapper to use
* @param <T> the type of object being supplier by the mapper
* @return an optional containing the mapped value; {@link Optional#empty()} if the tri-state is {@link TriState#DEFAULT} or the value provided by the mapper is {@code null}.
*/
public <T> Optional<T> map(BooleanFunction<@Nullable ? extends T> mapper) {
Objects.requireNonNull(mapper, "Mapper function cannot be null");
if (this == DEFAULT) {
return Optional.empty();
}
return Optional.ofNullable(mapper.apply(this.get()));
}
/**
* Gets the value of this tri-state, or throws an exception if this tri-state's value is {@link TriState#DEFAULT}.
*
* @param exceptionSupplier the supplying function that produces an exception to be thrown
* @param <X> Type of the exception to be thrown
* @return the value
* @throws X if the value is {@link TriState#DEFAULT}
*/
public <X extends Throwable> boolean orElseThrow(Supplier<X> exceptionSupplier) throws X {
if (this != DEFAULT) {
return this.get();
}
throw exceptionSupplier.get();
}
}
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.impl.base.event;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import net.minecraft.resources.ResourceLocation;
import com.seibel.lod.forge.fabric.api.event.Event;
class ArrayBackedEvent<T> extends Event<T> {
static final Logger LOGGER = LoggerFactory.getLogger("fabric-api-base");
private final Function<T[], T> invokerFactory;
private final Object lock = new Object();
private T[] handlers;
/**
* Registered event phases.
*/
private final Map<ResourceLocation, EventPhaseData<T>> phases = new LinkedHashMap<>();
/**
* Phases sorted in the correct dependency order.
*/
private final List<EventPhaseData<T>> sortedPhases = new ArrayList<>();
@SuppressWarnings("unchecked")
ArrayBackedEvent(Class<? super T> type, Function<T[], T> invokerFactory) {
this.invokerFactory = invokerFactory;
this.handlers = (T[]) Array.newInstance(type, 0);
update();
}
void update() {
this.invoker = invokerFactory.apply(handlers);
}
@Override
public void register(T listener) {
register(DEFAULT_PHASE, listener);
}
@Override
public void register(ResourceLocation phaseResourceLocation, T listener) {
Objects.requireNonNull(phaseResourceLocation, "Tried to register a listener for a null phase!");
Objects.requireNonNull(listener, "Tried to register a null listener!");
synchronized (lock) {
getOrCreatePhase(phaseResourceLocation, true).addListener(listener);
rebuildInvoker(handlers.length + 1);
}
}
private EventPhaseData<T> getOrCreatePhase(ResourceLocation id, boolean sortIfCreate) {
EventPhaseData<T> phase = phases.get(id);
if (phase == null) {
phase = new EventPhaseData<>(id, handlers.getClass().getComponentType());
phases.put(id, phase);
sortedPhases.add(phase);
if (sortIfCreate) {
PhaseSorting.sortPhases(sortedPhases);
}
}
return phase;
}
private void rebuildInvoker(int newLength) {
// Rebuild handlers.
if (sortedPhases.size() == 1) {
// Special case with a single phase: use the array of the phase directly.
handlers = sortedPhases.get(0).listeners;
} else {
@SuppressWarnings("unchecked")
T[] newHandlers = (T[]) Array.newInstance(handlers.getClass().getComponentType(), newLength);
int newHandlersIndex = 0;
for (EventPhaseData<T> existingPhase : sortedPhases) {
int length = existingPhase.listeners.length;
System.arraycopy(existingPhase.listeners, 0, newHandlers, newHandlersIndex, length);
newHandlersIndex += length;
}
handlers = newHandlers;
}
// Rebuild invoker.
update();
}
@Override
public void addPhaseOrdering(ResourceLocation firstPhase, ResourceLocation secondPhase) {
Objects.requireNonNull(firstPhase, "Tried to add an ordering for a null phase.");
Objects.requireNonNull(secondPhase, "Tried to add an ordering for a null phase.");
if (firstPhase.equals(secondPhase)) throw new IllegalArgumentException("Tried to add a phase that depends on itself.");
synchronized (lock) {
EventPhaseData<T> first = getOrCreatePhase(firstPhase, false);
EventPhaseData<T> second = getOrCreatePhase(secondPhase, false);
first.subsequentPhases.add(second);
second.previousPhases.add(first);
PhaseSorting.sortPhases(this.sortedPhases);
rebuildInvoker(handlers.length);
}
}
}
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.impl.base.event;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import net.minecraft.resources.ResourceLocation;
import com.seibel.lod.forge.fabric.api.event.Event;
public final class EventFactoryImpl {
private static final List<ArrayBackedEvent<?>> ARRAY_BACKED_EVENTS = new ArrayList<>();
private EventFactoryImpl() { }
public static void invalidate() {
ARRAY_BACKED_EVENTS.forEach(ArrayBackedEvent::update);
}
public static <T> Event<T> createArrayBacked(Class<? super T> type, Function<T[], T> invokerFactory) {
ArrayBackedEvent<T> event = new ArrayBackedEvent<>(type, invokerFactory);
ARRAY_BACKED_EVENTS.add(event);
return event;
}
public static void ensureContainsDefault(ResourceLocation[] defaultPhases) {
for (ResourceLocation id : defaultPhases) {
if (id.equals(Event.DEFAULT_PHASE)) {
return;
}
}
throw new IllegalArgumentException("The event phases must contain Event.DEFAULT_PHASE.");
}
public static void ensureNoDuplicates(ResourceLocation[] defaultPhases) {
for (int i = 0; i < defaultPhases.length; ++i) {
for (int j = i+1; j < defaultPhases.length; ++j) {
if (defaultPhases[i].equals(defaultPhases[j])) {
throw new IllegalArgumentException("Duplicate event phase: " + defaultPhases[i]);
}
}
}
}
// Code originally by sfPlayer1.
// Unfortunately, it's slightly slower than just passing an empty array in the first place.
private static <T> T buildEmptyInvoker(Class<T> handlerClass, Function<T[], T> invokerSetup) {
// find the functional interface method
Method funcIfMethod = null;
for (Method m : handlerClass.getMethods()) {
if ((m.getModifiers() & (Modifier.STRICT | Modifier.PRIVATE)) == 0) {
if (funcIfMethod != null) {
throw new IllegalStateException("Multiple virtual methods in " + handlerClass + "; cannot build empty invoker!");
}
funcIfMethod = m;
}
}
if (funcIfMethod == null) {
throw new IllegalStateException("No virtual methods in " + handlerClass + "; cannot build empty invoker!");
}
Object defValue = null;
try {
// concert to mh, determine its type without the "this" reference
MethodHandle target = MethodHandles.lookup().unreflect(funcIfMethod);
MethodType type = target.type().dropParameterTypes(0, 1);
if (type.returnType() != void.class) {
// determine default return value by invoking invokerSetup.apply(T[0]) with all-jvm-default args (null for refs, false for boolean, etc.)
// explicitCastArguments is being used to cast Object=null to the jvm default value for the correct type
// construct method desc (TLjava/lang/Object;Ljava/lang/Object;...)R where T = invoker ref ("this"), R = invoker ret type and args 1+ are Object for each non-"this" invoker arg
MethodType objTargetType = MethodType.genericMethodType(type.parameterCount()).changeReturnType(type.returnType()).insertParameterTypes(0, target.type().parameterType(0));
// explicit cast to translate to the invoker args from Object to their real type, inferring jvm default values
MethodHandle objTarget = MethodHandles.explicitCastArguments(target, objTargetType);
// build invocation args with 0 = "this", 1+ = null
Object[] args = new Object[target.type().parameterCount()];
//noinspection unchecked
args[0] = invokerSetup.apply((T[]) Array.newInstance(handlerClass, 0));
// retrieve default by invoking invokerSetup.apply(T[0]).targetName(def,def,...)
defValue = objTarget.invokeWithArguments(args);
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
final Object returnValue = defValue;
//noinspection unchecked
return (T) Proxy.newProxyInstance(EventFactoryImpl.class.getClassLoader(), new Class[]{handlerClass},
(proxy, method, args) -> returnValue);
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.impl.base.event;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.minecraft.resources.ResourceLocation;
/**
* Data of an {@link ArrayBackedEvent} phase.
*/
class EventPhaseData<T> {
final ResourceLocation id;
T[] listeners;
final List<EventPhaseData<T>> subsequentPhases = new ArrayList<>();
final List<EventPhaseData<T>> previousPhases = new ArrayList<>();
int visitStatus = 0; // 0: not visited, 1: visiting, 2: visited
@SuppressWarnings("unchecked")
EventPhaseData(ResourceLocation id, Class<?> listenerClass) {
this.id = id;
this.listeners = (T[]) Array.newInstance(listenerClass, 0);
}
void addListener(T listener) {
int oldLength = listeners.length;
listeners = Arrays.copyOf(listeners, oldLength + 1);
listeners[oldLength] = listener;
}
}
@@ -0,0 +1,164 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.impl.base.event;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import com.google.common.annotations.VisibleForTesting;
import org.jetbrains.annotations.ApiStatus;
/**
* Contains phase-sorting logic for {@link ArrayBackedEvent}.
*/
@ApiStatus.Internal
public class PhaseSorting {
@VisibleForTesting
public static boolean ENABLE_CYCLE_WARNING = true;
/**
* Deterministically sort a list of phases.
* 1) Compute phase SCCs (i.e. cycles).
* 2) Sort phases by id within SCCs.
* 3) Sort SCCs with respect to each other by respecting constraints, and by id in case of a tie.
*/
static <T> void sortPhases(List<EventPhaseData<T>> sortedPhases) {
// FIRST KOSARAJU SCC VISIT
List<EventPhaseData<T>> toposort = new ArrayList<>(sortedPhases.size());
for (EventPhaseData<T> phase : sortedPhases) {
forwardVisit(phase, null, toposort);
}
clearStatus(toposort);
Collections.reverse(toposort);
// SECOND KOSARAJU SCC VISIT
Map<EventPhaseData<T>, PhaseScc<T>> phaseToScc = new IdentityHashMap<>();
for (EventPhaseData<T> phase : toposort) {
if (phase.visitStatus == 0) {
List<EventPhaseData<T>> sccPhases = new ArrayList<>();
// Collect phases in SCC.
backwardVisit(phase, sccPhases);
// Sort phases by id.
sccPhases.sort(Comparator.comparing(p -> p.id));
// Mark phases as belonging to this SCC.
PhaseScc<T> scc = new PhaseScc<>(sccPhases);
for (EventPhaseData<T> phaseInScc : sccPhases) {
phaseToScc.put(phaseInScc, scc);
}
}
}
clearStatus(toposort);
// Build SCC graph
for (PhaseScc<T> scc : phaseToScc.values()) {
for (EventPhaseData<T> phase : scc.phases) {
for (EventPhaseData<T> subsequentPhase : phase.subsequentPhases) {
PhaseScc<T> subsequentScc = phaseToScc.get(subsequentPhase);
if (subsequentScc != scc) {
scc.subsequentSccs.add(subsequentScc);
subsequentScc.inDegree++;
}
}
}
}
// Order SCCs according to priorities. When there is a choice, use the SCC with the lowest id.
// The priority queue contains all SCCs that currently have 0 in-degree.
PriorityQueue<PhaseScc<T>> pq = new PriorityQueue<>(Comparator.comparing(scc -> scc.phases.get(0).id));
sortedPhases.clear();
for (PhaseScc<T> scc : phaseToScc.values()) {
if (scc.inDegree == 0) {
pq.add(scc);
// Prevent adding the same SCC multiple times, as phaseToScc may contain the same value multiple times.
scc.inDegree = -1;
}
}
while (!pq.isEmpty()) {
PhaseScc<T> scc = pq.poll();
sortedPhases.addAll(scc.phases);
for (PhaseScc<T> subsequentScc : scc.subsequentSccs) {
subsequentScc.inDegree--;
if (subsequentScc.inDegree == 0) {
pq.add(subsequentScc);
}
}
}
}
private static <T> void forwardVisit(EventPhaseData<T> phase, EventPhaseData<T> parent, List<EventPhaseData<T>> toposort) {
if (phase.visitStatus == 0) {
// Not yet visited.
phase.visitStatus = 1;
for (EventPhaseData<T> data : phase.subsequentPhases) {
forwardVisit(data, phase, toposort);
}
toposort.add(phase);
phase.visitStatus = 2;
} else if (phase.visitStatus == 1 && ENABLE_CYCLE_WARNING) {
// Already visiting, so we have found a cycle.
ArrayBackedEvent.LOGGER.warn(String.format(
"Event phase ordering conflict detected.%nEvent phase %s is ordered both before and after event phase %s.",
phase.id,
parent.id
));
}
}
private static <T> void clearStatus(List<EventPhaseData<T>> phases) {
for (EventPhaseData<T> phase : phases) {
phase.visitStatus = 0;
}
}
private static <T> void backwardVisit(EventPhaseData<T> phase, List<EventPhaseData<T>> sccPhases) {
if (phase.visitStatus == 0) {
phase.visitStatus = 1;
sccPhases.add(phase);
for (EventPhaseData<T> data : phase.previousPhases) {
backwardVisit(data, sccPhases);
}
}
}
private static class PhaseScc<T> {
final List<EventPhaseData<T>> phases;
final List<PhaseScc<T>> subsequentSccs = new ArrayList<>();
int inDegree = 0;
private PhaseScc(List<EventPhaseData<T>> phases) {
this.phases = phases;
}
}
}
@@ -0,0 +1,205 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seibel.lod.forge.fabric.impl.networking;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import io.netty.util.AsciiString;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.jetbrains.annotations.Nullable;
import com.seibel.lod.forge.fabric.api.networking.v1.PacketByteBufs;
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
import net.minecraft.ResourceLocationException;
import net.minecraft.network.Connection;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
/**
* A network addon which is aware of the channels the other side may receive.
*
* @param <H> the channel handler type
*/
public abstract class AbstractChanneledNetworkAddon<H> extends AbstractNetworkAddon<H> implements PacketSender {
protected final Connection connection;
protected final GlobalReceiverRegistry<H> receiver;
protected final Set<ResourceLocation> sendableChannels;
protected final Set<ResourceLocation> sendableChannelsView;
protected AbstractChanneledNetworkAddon(GlobalReceiverRegistry<H> receiver, Connection connection, String description) {
this(receiver, connection, new HashSet<>(), description);
}
protected AbstractChanneledNetworkAddon(GlobalReceiverRegistry<H> receiver, Connection connection, Set<ResourceLocation> sendableChannels, String description) {
super(receiver, description);
this.connection = connection;
this.receiver = receiver;
this.sendableChannels = sendableChannels;
this.sendableChannelsView = Collections.unmodifiableSet(sendableChannels);
}
public abstract void lateInit();
protected void registerPendingChannels(ChannelInfoHolder holder) {
final Collection<ResourceLocation> pending = holder.getPendingChannelsNames();
if (!pending.isEmpty()) {
register(new ArrayList<>(pending));
pending.clear();
}
}
// always supposed to handle async!
protected boolean handle(ResourceLocation channelName, FriendlyByteBuf originalBuf) {
this.logger.debug("Handling inbound packet from channel with name \"{}\"", channelName);
// Handle reserved packets
if (NetworkingImpl.REGISTER_CHANNEL.equals(channelName)) {
this.receiveRegistration(true, PacketByteBufs.slice(originalBuf));
return true;
}
if (NetworkingImpl.UNREGISTER_CHANNEL.equals(channelName)) {
this.receiveRegistration(false, PacketByteBufs.slice(originalBuf));
return true;
}
@Nullable H handler = this.getHandler(channelName);
if (handler == null) {
return false;
}
FriendlyByteBuf buf = PacketByteBufs.slice(originalBuf);
try {
this.receive(handler, buf);
} catch (Throwable ex) {
this.logger.error("Encountered exception while handling in channel with name \"{}\"", channelName, ex);
throw ex;
}
return true;
}
protected abstract void receive(H handler, FriendlyByteBuf buf);
protected void sendInitialChannelRegistrationPacket() {
final FriendlyByteBuf buf = this.createRegistrationPacket(this.getReceivableChannels());
if (buf != null) {
this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf);
}
}
@Nullable
protected FriendlyByteBuf createRegistrationPacket(Collection<ResourceLocation> channels) {
if (channels.isEmpty()) {
return null;
}
FriendlyByteBuf buf = PacketByteBufs.create();
boolean first = true;
for (ResourceLocation channel : channels) {
if (first) {
first = false;
} else {
buf.writeByte(0);
}
buf.writeBytes(channel.toString().getBytes(StandardCharsets.US_ASCII));
}
return buf;
}
// wrap in try with res (buf)
protected void receiveRegistration(boolean register, FriendlyByteBuf buf) {
List<ResourceLocation> ids = new ArrayList<>();
StringBuilder active = new StringBuilder();
while (buf.isReadable()) {
byte b = buf.readByte();
if (b != 0) {
active.append(AsciiString.b2c(b));
} else {
this.addId(ids, active);
active = new StringBuilder();
}
}
this.addId(ids, active);
this.schedule(register ? () -> register(ids) : () -> unregister(ids));
}
void register(List<ResourceLocation> ids) {
this.sendableChannels.addAll(ids);
this.invokeRegisterEvent(ids);
}
void unregister(List<ResourceLocation> ids) {
this.sendableChannels.removeAll(ids);
this.invokeUnregisterEvent(ids);
}
@Override
public void sendPacket(Packet<?> packet) {
Objects.requireNonNull(packet, "Packet cannot be null");
this.connection.send(packet);
}
@Override
public void sendPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> callback) {
Objects.requireNonNull(packet, "Packet cannot be null");
this.connection.send(packet, callback);
}
/**
* Schedules a task to run on the main thread.
*/
protected abstract void schedule(Runnable task);
protected abstract void invokeRegisterEvent(List<ResourceLocation> ids);
protected abstract void invokeUnregisterEvent(List<ResourceLocation> ids);
private void addId(List<ResourceLocation> ids, StringBuilder sb) {
String literal = sb.toString();
try {
ids.add(new ResourceLocation(literal));
} catch (ResourceLocationException ex) {
this.logger.warn("Received invalid channel identifier \"{}\" from connection {}", literal, this.connection);
}
}
public Set<ResourceLocation> getSendableChannels() {
return this.sendableChannelsView;
}
}

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