Compare commits

...

512 Commits

Author SHA1 Message Date
s809 7cd1a37914 Restore ordering of session config entries 2024-09-08 21:21:38 +05:00
s809 8ca2052748 Refactor session config 2024-09-08 19:05:42 +05:00
s809 576d0f5666 Fix crash on F3 when commit hash was failed to retrieve 2024-09-07 21:47:43 +05:00
s809 877588ebed Fix rare NPE when receiving LODs 2024-09-07 21:47:02 +05:00
s809 875b5fffcc Fix client crashing 2024-09-05 23:45:04 +05:00
s809 6293cc8c27 Prefill levelKeyPrefix in new worlds 2024-09-05 14:22:00 +05:00
s809 0361e5c69b Fix compilation 2024-09-04 22:53:02 +05:00
s809 654355c991 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into serverside 2024-09-04 18:22:47 +05:00
James Seibel 4712a77d00 Up version number 2.2.1 -> 2.2.2-dev 2024-09-04 06:58:59 -05:00
James Seibel 57c5b2d5fc Up version 2.2.1-dev -> 2.2.1 and API 3.0.0 -> 3.0.1 2024-09-04 06:58:20 -05:00
s809 a2949b8124 Change some string & remove unused config item 2024-09-03 16:52:10 +05:00
James Seibel 50c5701836 Fix referencing unavailable GLFW methods for MC 1.18.2 and lower 2024-09-02 08:00:43 -05:00
s809 6fe0477ca7 Limit number of retries on request errors
Add a delay if rate limit is hit
2024-09-02 15:31:39 +05:00
James Seibel 18e075538d Fix LODs flashing when moving and improve LodQuadTree code 2024-09-01 21:10:22 -05:00
James Seibel b00e8a08e9 add annotations to QuadTree 2024-09-01 21:09:50 -05:00
James Seibel ac4ab11a74 Fix LodRenderSection and QuadNode toString methods 2024-09-01 21:09:17 -05:00
James Seibel c26631db57 Cull beacons based on X/Z distance instead of 3D distance 2024-09-01 17:28:08 -05:00
James Seibel 1daa06fff4 Disable instanced rendering on Mac when Sodium is present
Closes !793 (Generic Rendering crashes with Sodium on M1 Mac)
2024-09-01 17:02:43 -05:00
James Seibel f3ef6f25f4 Fix some beacon rendering/updating issues 2024-09-01 16:36:37 -05:00
James Seibel ec012d9fd6 Fix glass panes not affecting beacon colors 2024-09-01 15:04:24 -05:00
James Seibel fc90cf3377 add disableUnchangedChunkCheck config 2024-08-31 22:11:25 -05:00
James Seibel e1e42d1caf Fix cloud color not matching MC 2024-08-31 21:55:54 -05:00
James Seibel 95ce29e355 Update all pos objects to use getters to match with DhBlockPos
I'd prefer not to need getters/setters since it's cleaner to just call pos.x, but that doesn't allow for immutable/mutable distinction.
2024-08-31 20:50:22 -05:00
James Seibel 0fd818b077 Allow users to re-activate DH rendering if a rendering error is thrown 2024-08-31 20:20:51 -05:00
James Seibel ba59daf747 Add beacon nearby culling 2024-08-31 20:20:24 -05:00
James Seibel b7d94c2ed1 Fix RenderableBoxGroup not supporting clear() 2024-08-31 20:06:04 -05:00
James Seibel 7a057a8d53 fix Lod builder not showing the correct stacktrace in Intellij 2024-08-31 15:04:30 -05:00
James Seibel 49c6ab97a9 Remove unused threadpool 2024-08-31 15:04:12 -05:00
James Seibel ed0d80b37e Reduce deplayed LOD modified save from 2 sec -> 500 ms
This should make some LOD update operations appear faster
2024-08-31 15:01:37 -05:00
James Seibel 9768728c92 Add RollingAverage object 2024-08-31 14:58:08 -05:00
James Seibel 0c68544f2f Fix DhLightingEngine putting lights at relative (0,0) and add debug logic 2024-08-31 12:45:39 -05:00
s809 048b36f80d Add comment 2024-08-31 20:50:50 +05:00
s809 40f902e2f5 Delay loading first level when on server 2024-08-31 20:46:58 +05:00
James Seibel b1f154a0ea Add DhBlockPosMutable and make the original immutable
This is to prevent issues with some methods accidentally mutating shared positions
2024-08-30 07:35:59 -05:00
James Seibel 628c9b071f DhBlockPos cleanup 2024-08-29 20:05:26 -05:00
James Seibel ed39b6181f Fix DH beacon detection logic mutating input block pos
alternate title: Fix DH beacon detection logic breaking the lighting engine
2024-08-29 19:54:36 -05:00
James Seibel 1d6d712483 Fix LODs not updating in the nether or when blocks are changed underground 2024-08-29 07:32:55 -05:00
s809 62ddb46674 Restore LOD fetching by distance 2024-08-29 17:09:08 +05:00
James Seibel 73c4f0ffcd Add a quick DH cloud UI config 2024-08-28 07:16:20 -05:00
s809 375cd44cbd Do not start generator until server responds with config 2024-08-27 16:35:22 +05:00
s809 ce057525d3 Show incompatible protocol version in F3 2024-08-27 16:02:15 +05:00
s809 01c879951c Fix sync on login 2024-08-26 16:53:59 +05:00
s809 4f19f05f3b Change naming of rate limit related items 2024-08-26 00:39:28 +05:00
s809 47f68c7ed3 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into serverside 2024-08-24 02:58:17 +05:00
s809 39db421aa1 Remove mentions of generation task priorities 2024-08-23 17:28:15 +05:00
s809 f4b0c08822 Fix network compression pool not shutting down 2024-08-23 17:11:32 +05:00
s809 f17c3fa267 "Fix" buffer release errors in FullDataPayload 2024-08-23 14:16:20 +05:00
James Seibel 48d1005be6 Up version number 2.2.0 -> 2.2.1-dev 2024-08-20 19:16:18 -05:00
James Seibel e71e8d1966 Up version number 2.1.3-dev -> 2.2.0 2024-08-20 17:44:41 -05:00
James Seibel 489b3d3ae1 Fix Legacy GL causing fog to smear 2024-08-20 17:44:41 -05:00
s809 81e6f55dbf Use same packet resource for all versions 2024-08-19 17:55:59 +05:00
James Seibel 1b162f10e6 Add sharedApi.isChunkAtChunkPosAlreadyUpdating() 2024-08-18 14:46:12 -05:00
James Seibel 301cce3d11 Remove unused chunkUnloadEvent 2024-08-18 14:25:51 -05:00
James Seibel e68d0d5c45 Fix fog and SSAO being broken by some mods 2024-08-17 22:29:28 -05:00
s809 b5e2019d28 Add logging of request group lifecycle 2024-08-15 15:46:24 +05:00
James Seibel 2cf952fb76 Deprecate IDhApiWorldGenerator.isBusy(), task queuing is now handled internally 2024-08-12 22:20:06 -05:00
James Seibel c7c5ab17bc Add optional DhApiChunk validation for world gen 2024-08-12 21:47:48 -05:00
James Seibel a98955530f Allow adding empty lists to DhApiChunk 2024-08-11 22:01:24 -05:00
James Seibel c63a509f9e Fix DhApiChunk setDataPoints failing for empty lists 2024-08-11 21:55:11 -05:00
s809 84dca85447 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into serverside 2024-08-11 20:59:23 +05:00
James Seibel dac51a9eea Add mod compat warning message config 2024-08-11 09:54:54 -05:00
s809 8c3e8136be Do not clear keyed level on close event 2024-08-10 23:53:22 +05:00
s809 606c157958 Make encode/decode error handling work correctly 2024-08-10 23:26:04 +05:00
s809 ba3677b641 Make error handling somewhat work 2024-08-10 19:49:33 +05:00
James Seibel 8d78a1ad74 Rename BeaconBeamDTO.pos -> blockPos 2024-08-09 07:25:49 -05:00
James Seibel 7c11bb4258 Fix beacons not enabling/disabling correctly 2024-08-09 07:25:24 -05:00
James Seibel 0d6ec3d836 Fix frustum culling when the screen is warped 2024-08-07 18:55:02 -05:00
s809 dee13a4ec4 Merge branch 'serverside-experimental/prevent-disconnects' into serverside 2024-08-07 22:20:29 +05:00
James Seibel 9449433fe8 Fix deleting beacons 2024-08-07 07:47:11 -05:00
James Seibel 2c976c9fb1 Improve fast chunk hash to respect surface block heights 2024-08-07 07:47:02 -05:00
James Seibel 90fdfbbe61 Fix direct memory leak and remove config for GpuUpload 2024-08-07 07:29:52 -05:00
James Seibel a8df13fdd2 Fix LodRenderSection holding onto unnecessary memory 2024-08-06 21:47:03 -05:00
James Seibel f05eac2637 test 2024-08-06 20:47:23 -05:00
s809 71e4cd6272 Fix real-time updates 2024-08-06 23:12:13 +05:00
s809 82c5de7dfe Fix Neoforge not being able to connect to vanilla servers 2024-08-05 14:51:17 +05:00
James Seibel 4ae30b3d47 Improve LOD detail level detection and hole filling 2024-08-04 08:30:58 -05:00
James Seibel 8abefdcfd5 Attempt to improve LOD building speed and reduce broken lighting on servers 2024-08-03 17:11:18 -05:00
James Seibel 801a126de0 Fix chunk has being saved before LOD update 2024-08-03 16:50:12 -05:00
James Seibel 377d0fbe12 Allow DhApiChunk to accept top down or bottom up data point orders 2024-08-03 09:32:57 -05:00
James Seibel 1ecf968668 Remove unused ChunkToLodBuilder 2024-08-03 09:32:29 -05:00
s809 9d11733444 Fix dimension switching (untested) 2024-08-03 15:42:43 +05:00
James Seibel c43b985f4e Fix off by 1 error in Render data transformer 2024-08-02 18:30:55 -05:00
James Seibel b7fea64925 Fix out of bounds exception in Full Data Transformer 2024-08-02 17:56:25 -05:00
s809 e62c6a5c55 [skip ci] Prevent disconnects on encode/decode/handle errors 2024-08-01 22:19:10 +05:00
James Seibel 116d7f4a3f Fix incorrect comment in DhSectionPos 2024-08-01 06:52:05 -05:00
James Seibel 0c36dc03a5 Fix cave culling affecting floating islands and add LOD reload to some configs 2024-07-31 19:06:44 -05:00
James Seibel c658269eb7 Remove deprecated methods and move method to StringUtil 2024-07-30 17:06:55 -05:00
James Seibel defaea86f0 Remove unused sodium and McRenderWrapper methods
Removed methods were originally used to cull LODs if MC had loaded chunks, however this turned out to be more trouble than it was worth and caused more problems than it solved.
2024-07-30 17:00:59 -05:00
James Seibel f1564cc90b Fix presets only using "custom" after any value was changed 2024-07-30 15:47:48 -05:00
James Seibel 66feb0b9c2 Fix SSAO shader crashing when entering empty config values 2024-07-30 15:35:01 -05:00
s809 93b57ae2e1 Increase defaults for network compression threads 2024-07-30 10:52:27 +05:00
James Seibel 79bfa21115 Fix default logging debug to file 2024-07-29 20:40:23 -05:00
James Seibel 5588b0d2fa Add TODO to cleanup LodRenderSection futures 2024-07-29 07:29:48 -05:00
James Seibel e9788acb46 Fix rapidly changing dimensions causing the game to crash 2024-07-29 07:13:06 -05:00
James Seibel 8056a5b8bf Add Buffer Builder/Uploader thread pools to the F3 menu 2024-07-29 07:08:42 -05:00
s809 e5033a0c0f Use FullDataPayload instead of reusing messages 2024-07-29 13:10:04 +05:00
James Seibel e0ad956e34 Fix incorrect DhApiChunk create constructor parameter order (again) 2024-07-28 20:18:15 -05:00
s809 32abe15b09 Add build number on F3 screen 2024-07-28 20:19:38 +05:00
s809 2b65e33aa7 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into serverside 2024-07-28 19:44:25 +05:00
James Seibel 9546f9cbc8 Close !66 (fix incorrect positions being fed into biome color code) 2024-07-28 09:33:24 -05:00
s809 bc6ab6c840 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into serverside 2024-07-28 19:01:28 +05:00
James Seibel 9834b20a9f Revert and Deprecate DhApiChunk and DhApiTerrainDataPoint constructors 2024-07-28 08:56:18 -05:00
James Seibel 752008e8ac Re-add deprecated IDhApiLevelWrapper.getHeight() 2024-07-28 08:55:54 -05:00
James Seibel fbe81021c0 Update API javadocs 2024-07-28 08:55:35 -05:00
s809 ccbb071704 Reapply "Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into serverside"
This reverts commit d26cb41048.
2024-07-28 17:05:58 +05:00
James Seibel 882c5399bd Fix holes in LODs boarding different detail levels 2024-07-27 21:06:50 -05:00
James Seibel dbe0461d5f Fix LOD upload warning 2024-07-27 20:25:55 -05:00
James Seibel d3d166dd02 Undo experimental change to LOD reloading 2024-07-27 20:11:28 -05:00
James Seibel d0dd1f38ff Fix LODs flashing twice when changing configs 2024-07-27 20:11:00 -05:00
James Seibel 53300a3028 Update IDhApiRenderProxy.clearRenderDataCache() to also clear cached block colors 2024-07-27 17:36:40 -05:00
James Seibel 56303dd82a level wrapper renamings 2024-07-27 16:51:08 -05:00
s809 d26cb41048 Revert "Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into serverside"
This reverts commit a15aaa573d, reversing
changes made to 83c1a2fd63.
2024-07-27 23:06:34 +05:00
s809 a15aaa573d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into serverside 2024-07-27 21:43:21 +05:00
James Seibel 19d8c89bd8 Fix ice/water vertical LOD lighting 2024-07-27 09:30:41 -05:00
James Seibel adba3e4c15 clear testing default debug config values 2024-07-27 08:40:59 -05:00
James Seibel 479ce8093e minor cleanup/refactor 2024-07-27 08:28:31 -05:00
James Seibel 1ed6c619d9 Add localization for new column builder debug options 2024-07-27 08:26:46 -05:00
Builderb0y 825f439ffb fix incorrect positions being fed into biome color code. 2024-07-27 02:32:31 +00:00
James Seibel b1b487e63f Improve RenderDataPointUtil toString() 2024-07-24 06:46:28 -05:00
James Seibel 2763a7ca75 add missing brackets 2024-07-23 20:41:22 -05:00
James Seibel b4b1a2a549 remove deprecated RenderDataPointUtil logic 2024-07-23 20:05:41 -05:00
James Seibel 5865317394 Remove deprecated LodQuadBuilder code 2024-07-23 19:53:13 -05:00
James Seibel b70c090e94 Refactor and cleanup buffer building 2024-07-23 19:39:44 -05:00
James Seibel a9f6b924c2 Move CubicLodTemplate to ColumnRenderBufferBuilder 2024-07-23 07:05:28 -05:00
James Seibel 9c25a6450a comment ColumnArrayView 2024-07-22 20:47:34 -05:00
James Seibel 448982fbaf refactor FullDataToRenderDataTransformer 2024-07-22 19:50:23 -05:00
James Seibel 2ee06c59f1 Add configs for testing the ColumnRenderBufferBuilder 2024-07-22 17:34:04 -05:00
James Seibel d38711ca4b Fix replay mod not showing LODs 2024-07-21 20:05:36 -05:00
James Seibel c9b650fb7f remove unused clientLevelWrapper.getGameDirectory() 2024-07-21 19:27:11 -05:00
James Seibel 3cef8b9a4f Improve cave culling and add config for ignored/cave blocks 2024-07-21 17:27:17 -05:00
James Seibel d9d9f3dad8 minor logging fixes 2024-07-21 17:06:58 -05:00
James Seibel 44fe1eafb1 Fix ConfigEntry String value saving 2024-07-21 16:09:46 -05:00
James Seibel 36fcc46445 Minor DataTransofmer refactor 2024-07-21 07:48:52 -05:00
James Seibel 64895ba521 Remove unnecessary suffix from SectionPos encode method 2024-07-21 07:42:40 -05:00
James Seibel 589340f2db Clean up SectionPos wording for chunk/block pos converters 2024-07-21 07:35:35 -05:00
James Seibel de7d22766a Fix RenderDataPointUtil.toString() ARGB order 2024-07-21 07:19:21 -05:00
James Seibel 568ff40df6 Fix API chunk world gen 2024-07-20 17:57:58 -05:00
s809 83c1a2fd63 Fix handler registration 2024-07-20 23:56:24 +05:00
James Seibel 17b5ba0ae1 Fix potential issues with WorldGenQueue not being marked as stopped
closes !61
2024-07-20 11:25:00 -05:00
James Seibel 4d4eeacbdd Add IDhApiWrapperFactory resourceLocation string methods for block/biomes 2024-07-20 11:20:48 -05:00
James Seibel 99dc644adf Add AbstractDhApiChunkWorldGenerator.generateApiChunk() 2024-07-20 10:45:43 -05:00
James Seibel f442ab56c0 Remove unnecessary glIsProgram() call 2024-07-18 07:40:04 -05:00
James Seibel 9147b139c7 Increase max VBO size 1 MB -> 10 MB 2024-07-18 07:39:52 -05:00
s809 0e904a388c Raise full data chunk size limit 2024-07-16 23:56:48 +05:00
s809 3723137fea Remove unused method 2024-07-16 23:52:28 +05:00
s809 71e54cc9ab Up protocol version 2024-07-16 23:51:30 +05:00
s809 b4cf962a85 Fix event handler registration 2024-07-16 23:40:20 +05:00
s809 1a30f240ef Client-side chunk handling 2024-07-16 17:49:09 +05:00
James Seibel 4f2b8e6d8d VBO handler commenting 2024-07-15 20:22:29 -05:00
s809 b3b5ac63c8 Server-side logic is pretty much finished 2024-07-16 00:27:22 +05:00
s809 16abc0faa1 [skip ci] Initial chunked full data message payloads 2024-07-15 07:57:20 +05:00
James Seibel 7165c086e4 Remove render param from DhApiAfterRenderEvent
This was causing confussion if deferred rendering (iris shaders) was enabled since the render parameters would change.
2024-07-14 09:30:56 -05:00
James Seibel fa22a4f27b Add a optional memory cache to the IDhApiTerrainDataRepo 2024-07-14 08:41:18 -05:00
James Seibel 9c0f5865f6 add missing genericRendering to IDhApiGraphicsConfig 2024-07-14 07:25:45 -05:00
James Seibel 1d0cb048cd Default logging to only write errors to chat 2024-07-13 12:54:21 -05:00
James Seibel 641d399a8e Merge branch 'distant-horizons-core-main' 2024-07-13 12:30:06 -05:00
James Seibel 32861e757d Add shader uniform "u" prefix 2024-07-13 12:04:05 -05:00
James Seibel 634738a1fc Remove minimum near fog distance and rename fog uniforms 2024-07-13 11:35:25 -05:00
James Seibel 859cbb6161 Fix fog reading/writing to the same buffer 2024-07-13 11:09:49 -05:00
James Seibel 6c960a81c0 testDisable beacon SSAO 2024-07-13 11:07:44 -05:00
James Seibel 1695c41ef2 Increase default fog start distance 2024-07-13 08:14:29 -05:00
James Seibel 8eabc6ad4c make clouds smaller and thinner 2024-07-12 21:47:06 -05:00
James Seibel a153ca1fe1 Fix repo connections not getting closed 2024-07-12 20:21:57 -05:00
James Seibel cab9f7c830 Clone API event parameters to reduce listener contamination 2024-07-12 19:22:20 -05:00
James Seibel 6bb832a488 Add renderEventParam to generic rendering shader binding by IMS request 2024-07-12 17:27:17 -05:00
s809 778c2f894e Fix level handling for real time updates 2024-07-12 23:11:36 +05:00
James Seibel e7dda9590a Add generic object setup/cleanup events 2024-07-12 07:15:57 -05:00
James Seibel 0483edd2f3 Fix material typo 2 2024-07-11 22:51:37 -05:00
James Seibel 122ef4dce0 Fix material typo 2024-07-11 22:07:09 -05:00
James Seibel e9d254f8c4 Add generic object materials 2024-07-11 18:12:58 -05:00
James Seibel 17aa85ad24 Add EDhApiBlockMaterial 2024-07-11 17:57:54 -05:00
James Seibel 8e1dfd688e Fix inverting gener rendering event cancling 2024-07-11 17:57:30 -05:00
James Seibel 691d5caded Add api for generic rendering config 2024-07-11 17:38:51 -05:00
James Seibel 31c089f82f Add DhApiBeforeGenericObjectRenderEvent 2024-07-11 17:32:17 -05:00
James Seibel 8eceeb0226 Add namespace/path to generic rendering (including F3 piechart) 2024-07-11 17:20:02 -05:00
James Seibel c178afa4b9 Minor refactoring/renaming 2024-07-11 16:40:32 -05:00
James Seibel 116df0d999 Add IDhApiGenericObjectShaderProgram 2024-07-11 16:35:38 -05:00
s809 2617cd294d Add cache for ignoring responses for cancelled requests 2024-07-11 23:06:23 +05:00
s809 43b421042d Add a comment to semaphores 2024-07-11 22:08:10 +05:00
s809 af69678545 Fix player tracking on server 2024-07-10 23:51:39 +05:00
James Seibel ef3cd4b43d Add "IP Only" to multiplayer tooltip 2024-07-10 07:45:07 -05:00
James Seibel 4b27f39a04 Fix generic rendering at extreme distances 2024-07-10 07:37:11 -05:00
James Seibel 53a2bf1748 mark ConfigLinkedEntry localization broken 2024-07-09 19:31:14 -05:00
James Seibel edec8bc0a2 Update localization 2024-07-09 19:30:59 -05:00
James Seibel 066b23c785 Add toggleable logging for GL Buffer garbage collection
Will need to be tested by someone who is experiencing issue #718, so far I've been unable to reproduce anything meaningful.
2024-07-09 17:40:21 -05:00
s809 85341f7a6d Add missing semaphore release 2024-07-09 18:06:16 +05:00
James Seibel 1f74f19cd9 minor cleanup 2024-07-09 07:49:56 -05:00
James Seibel 232c727b4f Move IBlockStateWrapper constants into LodUtil 2024-07-09 07:38:45 -05:00
James Seibel cd5da82d0c Add a TODO to LevelWrapper 2024-07-09 07:33:56 -05:00
James Seibel b762c0561d Add beacon colors 2024-07-09 07:33:17 -05:00
s809 9e0edd0cf3 Prevent request cancellation deadlock 2024-07-09 14:47:45 +05:00
James Seibel f144a9ebc1 Optimize beacon detection 2024-07-08 20:20:48 -05:00
James Seibel 29ef95387c Shrink cloud texture to improve performance 2024-07-08 19:56:20 -05:00
James Seibel 0d79a856b2 Add cloud greedy meshing 2024-07-08 18:45:42 -05:00
s809 84e90a7a9b Use dedicated thread pool for data compression 2024-07-08 23:07:58 +05:00
James Seibel bd5054e762 re-arrange the generic rendering config 2024-07-08 07:44:41 -05:00
James Seibel 63dea2515e Add generic rendering US localization 2024-07-08 07:42:56 -05:00
James Seibel baa89edd03 Add a few missing items from beacon render handler 2024-07-08 07:35:34 -05:00
James Seibel c45f9f442f Clean up beacon render handling logic 2024-07-08 07:32:29 -05:00
James Seibel 9e13b27197 Fix double unloading beacons 2024-07-07 19:54:17 -05:00
James Seibel 3c173685ea Fix beacons disappearing when unloading LODs 2024-07-07 19:45:27 -05:00
James Seibel 8eb70cbaed fix unloading chunks removing beacon beams 2024-07-07 19:18:40 -05:00
James Seibel 22167081f0 Fix generic render un-binding when moving between levels 2024-07-07 19:16:33 -05:00
James Seibel 23d07aa92d Disable cloud rendering if instanced rendering isn't available 2024-07-07 18:42:11 -05:00
James Seibel 578a9f9309 add directional shading to direct generic rendering 2024-07-07 18:31:43 -05:00
James Seibel bacdfa96e3 rename ILevelWrapper.getHeight -> getMaxHeight 2024-07-07 18:16:00 -05:00
James Seibel c73c3f8490 Add missing generic rendering config options 2024-07-07 18:11:18 -05:00
James Seibel f4a8bfeb0a Add cloud rendering 2024-07-07 18:02:43 -05:00
James Seibel 197e6e8178 add vec3f distance methods 2024-07-07 14:52:30 -05:00
s809 48a8cdc365 Disable parent update propagation 2024-07-07 19:46:47 +05:00
s809 171e6b9bcd Reset state of level detection on world exit 2024-07-07 01:49:44 +05:00
James Seibel c2c8bf8613 minor generic render refactor 2024-07-05 06:56:46 -05:00
James Seibel fce703579f Fix concurrent modification for GenericObjectRenderer 2024-07-04 21:41:57 -05:00
James Seibel e98f17f63b Remove useless IServerLevelWrapper.tryGetClientLevelWrapper() 2024-07-04 16:23:39 -05:00
James Seibel 120dddf844 Fix Api client level not containing the generic renderer 2024-07-04 16:14:32 -05:00
James Seibel ca711bbc72 Instance beacon rendering 2024-07-04 14:34:12 -05:00
James Seibel cc4cb10307 Fix uploading generic objects crashing 2024-07-04 14:34:01 -05:00
James Seibel 88db5c9594 re-add generic rendering to the API 2024-07-03 22:37:52 -05:00
James Seibel 81bfa9a02b Add generic rendering to the F3 menu 2024-07-03 20:46:11 -05:00
James Seibel ae72e627c5 Add a config to use pre-existing lighting 2024-07-03 20:30:49 -05:00
James Seibel 131b2835e5 Make generic renderer level dependent 2024-07-02 22:11:06 -05:00
James Seibel 5b905a9ab3 minor LodRenderer refactor 2024-07-02 19:23:02 -05:00
James Seibel e90c7cd8a0 Add beacon activation logic from merge 60
Closes !60
2024-07-02 17:50:25 -05:00
James Seibel 3b4a0ff4bc test 2024-07-02 17:08:55 -05:00
James Seibel 55cb4595bd Fix beacons un-loading incorrectly in some situations
Specifically neighboring chunks updating and in some cases flying away too fast
2024-07-02 07:50:21 -05:00
James Seibel e91afc17a3 Fix beacon beams for loaded chunks 2024-07-01 19:02:36 -05:00
James Seibel 6a398e6514 Start adding beacon beam repo handling 2024-07-01 07:51:08 -05:00
James Seibel 51de347bdd Add temporary proof-of-concept beacon rendering 2024-06-30 18:08:47 -05:00
James Seibel 72d6cb9697 Disable debug generic object rendering 2024-06-30 18:08:00 -05:00
James Seibel 4a025de9d6 Add generic object sky/block light 2024-06-30 17:45:50 -05:00
James Seibel 6c8060fa87 Up API version 2.1.0 -> 3.0.0 2024-06-30 16:33:54 -05:00
James Seibel 0c0987b66b Replace Vec3f and Mat4f in API with API versions 2024-06-30 16:33:38 -05:00
James Seibel 5a71e4015c Add javadocs to generic rendering objects 2024-06-30 15:28:00 -05:00
James Seibel f68edcbfea Add debug render code toggle 2024-06-30 14:38:35 -05:00
James Seibel aefa0d6797 generic renderable active flag and renaming cube -> box 2024-06-30 14:27:09 -05:00
s809 7e48c49e33 Make data source encoding lazy and move it off server thread 2024-07-01 00:15:54 +05:00
James Seibel 305a6bb459 Improve generic rendering pos objects 2024-06-30 14:02:44 -05:00
James Seibel 28c8614550 Store generic object instance VBOs if possible 2024-06-30 13:46:03 -05:00
s809 1b48d61d3f Rename CloseEvent 2024-06-30 22:35:41 +05:00
James Seibel f282d78fb9 minor generic obj cleanup 2024-06-30 09:31:45 -05:00
James Seibel 7f8b5579c5 Add generic rendering profilers and move some vertex attribs to uniforms 2024-06-30 09:25:12 -05:00
yeshi db786290e8 tell user to restart the game if the renderer dies 2024-06-29 21:56:38 +02:00
James Seibel 2c71d97c15 fix instanced generic duplicate rendering 2024-06-29 11:00:53 -06:00
James Seibel bf1361c7c3 GenericObjectRenderer forgot cached uniform location 2024-06-29 10:34:58 -06:00
James Seibel f2bba7f3df Add instanced and direct genericObject rendering 2024-06-29 10:29:30 -06:00
James Seibel 62e5183c54 Improve GLProxy creation validation/logging 2024-06-29 10:18:27 -06:00
James Seibel c1a90c9350 Add instanced generic object rendering 2024-06-29 09:11:49 -06:00
James Seibel 0d0826f319 Separate out Generic object rendering 2024-06-28 16:53:05 -06:00
s809 47541fa99c Move fixing the dimension name into even more correct place 2024-06-28 23:18:24 +05:00
s809 13638cedee Move fixing the dimension name into correct place 2024-06-28 19:28:36 +05:00
s809 4cdf31cfe8 Fix paths unable to be created on Windows 2024-06-28 17:25:09 +05:00
s809 3ff9a93066 Fix test compilation failing 2024-06-28 15:52:39 +05:00
s809 083a036666 Use level's ResourceLocation instead of dimension type's 2024-06-28 15:28:33 +05:00
James Seibel 6bfa3a422e Move generic cube rendering into it's own class 2024-06-27 06:36:30 -06:00
James Seibel 352abc40e6 Add proof-of-concept cube rendering 2024-06-27 06:22:15 -06:00
s809 a0efe44e8d Clean up package structure 2024-06-26 23:57:37 +05:00
James Seibel 58d26dedd6 Show overloaded message in chat and increase message timeout 5 -> 30 sec 2024-06-26 12:58:18 -05:00
s809 8d110e22dd Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into refactor/remove-tcp-connection 2024-06-26 15:13:03 +05:00
s809 4d6e11fdeb Fix compilation 2024-06-26 14:55:21 +05:00
s809 454b15ff60 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into refactor/remove-tcp-connection 2024-06-26 14:54:00 +05:00
James Seibel 321afa2a9e Up version 2.1.2 -> 2.1.3-dev 2024-06-25 19:25:30 -05:00
James Seibel 71ffbfb7b9 add "warning" to the low memory warning message 2024-06-25 19:24:07 -05:00
James Seibel 2ab7949ce5 Fix database file paths 2024-06-25 19:23:53 -05:00
James Seibel 28e1eaae77 Up version 2.1.1-dev -> 2.1.2 2024-06-24 20:53:36 -05:00
James Seibel 30dda058fe Throw an exception if the file handler can't read/write to the DB 2024-06-23 08:22:35 -05:00
James Seibel 0d16c037f5 Increase default world gen timeout to 3 minutes (from 60 sec) 2024-06-18 07:11:48 -05:00
James Seibel 7f50de17c0 Fix file handler tooltip 2024-06-17 07:40:49 -05:00
James Seibel 67819b30eb Improve F3 menu logic and visuals 2024-06-15 19:20:20 -05:00
s809 d2f4972693 Put messages received before player joining into queue 2024-06-16 00:45:16 +05:00
James Seibel ad38722304 add a todo to shared api 2024-06-15 11:26:46 -05:00
James Seibel 4da48c4c55 Lower the default CPU presets 2024-06-15 11:26:01 -05:00
James Seibel 6542e9e889 comment out unused showMigrationChatWarning 2024-06-15 11:04:56 -05:00
James Seibel 2f7e3d43d1 Add a startup low memory warning 2024-06-15 11:04:43 -05:00
James Seibel edaafb5cf0 Fix saving the chunk hash incorrectly 2024-06-15 10:37:59 -05:00
James Seibel 81d1ed419e Prevent creating LODs for already processed chunks 2024-06-15 09:42:43 -05:00
James Seibel 385e3dc964 Add ChunkWrapper BlockBiome HashCode 2024-06-15 08:11:16 -05:00
James Seibel 9592cd80f3 Improve position error logging 2024-06-15 07:20:38 -05:00
James Seibel 7b153a8aad Fix SelfUpdater list logging 2024-06-14 07:11:06 -05:00
s809 acb299530d Avoid reloading levels when unnecessary 2024-06-14 16:25:20 +05:00
James Seibel 54c2213eb6 Merge in JustALittleWolf's optimizations 2024-06-13 07:30:17 -05:00
s809 7c705015e6 Use level keys 2024-06-13 16:44:37 +05:00
JustAlittleWolf 1274a8e097 Directly access childNodes in LodQuadTree
This changes `LodQuadTree::recursivelyUpdateRenderSectionNode` to directly iterate on the children, instead of creating a childpositerator, and searching for the sectionpos. This lowers memory usage, as the iterators add quite a lot of object garbage (see https://i.imgur.com/r0qlxzc.png)
2024-06-13 13:15:39 +02:00
JustAlittleWolf bd1d0063e5 Change iterator Queue from LinkedList to ArrayDequeue
This improves performance and memory allocation, whenever the iterators are used. See https://docs.oracle.com/javase/8/docs/api/java/util/ArrayDeque.html
2024-06-13 13:14:30 +02:00
James Seibel af9b55ad6c Add lighting engine unit tests 2024-06-11 19:33:08 -05:00
James Seibel 97b86d69c4 Move shared ChunkWrapper code form Main to Core 2024-06-11 18:34:57 -05:00
James Seibel c6b4eacf03 Improve the overloaded chunk loading message 2024-06-11 07:35:28 -05:00
s809 bcb21be848 Show dimension names 2024-06-10 23:39:57 +05:00
s809 562594de2f Better error on invalid dimension 2024-06-09 22:01:30 +05:00
s809 03a00bb7ca Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into refactor/remove-tcp-connection 2024-06-09 21:18:08 +05:00
James Seibel e011ce3ee0 Remove OpenGL multithreading 2024-06-08 12:49:08 -05:00
James Seibel 1dd6359c89 Try changing LZMA preset from 4 -> 3 (faster, less compressed) 2024-06-08 11:06:26 -05:00
James Seibel e41abdd176 Improve config comment spacing 2024-06-08 08:33:32 -05:00
James Seibel b7a5bfd274 Add update branch config "auto" 2024-06-08 08:11:09 -05:00
James Seibel c3abfb123d Up the version number 2.1.0-a -> 2.1.1-a-dev 2024-06-07 17:42:36 -05:00
s809 dc3aa939db Fix logging errors 2024-06-08 00:07:24 +05:00
s809 39391b944f Add toString to messages & fix incorrect call 2024-06-06 21:25:19 +05:00
s809 a6fc8f1702 Fix compilation 2024-06-02 20:00:09 +05:00
s809 b0777789fd Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into refactor/remove-tcp-connection 2024-06-02 19:58:53 +05:00
s809 24a2a48deb Increase section reload delay 2024-06-01 19:49:23 +05:00
s809 e08faa7943 Fix requests breaking on rejoining 2024-06-01 12:17:04 +05:00
James Seibel 76f28e648c Up the version number 2.0.4-a-dev -> 2.1.0-a 2024-05-30 20:13:55 -05:00
s809 a000afbc60 Kinda works, rejoining is broken 2024-05-29 23:36:34 +05:00
James Seibel f49a79b54a remove unused lightmapBindingIndex in DhApiRenderParam 2024-05-27 17:57:45 -05:00
James Seibel 3cf385c2a2 Potentially fix memory leaks when rendering is disabled 2024-05-27 17:37:52 -05:00
s809 a3e34c9738 [skip ci] Still a mess 2024-05-27 22:01:57 +05:00
s809 1f63bdf124 [skip ci] Somewhere 2024-05-22 23:18:18 +05:00
s809 44205664b5 [skip ci] Incomplete 2024-05-21 22:54:57 +05:00
James Seibel 8c91a84795 Fix LZ4 in retail MC 2024-05-21 07:43:33 -05:00
James Seibel 4af63758f2 Add error logging to stream wrappers 2024-05-21 07:42:22 -05:00
James Seibel 969b02dc18 Put config button hide option only in file 2024-05-20 22:15:38 -05:00
Ran 2111ad64c4 Properly shade libraries when using Java version Ω 2024-05-21 02:09:04 +00:00
James Seibel e02deb2fb0 Merge branch 'main' into 'main'
thing part 2 (last mr didn't include core)

See merge request jeseibel/distant-horizons-core!57
2024-05-20 19:57:16 +00:00
Yeshi0 410e34b147 remove unnecessary reference to zstd 2024-05-20 17:53:02 +02:00
s809 40d019d7e8 Merge remote-tracking branch 'origin/main' 2024-05-18 22:14:19 +05:00
s809 96755e6174 Move overrides in LAN to config 2024-05-18 22:09:19 +05:00
James Seibel 9cebd7ee54 Add ConfigBasedLogger.errorAndThrow() 2024-05-18 08:07:41 -05:00
James Seibel cfec32746d Fix shading for MC 1.20.6 IE Java 21 2024-05-18 07:27:17 -05:00
s809 bd5866787f Update Config.java 2024-05-17 12:41:09 +00:00
s809 d9651bbd27 Merge branch 'main' into 'main'
rewrite config comments

See merge request s809/distant-horizons-core!1
2024-05-17 12:39:54 +00:00
James Seibel fabe5d77ea Merge branch 'SectionPosRewrite' 2024-05-16 22:15:03 -05:00
James Seibel c67712d973 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-05-15 18:57:53 -05:00
Yeshi0 a1f4442a53 rewrite config comments 2024-05-14 20:16:44 +02:00
s809 e6b140245b Fix awt dependency error 2024-05-12 17:34:58 +05:00
s809 08336027b2 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into feature/2.0.4 2024-05-11 19:16:01 +05:00
s809 543b5ed49a Fix dimension switching (at cost of breaking immersive portals) 2024-05-10 23:56:07 +05:00
s809 3d86c5c5ee Fix generated sections not appearing 2024-05-10 21:13:40 +05:00
s809 8e1009ab3f Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into feature/2.0.4 2024-05-05 19:51:21 +05:00
s809 551a5f1a72 Fix updates 2024-05-05 16:55:15 +05:00
James Seibel 7e45a98e8f Up the API version 1.1.0 -> 2.0.0
There were several breaking changes and I forgot to up the major version number appropriately.
2024-05-04 18:16:19 -05:00
s809 2664f96e0f Generation works, updates don't 2024-05-03 22:56:01 +05:00
s809 dde2bcc947 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-05-02 21:47:35 +05:00
s809 3e3e97385b Fix 1.16.5 and 1.17.1 builds 2024-04-17 21:02:14 +05:00
s809 05fba12038 Prevent generation when config is not acknowledged by server 2024-04-16 21:55:02 +05:00
s809 c1f2803c56 Add missing newlines for override configs 2024-04-16 21:39:56 +05:00
s809 7006c669f0 More verbose invalid level error 2024-04-16 21:38:37 +05:00
s809 7cd0c956f6 Fix IPv6 addresses not being properly handled 2024-04-16 21:27:26 +05:00
s809 7c33dda11b Add FlushConsolidationHandler 2024-04-16 20:32:50 +05:00
s809 5f9f0f23b8 Fix integer overflows 2024-04-12 23:14:58 +05:00
s809 284191a904 Fix Neoforge 2024-04-12 22:36:04 +05:00
s809 0ad60cd5d9 Merge branch 'feature/plugin-channel' 2024-04-02 22:34:45 +05:00
s809 8485d1585a Remove localhost from check 2024-04-02 22:27:36 +05:00
s809 1cd2f75dd2 Fix compilation 2024-04-01 21:52:20 +05:00
s809 bdc4fa4477 Fix errors when on vanilla server 2024-04-01 00:55:15 +05:00
s809 ff7720a8d6 Adjust server port change behavior 2024-04-01 00:07:32 +05:00
s809 6829709123 Fix reconnection logic 2024-03-30 23:40:05 +05:00
s809 0d355f675a Incomplete 2024-03-26 00:30:57 +05:00
s809 af2f0e8582 Fix Forge 2024-03-18 21:37:58 +05:00
s809 3362570123 Add thread pool task buildup limiter 2024-03-16 12:28:38 +05:00
s809 e008eb8a13 Server side plugin networking
Untested port for Forge
2024-03-14 21:46:23 +05:00
s809 1f438d8f87 Fix world setting 2024-03-10 21:09:52 +05:00
s809 278ae04532 Initial buggy plugin channel support 2024-03-05 22:09:30 +05:00
s809 2d4f033891 Do not wait for world gen tasks to stop while shutting down queue 2024-02-25 18:05:45 +05:00
s809 1fd85f2249 Show server side messages in F3 on disconnect 2024-02-24 22:48:24 +05:00
s809 d966697ecb Change some wording 2024-02-24 21:37:54 +05:00
s809 2e6c0ba356 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-02-22 23:06:21 +05:00
s809 ebb47990f4 Fix immersive portals 2024-02-15 23:15:01 +05:00
s809 15fe39c1bb Fix connection exception handling 2024-02-13 22:03:55 +05:00
s809 7bb0ec3148 Fix compilation 2024-02-12 21:39:30 +05:00
s809 6fcfacd346 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-02-12 21:38:58 +05:00
s809 48212ba746 Add another config option
Fix rate limiting issues (kinda)
2024-02-11 19:39:35 +05:00
s809 7bf9ce141a Avoid doing requests on join 2024-02-10 17:06:49 +05:00
s809 2353bd7545 Fix compilation 2024-02-07 21:03:37 +05:00
s809 02ddf5773c Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-02-07 20:49:49 +05:00
s809 3e37e9ee08 Remove unused packets 2024-02-04 21:57:57 +05:00
s809 b1b907bfe5 Silence a warning 2024-02-04 21:33:21 +05:00
s809 d347dbd222 Fix typo 2024-02-04 21:29:21 +05:00
s809 44527630da Fix queue not filled when generation is toggled 2024-02-04 21:00:02 +05:00
s809 df6ac6d740 Add connection state on F3 screen
Hide refresh queue from debug when disabled
2024-02-04 20:20:57 +05:00
s809 2ce08f8957 Merge remote-tracking branch 'origin/main' 2024-02-04 02:36:04 +05:00
s809 1baa666d23 Add priority distance limiting by ratio 2024-02-04 02:34:53 +05:00
s809 e5e4551038 Some logging changes 2024-02-03 23:02:31 +05:00
s809 0cfbe09558 Use ConfigBasedLogger
Add sub-sectioning to server networking section
2024-02-03 22:24:34 +05:00
s809 7d72e82325 Change a comment in Config 2024-02-03 20:17:21 +05:00
s809 3f823c58cc Fix exception while saving new data 2024-02-02 05:48:36 +00:00
s809 3932ea21c2 Limit rate+concurrency instead of only concurrency
Rename post-relog update to Login sync
2024-01-29 22:36:13 +05:00
s809 c9d426e581 Refactor ILevelRelatedMessage and RemotePlayerConnectionHandler 2024-01-28 22:37:50 +05:00
s809 61c516df1d Post-relog updates 2024-01-27 19:45:30 +05:00
s809 7e2019abd4 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-01-21 17:20:49 +05:00
s809 f0f3614b9d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-01-16 20:17:43 +05:00
s809 573a284580 Fix generation 2024-01-13 19:44:48 +05:00
s809 310c890474 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-01-13 16:51:12 +05:00
s809 8a309b56d9 Fix crash when changing config while disconnected 2024-01-13 16:08:49 +05:00
s809 adc3f15c97 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2024-01-08 17:50:00 +05:00
s809 962f523af9 Fix 1.16.5 and 1.17.1 builds 2024-01-05 22:37:27 +05:00
s809 dbc1ad4cb7 Add names to network threads 2024-01-05 22:08:37 +05:00
s809 8b0f6a4414 Daemonize timers 2024-01-05 22:08:16 +05:00
s809 502aaf6a8a Add a config to delay generation requests, for cases when gen tasks are not filled properly yet 2023-12-28 18:58:50 +05:00
s809 5c644fbf5b Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-12-24 19:16:03 +05:00
s809 da60ca7560 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-12-21 19:17:51 +05:00
s809 a5a56c7eb7 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-12-21 11:47:51 +05:00
s809 ff8b1f24d0 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-12-20 23:18:57 +05:00
s809 904c1a7d71 Add protection against hang on shutdown 2023-12-19 23:20:23 +05:00
s809 02aca6f044 Allow section state requests to be controlled separately 2023-12-19 22:52:19 +05:00
s809 b4ea632b93 Add kick trigger on repeated rate limit hitting
Remove some unused code
2023-12-18 23:10:39 +05:00
s809 a2cc1c2913 Revert "Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core"
This reverts commit 522a799516, reversing
changes made to 04e43ebec8.
2023-12-18 22:15:34 +05:00
s809 522a799516 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-12-18 19:17:14 +05:00
s809 04e43ebec8 Remove current post-relog update feature 2023-12-18 19:13:57 +05:00
s809 077d72c23b Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-12-15 20:29:15 +05:00
s809 cb95c45d76 Fix compilation 2023-12-06 22:06:37 +05:00
s809 a9de079132 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-12-06 21:09:19 +05:00
s809 166cc55e3c Abstract away ChannelHandlerContext from user code 2023-11-27 23:46:05 +05:00
s809 f36bffa4b7 Add missing config entries in chat commands 2023-11-26 21:32:50 +05:00
s809 6da1e75dad Fix server side generation setting being ignored 2023-11-25 18:04:25 +05:00
s809 82d66ca392 Basic chat commands 2023-11-25 17:44:51 +05:00
s809 e98cf1f2b5 Hide all unrelated config entries 2023-11-23 20:58:09 +05:00
s809 77bd333fff Fix RejectedExecutionException when leaving server 2023-11-20 17:18:05 +05:00
s809 b791a185a2 Deduplicate code in MultiplayerConfigChangeListener 2023-11-20 16:54:17 +05:00
s809 c64d7fedd2 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-11-19 22:56:56 +05:00
s809 d2f5c02238 Bandaid fix to prevent duplicate section requests 2023-11-12 17:17:15 +05:00
s809 9cfcf37fb3 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-11-11 19:20:33 +05:00
s809 84d36df388 Do not clean up rendering on a dedicated server 2023-11-04 16:56:15 +05:00
s809 880abd0124 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-11-03 21:05:27 +05:00
s809 72274bfd7d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-10-30 15:26:29 +05:00
s809 9640169be9 Make post-relog update independent from generation toggle 2023-10-23 23:18:52 +05:00
Steveplays28 9daf0c7317 chore: Add missing language entries for the server networking config 2023-10-20 14:07:42 +02:00
Steveplays28 a4df5a8ed8 style: Rename renderDistance to renderDistanceRadius to stay in sync with the main config 2023-10-20 14:03:19 +02:00
Steveplays28 df3d20f94e fix: Fix getting LOD render distance radius from the config
This config option was renamed recently, to fix LODs not rendering out to the LOD render distance border. Also removed an unused import.
2023-10-20 13:49:55 +02:00
Steveplays28 f3b40f51a2 Merge branch 'main-upstream'
# Conflicts:
#	core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java
#	core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
#	core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java
2023-10-20 13:41:33 +02:00
s809 e3d7598501 Fix compilation 2023-10-14 22:13:01 +05:00
s809 596b822a5d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-10-14 22:09:15 +05:00
s809 e9e7ac48b1 Fix compilation 2023-09-28 23:28:18 +05:00
s809 2e2254fbbd Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-09-28 22:54:35 +05:00
s809 8bda3351b8 Make worldGenLoopingQueue lock free 2023-09-27 21:40:59 +05:00
Steveplays28 532f3adba8 Merge branch 'main-upstream' 2023-09-27 14:09:04 +02:00
s809 cc8b97f2fe Improve management of frequent real time updates 2023-09-26 22:03:04 +05:00
s809 db31c54309 Fix Enable Distant Generation config being ignored 2023-09-26 13:21:37 +05:00
s809 375e81b17d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-09-26 11:40:38 +05:00
s809 4fb9126d49 Fix unloaded file check 2023-09-24 18:48:14 +05:00
Steveplays28 ed2fca240e fix: Fix compiling after merge 2023-09-24 11:33:49 +02:00
Steveplays28 f5549f2ebe Merge remote-tracking branch 'origin-core/main' 2023-09-24 11:28:38 +02:00
Steveplays28 18e9cfe2a5 Merge branch 'main-upstream' 2023-09-24 11:24:55 +02:00
s809 e4e6753a02 Add gen task rate display 2023-09-24 14:24:31 +05:00
Steveplays28 8e7855405d Merge remote-tracking branch 'origin-core/main' 2023-09-23 16:34:07 +02:00
Steveplays28 381cae7307 feat: Add config option for server port 2023-09-23 16:33:43 +02:00
s809 e94d67916d Fix compiling
Remove unused config category
Use pooling when receiving sections
Fix use of real time update config
Fix debug renderer not unregistered on queue close
2023-09-23 15:32:24 +05:00
Steveplays28 c98f9476cb Merge remote-tracking branch 'upstream-core/main'
# Conflicts:
#	core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiDebuggingConfig.java
#	core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java
#	core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java
#	core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java
#	core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java
#	core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java
#	core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java
2023-09-22 15:40:31 +02:00
s809 6c36f3c7e9 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-09-21 21:04:58 +05:00
s809 877a89d17a Add config for a few slow features 2023-09-21 21:00:23 +05:00
s809 d325a69e3f Move context levels to requests 2023-09-21 10:16:34 +05:00
s809 08704aad2c Allow selecting specific IDebugRenderable's for rendering 2023-09-19 21:32:59 +05:00
s809 a80bb082b3 Validate response types 2023-09-19 20:19:25 +05:00
s809 fccd197cd5 Fix chunk updates sent to incomplete connections
Hide useless warns, for cases when listener is not configured yet
2023-09-19 18:53:10 +05:00
s809 2cfc2c81c8 Fix future id collisions between c<->s
(cause of occasional hangs on disconnection)
Add packet trace logging
2023-09-19 17:28:26 +05:00
s809 6f4e105542 Fix compiling 2023-09-18 13:44:19 +05:00
s809 633b3f2033 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-09-18 13:24:43 +05:00
Steveplays28 f0a62c813a Merge remote-tracking branch 'upstream-core/main' 2023-09-12 17:35:29 +02:00
s809 21f03526f8 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-09-10 12:03:29 +05:00
Steveplays28 0e7a96d308 fix: Fix missing IServerKeyedClientLevel import 2023-09-09 21:03:17 +02:00
Steveplays28 87572246a6 Merge remote-tracking branch 'upstream-core/main' 2023-09-09 20:53:44 +02:00
Steveplays28 025484d5b4 Merge remote-tracking branch 'upstream-core/main' 2023-09-09 14:47:07 +02:00
Steveplays28 15e4b1316e Merge remote-tracking branch 'upstream-core/main' 2023-09-08 19:54:43 +02:00
s809 e02eddc60e Fix compiling 2023-09-07 21:07:16 +05:00
s809 1e1ddd505b Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-09-07 20:07:30 +05:00
s809 415f16507b Add post-rejoin updates 2023-09-02 01:23:56 +05:00
s809 cb95978502 Fix compilation 2023-08-27 19:56:12 +05:00
s809 1b729f3fe7 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-08-27 19:10:25 +05:00
s809 d84e097fa2 Merge branch 'client-level-error' of https://gitlab.com/s809/distant-horizons-core into client-level-error 2023-08-27 18:43:06 +05:00
s809 51ad901206 Fix loading ClientLevel on server 2023-08-27 18:41:47 +05:00
s809 517925a207 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-08-26 21:33:44 +05:00
s809 c5abc22c58 Merge branch 'feat/server-updates' 2023-08-24 00:01:07 +05:00
s809 2330377212 Send updates at chunk level instead of sections 2023-08-23 23:55:16 +05:00
s809 9db56bbf87 test 2023-08-22 20:41:42 +05:00
s809 52a90fec6c Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into feat/server-updates 2023-08-22 19:12:43 +05:00
Steveplays28 3630dc724d fix: Add null check to config GUI when adding a screen change listener 2023-08-22 10:52:19 +02:00
s809 627bfbc007 Incomplete 2023-08-21 22:08:35 +05:00
Steveplays28 d9283e938b feat: Update rendering block ignores
Barrier blocks, structure void blocks, light blocks, and air blocks now share 2 `HashMap`s that define blocks that should be ignored by the LOD builder.
2023-08-21 03:41:27 +02:00
s809 ce4d50654d Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-08-19 22:28:13 +05:00
s809 7568ab56f6 Fix hang when near completion of loading from server
Replace total value with sum of pending+finished requests
2023-08-19 22:21:01 +05:00
s809 bf58654a10 Fix prioritization not working properly 2023-08-19 21:22:51 +05:00
Steveplays28 e4576c7d51 Merge remote-tracking branch 'upstream-core/main' 2023-08-19 11:41:38 +02:00
Steveplays28 a1f07c075e Merge remote-tracking branch 'upstream-core/main' 2023-08-18 15:12:11 +02:00
s809 84c4ad6cdd Add missing level wrapper argument (and a bunch of null checks) 2023-08-18 15:04:59 +02:00
Steveplays28 47aef1f349 Merge remote-tracking branch 'upstream-core/main'
# Conflicts:
#	core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java
#	core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java
#	core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataFileHandler.java
#	core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java
#	core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
#	core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java
#	core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java
#	core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java
#	core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/NetworkEventSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/messages/AckMessage.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseReasonMessage.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/messages/HelloMessage.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/messages/PlayerUUIDMessage.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/messages/RemotePlayerConfigMessage.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/objects/RemotePlayer.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/protocol/EMessageHandlerSide.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkMessage.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageRegistry.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkChannelInitializer.java
#	core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkExceptionHandler.java
#	core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java
#	core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java
#	core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java
#	core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/misc/IServerPlayerWrapper.java
#	core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IBiomeWrapper.java
2023-08-16 11:36:00 +02:00
Steveplays28 1e7a25046a fix: Fix BlockStateWrapper and Biome serializing to empty strings 2023-08-15 00:03:13 +02:00
Steveplays28 87a9e93278 fix: Fix server trying to access client instance 2023-08-14 19:23:39 +02:00
Steveplays28 2d3062008e Merge remote-tracking branch 'upstream-core/main' 2023-08-14 15:40:41 +02:00
Steveplays28 8dcec7a1bd refactor: Re-add old serialization method
This is used by some override methods that don't have access to the level.
These old serialization methods have `FIXME`s so they're easy to find in the future.
2023-08-13 23:18:55 +02:00
Steveplays28 d839b6e4bd Merge remote-tracking branch 'upstream-core/main'
# Conflicts:
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java
#	core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java
2023-08-13 22:59:43 +02:00
s809 0c155ac8cd Generation task prioritization (loaded > unloaded > ungenerated) 2023-08-13 18:59:08 +05:00
s809 271b193543 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-08-13 01:53:06 +05:00
s809 e4ac25f4ce Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-08-08 20:57:30 +05:00
s809 52f9e3e9e4 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-08-08 12:35:21 +05:00
s809 6bf32ff85c Add debug renderer for remote generation queue 2023-08-05 22:30:33 +05:00
s809 9bd432ad7f Fix memory leak related to requests 2023-08-04 22:12:09 +05:00
s809 04fc4aa676 Remove unnecessary logging 2023-08-04 21:51:53 +05:00
s809 8ee4b8b4c9 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-08-04 21:10:41 +05:00
s809 5767668efa Somewhat proper request cancellation 2023-08-04 21:04:34 +05:00
s809 76b226b865 Fix switching dimensions (request cancellation is broken) 2023-08-04 13:06:56 +05:00
s809 1788c18d59 Everything I've done so far (not working/finished) 2023-08-01 22:31:16 +05:00
s809 2251cd4c25 Attempt to fix dimension switching 2023-08-01 17:04:40 +05:00
s809 781b588980 Implement server-side rate limiting 2023-08-01 12:55:36 +05:00
s809 74ac4fe64f Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-07-31 17:43:16 +05:00
s809 6d1f9803ce Avoid losing requests due to concurrency 2023-07-31 17:42:14 +05:00
s809 95d721e1a3 World generation 2023-07-31 15:23:56 +05:00
s809 d2f2a3b8aa Attempt to use GeneratedFullDataFileHandler 2023-07-24 19:59:16 +05:00
s809 768ce5b8fd something 2023-07-24 19:16:05 +05:00
s809 3e9f741d62 Implement transferring of missing full data source types 2023-07-24 14:15:03 +05:00
s809 133f007bde Fix mistake 2023-07-24 11:01:10 +05:00
s809 a623a3bfab Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-07-24 10:41:17 +05:00
s809 4157a39589 Somewhat working generation 2023-07-24 01:46:09 +05:00
s809 10e2873497 Downloads already visited chunks 2023-07-23 23:48:42 +05:00
s809 d7ef6c8a72 Got chunks to generate on server 2023-07-23 20:34:40 +05:00
s809 d29ba9d423 Requests now work properly
Merge request tracker into event source
2023-07-23 14:39:29 +05:00
s809 0c60395426 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-07-23 11:08:31 +05:00
s809 4ac1c0d4b3 Sending some responses
Rejoin is horribly broken
2023-07-19 22:29:33 +05:00
Steveplays28 9a0c9e9b7d feat: Implement syncing of DhSectionPos for chunk requests/responses 2023-07-19 16:48:43 +02:00
s809 79408c081a Close network request tacker properly 2023-07-19 17:40:38 +05:00
s809 218411902e Incomplete something 2023-07-19 15:54:17 +05:00
s809 a42f8367a4 Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-07-19 12:20:11 +05:00
s809 02acfaa3ed Finer control over message handling (untested) 2023-07-19 12:19:39 +05:00
s809 9a2799e83b Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core 2023-07-16 12:47:44 +05:00
s809 73e6ce75b0 Replace "tell version to client" part with simple ack because YAGNI 2023-07-16 12:38:32 +05:00
320 changed files with 15345 additions and 7582 deletions
+1 -1
View File
@@ -537,7 +537,7 @@ ij_groovy_wrap_chain_calls_after_dot = false
ij_groovy_wrap_long_lines = false ij_groovy_wrap_long_lines = false
[{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}] [{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}]
indent_size = 4 indent_size = 2
ij_json_array_wrapping = split_into_lines ij_json_array_wrapping = split_into_lines
ij_json_keep_blank_lines_in_code = 0 ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false ij_json_keep_indents_on_empty_lines = false
+1 -1
View File
@@ -3,7 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins { plugins {
id "java" id "java"
id "com.github.johnrengelman.shadow" version '7.1.2' apply false id "com.github.johnrengelman.shadow" version '8.1.1' apply false
} }
@@ -23,7 +23,9 @@ import com.seibel.distanthorizons.api.interfaces.events.IDhApiEventInjector;
import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory; import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory;
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGeneratorOverrideRegister; import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGeneratorOverrideRegister;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderObjectFactory;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy; import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.override.DhApiWorldGeneratorOverrideRegister; import com.seibel.distanthorizons.api.methods.override.DhApiWorldGeneratorOverrideRegister;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
@@ -123,10 +125,16 @@ public class DhApi
/** /**
* Used to create wrappers for Minecraft objects needed by other Distant Horizons API methods. * Used to create wrappers for Minecraft objects needed by other Distant Horizons API methods.
* @since API 1.1.0 * @since API 2.0.0
*/ */
public static IDhApiWrapperFactory wrapperFactory = null; public static IDhApiWrapperFactory wrapperFactory = null;
/**
* Used to create custom renderable objects. <br>
* These objects can be added to the renderer in {@link IDhApiLevelWrapper}
* @since API 3.0.0
*/
public static IDhApiCustomRenderObjectFactory customRenderObjectFactory = null;
} }
@@ -172,7 +180,7 @@ public class DhApi
* This version should be updated whenever non-breaking fixes are added to the Distant Horizons API. * This version should be updated whenever non-breaking fixes are added to the Distant Horizons API.
* @since API 1.0.0 * @since API 1.0.0
*/ */
public static int getApiPatchVersion() { return ModInfo.API_PATH_VERSION; } public static int getApiPatchVersion() { return ModInfo.API_PATCH_VERSION; }
/** /**
* Returns the mod's semantic version number in the format: Major.Minor.Patch * Returns the mod's semantic version number in the format: Major.Minor.Patch
@@ -198,8 +206,8 @@ public class DhApi
/** /**
* Returns true if the thread this method was called from is owned by Distant Horizons. * Returns true if the thread this method was called from is owned by Distant Horizons.
* @since API 1.1.0 * @since API 2.0.0
*/ */
public static boolean isDhThread() { return Thread.currentThread().getName().startsWith(ModInfo.THREAD_NAME_PREFIX); } public static boolean isDhThread() { return Thread.currentThread().getName().startsWith(ModInfo.THREAD_NAME_PREFIX); }
} }
@@ -24,7 +24,7 @@ package com.seibel.distanthorizons.api.enums;
* CHUNK - Detail Level: 4, width 16 block, <br> * CHUNK - Detail Level: 4, width 16 block, <br>
* REGION - Detail Level: 9, width 512 block <br> <br> * REGION - Detail Level: 9, width 512 block <br> <br>
* *
* Detail levels in Distant Horizons represent how large a section (of either LODs or MC chunks) * Detail levels in Distant Horizons represent how large a LOD
* is, with the smallest being 0 (1 block wide). <br> * is, with the smallest being 0 (1 block wide). <br>
* The width of a detail level can be calculated by putting the detail level to the power of 2. <br> * The width of a detail level can be calculated by putting the detail level to the power of 2. <br>
* Example for the chunk detail level (4): 2^4 = 16 blocks wide <Br><br> * Example for the chunk detail level (4): 2^4 = 16 blocks wide <Br><br>
@@ -23,7 +23,7 @@ package com.seibel.distanthorizons.api.enums.config;
* NONE, <br> * NONE, <br>
* NON_COLLIDING, <br> * NON_COLLIDING, <br>
* *
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiBlocksToAvoid public enum EDhApiBlocksToAvoid
@@ -22,14 +22,13 @@ package com.seibel.distanthorizons.api.enums.config;
/** /**
* UNCOMPRESSED <br> * UNCOMPRESSED <br>
* LZ4 <br> * LZ4 <br>
* ZSTD <br>
* XZ <br><br> * XZ <br><br>
* *
* Note: speed and compression ratios are examples * Note: speed and compression ratios are examples
* and should only be used for estimated comparisons. * and should only be used for estimated comparisons.
* *
* @version 2024-3-16 * @version 2024-3-16
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiDataCompressionMode public enum EDhApiDataCompressionMode
{ {
@@ -20,7 +20,7 @@
package com.seibel.distanthorizons.api.enums.config; package com.seibel.distanthorizons.api.enums.config;
/** /**
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiGLErrorHandlingMode public enum EDhApiGLErrorHandlingMode
@@ -20,7 +20,7 @@
package com.seibel.distanthorizons.api.enums.config; package com.seibel.distanthorizons.api.enums.config;
/** /**
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiGlProfileMode public enum EDhApiGlProfileMode
@@ -23,13 +23,12 @@ package com.seibel.distanthorizons.api.enums.config;
* AUTO, <br> * AUTO, <br>
* BUFFER_STORAGE, <br> * BUFFER_STORAGE, <br>
* SUB_DATA, <br> * SUB_DATA, <br>
* BUFFER_MAPPING, <br>
* DATA <br> * DATA <br>
* *
* @author Leetom * @author Leetom
* @author James Seibel * @author James Seibel
* @version 2024-4-6 * @version 2024-4-6
* @since API 1.1.0 * @since API 3.0.0
*/ */
public enum EDhApiGpuUploadMethod public enum EDhApiGpuUploadMethod
{ {
@@ -49,7 +48,10 @@ public enum EDhApiGpuUploadMethod
* May end up storing buffers in System memory. <br> * May end up storing buffers in System memory. <br>
* Fast rending if in GPU memory, slow if in system memory, <br> * Fast rending if in GPU memory, slow if in system memory, <br>
* but won't stutter when uploading. * but won't stutter when uploading.
*
* @deprecated not currently supported
*/ */
@Deprecated
BUFFER_MAPPING(true, false), BUFFER_MAPPING(true, false),
/** Fast rendering but may stutter when uploading. */ /** Fast rendering but may stutter when uploading. */
@@ -24,7 +24,7 @@ package com.seibel.distanthorizons.api.enums.config;
* FADE_TO_DIRT <br> * FADE_TO_DIRT <br>
* AS_DIRT <br> * AS_DIRT <br>
* *
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-7 * @version 2024-4-7
*/ */
public enum EDhApiGrassSideRendering public enum EDhApiGrassSideRendering
@@ -26,7 +26,7 @@ package com.seibel.distanthorizons.api.enums.config;
* HIGH <br> * HIGH <br>
* UNLIMITED <br> * UNLIMITED <br>
* *
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiHorizontalQuality public enum EDhApiHorizontalQuality
@@ -24,7 +24,7 @@ package com.seibel.distanthorizons.api.enums.config;
* ENABLED <br> * ENABLED <br>
* DISABLED <br> * DISABLED <br>
* *
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiLodShading public enum EDhApiLodShading
@@ -22,7 +22,7 @@ package com.seibel.distanthorizons.api.enums.config;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
/** /**
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiLoggerMode public enum EDhApiLoggerMode
@@ -33,7 +33,7 @@ import com.seibel.distanthorizons.coreapi.util.MathUtil;
* *
* @author James Seibel * @author James Seibel
* @author Leonardo Amato * @author Leonardo Amato
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiMaxHorizontalResolution public enum EDhApiMaxHorizontalResolution
@@ -30,7 +30,7 @@ package com.seibel.distanthorizons.api.enums.config;
* Determines how the multiplayer folders should be named. * Determines how the multiplayer folders should be named.
* *
* @author James Seibel * @author James Seibel
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiServerFolderNameMode public enum EDhApiServerFolderNameMode
@@ -1,14 +1,41 @@
package com.seibel.distanthorizons.api.enums.config; package com.seibel.distanthorizons.api.enums.config;
import com.seibel.distanthorizons.coreapi.ModInfo;
/** /**
* AUTO, <br>
* STABLE, <br> * STABLE, <br>
* NIGHTLY, <br><br> * NIGHTLY, <br><br>
* *
* @since API 1.1.0 * @since API 2.1.0
* @version 2024-4-6 * @version 2024-6-8
*/ */
public enum EDhApiUpdateBranch public enum EDhApiUpdateBranch
{ {
AUTO,
STABLE, STABLE,
NIGHTLY NIGHTLY;
/**
* If the updateBranch value is {@link EDhApiUpdateBranch#AUTO}
* this method will convert it either to {@link EDhApiUpdateBranch#STABLE} or {@link EDhApiUpdateBranch#NIGHTLY}
* based on this jar's state. <Br><br>
*
* If updateBranch is {@link EDhApiUpdateBranch#STABLE} or {@link EDhApiUpdateBranch#NIGHTLY}
* it just returns.
*/
public static EDhApiUpdateBranch convertAutoToStableOrNightly(EDhApiUpdateBranch updateBranch)
{
if (updateBranch != EDhApiUpdateBranch.AUTO)
{
return updateBranch;
}
else
{
return ModInfo.IS_DEV_BUILD ? EDhApiUpdateBranch.NIGHTLY : EDhApiUpdateBranch.STABLE;
}
}
} }
@@ -28,7 +28,7 @@ package com.seibel.distanthorizons.api.enums.config;
* the vanilla Minecraft terrain. * the vanilla Minecraft terrain.
* *
* @author James Seibel * @author James Seibel
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
@Deprecated // not currently in use, if the config this enum represents is re-implemented, the deprecated flag can be removed @Deprecated // not currently in use, if the config this enum represents is re-implemented, the deprecated flag can be removed
@@ -30,7 +30,7 @@ import com.seibel.distanthorizons.coreapi.util.MathUtil;
* *
* @author Leonardo Amato * @author Leonardo Amato
* @version 2024-4-6 * @version 2024-4-6
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiVerticalQuality public enum EDhApiVerticalQuality
{ {
@@ -24,7 +24,7 @@ package com.seibel.distanthorizons.api.enums.config;
* VISUALLY_EQUAL <br><br> * VISUALLY_EQUAL <br><br>
* *
* @version 2024-3-27 * @version 2024-3-27
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiWorldCompressionMode public enum EDhApiWorldCompressionMode
{ {
@@ -30,7 +30,7 @@ import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui
* HIGH, <br> * HIGH, <br>
* EXTREME, <br> * EXTREME, <br>
* *
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiQualityPreset public enum EDhApiQualityPreset
@@ -29,7 +29,7 @@ import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui
* BALANCED, <br> * BALANCED, <br>
* AGGRESSIVE, <br> * AGGRESSIVE, <br>
* *
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiThreadPreset public enum EDhApiThreadPreset
@@ -0,0 +1,68 @@
package com.seibel.distanthorizons.api.enums.rendering;
/**
* contains the indices used by shaders to determine
* how different block types should be rendered. <br><br>
*
* UNKNOWN, <br>
* LEAVES, <br>
* STONE, <br>
* WOOD, <br>
* METAL, <br>
* DIRT, <br>
* LAVA, <br>
* DEEPSLATE, <br>
* SNOW, <br>
* SAND, <br>
* TERRACOTTA, <br>
* NETHER_STONE, <br>
* WATER, <br>
* GRASS, <br>
* AIR, <br>
* ILLUMINATED, <br>
*
* @author IMS
* @author James Seibel
* @since API 3.0.0
* @version 2024-7-11
*/
public enum EDhApiBlockMaterial
{
UNKNOWN(0),
LEAVES(1),
STONE(2),
WOOD(3),
METAL(4),
DIRT(5),
LAVA(6),
DEEPSLATE(7),
SNOW(8),
SAND(9),
TERRACOTTA(10),
NETHER_STONE(11),
WATER(12),
GRASS(13),
/** shouldn't normally be needed, but just in case */
AIR(14),
ILLUMINATED(15); // Max value
public final byte index;
EDhApiBlockMaterial(int index) { this.index = (byte)index;}
public static EDhApiBlockMaterial getFromIndex(int index)
{
for(EDhApiBlockMaterial material : EDhApiBlockMaterial.values())
{
if (material.index == index)
{
return material;
}
}
return EDhApiBlockMaterial.UNKNOWN;
}
}
@@ -29,7 +29,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* @author Leetom * @author Leetom
* @author James Seibel * @author James Seibel
* @version 2024-4-6 * @version 2024-4-6
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiDebugRendering public enum EDhApiDebugRendering
{ {
@@ -25,7 +25,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* *
* @author James Seibel * @author James Seibel
* @version 2024-4-6 * @version 2024-4-6
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiFogColorMode public enum EDhApiFogColorMode
{ {
@@ -25,7 +25,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* FOG_DISABLED <br> * FOG_DISABLED <br>
* *
* @author James Seibel * @author James Seibel
* @since API 1.1.0 * @since API 2.0.0
* @version 2022-6-2 * @version 2022-6-2
*/ */
public enum EDhApiFogDrawMode public enum EDhApiFogDrawMode
@@ -26,7 +26,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* *
* @author Leetom * @author Leetom
* @version 2022-6-30 * @version 2022-6-30
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiFogFalloff public enum EDhApiFogFalloff
{ {
@@ -33,7 +33,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* *
* @author Leetom * @author Leetom
* @version 2024-4-6 * @version 2024-4-6
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiHeightFogMixMode public enum EDhApiHeightFogMixMode
{ {
@@ -29,7 +29,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* *
* @author Leetom * @author Leetom
* @version 2024-4-6 * @version 2024-4-6
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiHeightFogMode public enum EDhApiHeightFogMode
{ {
@@ -7,7 +7,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* *
* @author James Seibel * @author James Seibel
* @version 2024-1-30 * @version 2024-1-30
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiRenderPass public enum EDhApiRenderPass
{ {
@@ -24,7 +24,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* Debug <br> * Debug <br>
* Disabled <br> * Disabled <br>
* *
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiRendererMode public enum EDhApiRendererMode
@@ -24,7 +24,7 @@ package com.seibel.distanthorizons.api.enums.rendering;
* FAKE, <br> * FAKE, <br>
* COMPLETE, <br> * COMPLETE, <br>
* *
* @since API 1.1.0 * @since API 2.0.0
* @version 2024-4-6 * @version 2024-4-6
*/ */
public enum EDhApiTransparency public enum EDhApiTransparency
@@ -31,7 +31,7 @@ import java.util.function.Consumer;
* *
* @author Builderb0y, James Seibel * @author Builderb0y, James Seibel
* @version 2023-12-21 * @version 2023-12-21
* @since API 1.1.0 * @since API 2.0.0
*/ */
public enum EDhApiWorldGeneratorReturnType public enum EDhApiWorldGeneratorReturnType
{ {
@@ -40,7 +40,7 @@ public enum EDhApiWorldGeneratorReturnType
* {@link IDhApiWorldGenerator#generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer)} * {@link IDhApiWorldGenerator#generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer)}
* will be used when generating terrain. * will be used when generating terrain.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
VANILLA_CHUNKS, VANILLA_CHUNKS,
@@ -49,7 +49,7 @@ public enum EDhApiWorldGeneratorReturnType
* {@link IDhApiWorldGenerator#generateApiChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer)} * {@link IDhApiWorldGenerator#generateApiChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer)}
* will be used when generating terrain. * will be used when generating terrain.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
API_CHUNKS; API_CHUNKS;
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.api.interfaces.block; package com.seibel.distanthorizons.api.interfaces.block;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper; import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper;
/** /**
@@ -30,12 +31,25 @@ import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper;
*/ */
public interface IDhApiBlockStateWrapper extends IDhApiUnsafeWrapper public interface IDhApiBlockStateWrapper extends IDhApiUnsafeWrapper
{ {
/** @since API 1.0.0 */
boolean isAir(); boolean isAir();
/** @since API 1.0.0 */
boolean isSolid(); boolean isSolid();
/** @since API 1.0.0 */
boolean isLiquid(); boolean isLiquid();
// TODO: /**
// boolean hasNoCollision(); * Returns the full serialized form of the given block
// boolean noFaceIsFullFace(); * as defined by DH's serialization methods.
* @since API 3.0.0
*/
String getSerialString();
/**
* Returns the byte value representing the {@link EDhApiBlockMaterial} enum.
* @see EDhApiBlockMaterial
* @since API 3.0.0
*/
byte getMaterialId();
} }
@@ -36,7 +36,6 @@ public interface IDhApiConfig
IDhApiWorldGenerationConfig worldGenerator(); IDhApiWorldGenerationConfig worldGenerator();
IDhApiMultiplayerConfig multiplayer(); IDhApiMultiplayerConfig multiplayer();
IDhApiMultiThreadingConfig multiThreading(); IDhApiMultiThreadingConfig multiThreading();
IDhApiGpuBuffersConfig gpuBuffers();
// note: DON'T add the Auto Updater to this API. We only want the user's to have the ability to control when things are downloaded to their machines. // note: DON'T add the Auto Updater to this API. We only want the user's to have the ability to control when things are downloaded to their machines.
//IDhApiLoggingConfig logging(); // TODO implement //IDhApiLoggingConfig logging(); // TODO implement
IDhApiDebuggingConfig debugging(); IDhApiDebuggingConfig debugging();
@@ -47,7 +47,7 @@ public interface IDhApiConfigValue<T>
* Returns the value of the config if it was set by the API. * Returns the value of the config if it was set by the API.
* Returns null if the config hasn't been set by the API. * Returns null if the config hasn't been set by the API.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
T getApiValue(); T getApiValue();
@@ -68,7 +68,7 @@ public interface IDhApiConfigValue<T>
* use the value set in the config menu. * use the value set in the config menu.
* *
* @return true if the value was set, false otherwise. * @return true if the value was set, false otherwise.
* @since API 1.1.0 * @since API 2.0.0
*/ */
boolean clearValue(); boolean clearValue();
@@ -19,30 +19,28 @@
package com.seibel.distanthorizons.api.interfaces.config.client; package com.seibel.distanthorizons.api.interfaces.config.client;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigGroup; import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigGroup;
import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue; import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue;
/** /**
* Distant Horizons' OpenGL buffer configuration. * Distant Horizons' generic rendering configuration. <br><br>
* *
* @author James Seibel * @author James Seibel
* @version 2023-6-14 * @version 2024-7-11
* @since API 1.0.0 * @since API 3.0.0
*/ */
public interface IDhApiGpuBuffersConfig extends IDhApiConfigGroup public interface IDhApiGenericRenderingConfig extends IDhApiConfigGroup
{ {
/**
/** Defines how geometry data is uploaded to the GPU. */ * If enabled DH will render generic objects into its terrain pass. <br>
IDhApiConfigValue<EDhApiGpuUploadMethod> gpuUploadMethod(); * This includes: clouds, beacons, and API added objects.
/**
* Defines how long we should wait after uploading one
* Megabyte of geometry data to the GPU before uploading
* the next Megabyte of data. <br>
* This can be set to a non-zero number to reduce stuttering caused by
* uploading buffers to the GPU.
*/ */
IDhApiConfigValue<Integer> gpuUploadPerMegabyteInMilliseconds(); IDhApiConfigValue<Boolean> renderingEnabled();
/** If enabled DH will render beacon beams. */
IDhApiConfigValue<Boolean> beaconRenderingEnabled();
/** If enabled DH will render clouds. */
IDhApiConfigValue<Boolean> cloudRenderingEnabled();
} }
@@ -41,6 +41,7 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
IDhApiFogConfig fog(); IDhApiFogConfig fog();
IDhApiAmbientOcclusionConfig ambientOcclusion(); IDhApiAmbientOcclusionConfig ambientOcclusion();
IDhApiNoiseTextureConfig noiseTexture(); IDhApiNoiseTextureConfig noiseTexture();
IDhApiGenericRenderingConfig genericRendering();
@@ -121,7 +122,7 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
* Setting this to 0 will reduce/prevent holes in the world due to clipping to close to the camera * Setting this to 0 will reduce/prevent holes in the world due to clipping to close to the camera
* but may cause overdraw issues with transparent or non-full blocks. * but may cause overdraw issues with transparent or non-full blocks.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
IDhApiConfigValue<Double> overdrawPreventionRadius(); IDhApiConfigValue<Double> overdrawPreventionRadius();
@@ -158,7 +159,7 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
/** /**
* Determines how LODs should be shaded. * Determines how LODs should be shaded.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
IDhApiConfigValue<EDhApiLodShading> lodShading(); IDhApiConfigValue<EDhApiLodShading> lodShading();
@@ -171,7 +172,7 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
* start/stop rendering incorrectly based on the camera direction, * start/stop rendering incorrectly based on the camera direction,
* but will also reduce FPS. * but will also reduce FPS.
* *
* @since API 1.1.0 * @since API 2.0.0
* @see IDhApiGraphicsConfig#disableShadowFrustumCulling() * @see IDhApiGraphicsConfig#disableShadowFrustumCulling()
*/ */
IDhApiConfigValue<Boolean> disableFrustumCulling(); IDhApiConfigValue<Boolean> disableFrustumCulling();
@@ -183,7 +184,7 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
* *
* Disable this if shadows render incorrectly. * Disable this if shadows render incorrectly.
* *
* @since API 1.1.0 * @since API 2.0.0
* @see IDhApiGraphicsConfig#disableFrustumCulling() * @see IDhApiGraphicsConfig#disableFrustumCulling()
*/ */
IDhApiConfigValue<Boolean> disableShadowFrustumCulling(); IDhApiConfigValue<Boolean> disableShadowFrustumCulling();
@@ -0,0 +1,21 @@
package com.seibel.distanthorizons.api.interfaces.data;
/**
* Can be used to drastically speed up repeat read operations in {@link IDhApiTerrainDataRepo}.
*
* @see IDhApiTerrainDataRepo
*
* @author James Seibel
* @version 2024-7-14
* @since API 3.0.0
*/
public interface IDhApiTerrainDataCache
{
/**
* Removes any data that's currently stored in this cache.
* This cane be done to free up memory or invalidate
* the cache so fresh data can be pulled in.
*/
void clear();
}
@@ -29,6 +29,8 @@ import com.seibel.distanthorizons.api.objects.data.DhApiTerrainDataPoint;
/** /**
* Used to interface with Distant Horizons' terrain data. * Used to interface with Distant Horizons' terrain data.
* *
* @see IDhApiTerrainDataCache
*
* @author James Seibel * @author James Seibel
* @version 2023-6-22 * @version 2023-6-22
* @since API 1.0.0 * @since API 1.0.0
@@ -40,29 +42,50 @@ public interface IDhApiTerrainDataRepo
// getters // // getters //
//=========// //=========//
/** Returns the terrain datapoint at the given block position, at/or containing the given Y position. */ /** @see IDhApiTerrainDataRepo#getSingleDataPointAtBlockPos(IDhApiLevelWrapper, int, int, int, IDhApiTerrainDataCache) */
DhApiResult<DhApiTerrainDataPoint> getSingleDataPointAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosY, int blockPosZ); default DhApiResult<DhApiTerrainDataPoint> getSingleDataPointAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosY, int blockPosZ) { return this.getSingleDataPointAtBlockPos(levelWrapper, blockPosX, blockPosY, blockPosZ, null); }
/** Returns every datapoint in the column located at the given block X and Z position top to bottom. */ /**
DhApiResult<DhApiTerrainDataPoint[]> getColumnDataAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosZ); * Returns the terrain datapoint at the given block position, at/or containing the given Y position.
* @since API 3.0.0
*/
DhApiResult<DhApiTerrainDataPoint> getSingleDataPointAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosY, int blockPosZ, IDhApiTerrainDataCache dataCache);
/** @see IDhApiTerrainDataRepo#getColumnDataAtBlockPos(IDhApiLevelWrapper, int, int, IDhApiTerrainDataCache) */
default DhApiResult<DhApiTerrainDataPoint[]> getColumnDataAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosZ) { return this.getColumnDataAtBlockPos(levelWrapper, blockPosX, blockPosZ, null); }
/**
* Returns every datapoint in the column located at the given block X and Z position top to bottom.
* @since API 3.0.0
*/
DhApiResult<DhApiTerrainDataPoint[]> getColumnDataAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosZ, IDhApiTerrainDataCache dataCache);
/** @see IDhApiTerrainDataRepo#getAllTerrainDataAtChunkPos(IDhApiLevelWrapper, int, int, IDhApiTerrainDataCache) */
default DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtChunkPos(IDhApiLevelWrapper levelWrapper, int chunkPosX, int chunkPosZ) { return this.getAllTerrainDataAtChunkPos(levelWrapper, chunkPosX, chunkPosZ, null); }
/** /**
* Returns every datapoint in the given chunk's X and Z position. <br><br> * Returns every datapoint in the given chunk's X and Z position. <br><br>
* *
* The returned array is ordered: [relativeBlockX][relativeBlockZ][columnIndex] <br> * The returned array is ordered: [relativeBlockX][relativeBlockZ][columnIndex] <br>
* RelativeBlockX/Z are relative to the block position closest to negative infinity in the chunk's position. <br> * RelativeBlockX/Z are relative to the block position closest to negative infinity in the chunk's position. <br>
* The column data is ordered from top to bottom. Note: each column may have a different number of values. <br> * The column data is ordered from top to bottom. Note: each column may have a different number of values. <br>
*
* @since API 3.0.0
*/ */
DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtChunkPos(IDhApiLevelWrapper levelWrapper, int chunkPosX, int chunkPosZ); DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtChunkPos(IDhApiLevelWrapper levelWrapper, int chunkPosX, int chunkPosZ, IDhApiTerrainDataCache dataCache);
/** @see IDhApiTerrainDataRepo#getAllTerrainDataAtRegionPos(IDhApiLevelWrapper, int, int, IDhApiTerrainDataCache) */
default DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtRegionPos(IDhApiLevelWrapper levelWrapper, int regionPosX, int regionPosZ) { return this.getAllTerrainDataAtRegionPos(levelWrapper, regionPosX, regionPosZ, null); }
/** /**
* Returns every datapoint in the given region's X and Z position. <br><br> * Returns every datapoint in the given region's X and Z position. <br><br>
* *
* The returned array is ordered: [relativeBlockX][relativeBlockZ][columnIndex] <br> * The returned array is ordered: [relativeBlockX][relativeBlockZ][columnIndex] <br>
* RelativeBlockX/Z are relative to the block position closest to negative infinity in the region's position. <br> * RelativeBlockX/Z are relative to the block position closest to negative infinity in the region's position. <br>
* The column data is ordered from top to bottom. Note: each column may have a different number of values. <br> * The column data is ordered from top to bottom. Note: each column may have a different number of values. <br>
*
* @since API 3.0.0
*/ */
DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtRegionPos(IDhApiLevelWrapper levelWrapper, int regionPosX, int regionPosZ); DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtRegionPos(IDhApiLevelWrapper levelWrapper, int regionPosX, int regionPosZ, IDhApiTerrainDataCache dataCache);
/** @see IDhApiTerrainDataRepo#getAllTerrainDataAtDetailLevelAndPos(IDhApiLevelWrapper, byte, int, int, IDhApiTerrainDataCache) */
default DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtRegionPos(IDhApiLevelWrapper levelWrapper, byte detailLevel, int posX, int posZ) { return this.getAllTerrainDataAtDetailLevelAndPos(levelWrapper, detailLevel, posX, posZ, null); }
/** /**
* Returns every datapoint in the column located at the given detail level and X/Z position. <br> * Returns every datapoint in the column located at the given detail level and X/Z position. <br>
* This can be used to return terrain data for non-standard sizes (IE 2x2 blocks or 2x2 chunks). * This can be used to return terrain data for non-standard sizes (IE 2x2 blocks or 2x2 chunks).
@@ -71,20 +94,42 @@ public interface IDhApiTerrainDataRepo
* Every increase doubles the width of the returned area. <br> * Every increase doubles the width of the returned area. <br>
* Example values: 0 = block, 1 = 2x2 blocks, 2 = 4x4 blocks, ... 4 = chunk (16x16 blocks), ... 9 = region (512x512 blocks) <br> * Example values: 0 = block, 1 = 2x2 blocks, 2 = 4x4 blocks, ... 4 = chunk (16x16 blocks), ... 9 = region (512x512 blocks) <br>
* See {@link EDhApiDetailLevel} for more information. * See {@link EDhApiDetailLevel} for more information.
*
* @since API 3.0.0
*/ */
DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtDetailLevelAndPos(IDhApiLevelWrapper levelWrapper, byte detailLevel, int posX, int posZ); DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtDetailLevelAndPos(IDhApiLevelWrapper levelWrapper, byte detailLevel, int posX, int posZ, IDhApiTerrainDataCache dataCache);
/** @see IDhApiTerrainDataRepo#raycast(IDhApiLevelWrapper, double, double, double, float, float, float, int, IDhApiTerrainDataCache) */
default DhApiResult<DhApiRaycastResult> raycast(
IDhApiLevelWrapper levelWrapper,
double rayOriginX, double rayOriginY, double rayOriginZ,
float rayDirectionX, float rayDirectionY, float rayDirectionZ,
int maxRayBlockLength)
{
return this.raycast(
levelWrapper,
rayOriginX, rayOriginY, rayOriginZ,
rayDirectionX, rayDirectionY, rayDirectionZ,
maxRayBlockLength,
null);
}
/** /**
* Returns the datapoint and position of the LOD * Returns the datapoint and position of the LOD
* at the end of the given ray. <br><br> * at the end of the given ray. <br><br>
* *
* Will return "success" with a null datapoint if the ray reaches the max length without finding any data. * Will return "success" with a null datapoint if the ray reaches the max length without finding any data.
*
* @since API 3.0.0
*/ */
DhApiResult<DhApiRaycastResult> raycast( DhApiResult<DhApiRaycastResult> raycast(
IDhApiLevelWrapper levelWrapper, IDhApiLevelWrapper levelWrapper,
double rayOriginX, double rayOriginY, double rayOriginZ, double rayOriginX, double rayOriginY, double rayOriginZ,
float rayDirectionX, float rayDirectionY, float rayDirectionZ, float rayDirectionX, float rayDirectionY, float rayDirectionZ,
int maxRayBlockLength); int maxRayBlockLength,
IDhApiTerrainDataCache dataCache);
@@ -98,15 +143,27 @@ public interface IDhApiTerrainDataRepo
* Notes: <br> * Notes: <br>
* - Only works if the given {@link IDhApiLevelWrapper} points to a loaded level. <br> * - Only works if the given {@link IDhApiLevelWrapper} points to a loaded level. <br>
* - If the player travels to this chunk, or the chunk is updated in some other way; your data will be replaced * - If the player travels to this chunk, or the chunk is updated in some other way; your data will be replaced
* by whatever the current chunk is. <br> * by whatever the current chunk is. <br>
* - This method may not update the LOD data immediately. Any other chunks have * - This method may not update the LOD data immediately. Any other chunks that have
* been queued to update, they will be handled first. * been queued to update will be handled first.
* *
* @param levelWrapper the level wrapper that the chunk should be saved to. * @param levelWrapper the level wrapper that the chunk should be saved to.
* @param chunkObjectArray see {@link IDhApiWorldGenerator#generateChunks} for what objects are expected. * @param chunkObjectArray see {@link IDhApiWorldGenerator#generateChunks} for what objects are expected.
* @throws ClassCastException if chunkObjectArray doesn't contain the right objects. * @throws ClassCastException if chunkObjectArray doesn't contain the right objects.
* The exception will contain the expected object(s). * The exception will contain the expected object(s).
*/ */
public DhApiResult<Void> overwriteChunkDataAsync(IDhApiLevelWrapper levelWrapper, Object[] chunkObjectArray) throws ClassCastException; DhApiResult<Void> overwriteChunkDataAsync(IDhApiLevelWrapper levelWrapper, Object[] chunkObjectArray) throws ClassCastException;
//=========//
// helpers //
//=========//
/**
* @return a {@link IDhApiTerrainDataCache} backed by {@link java.lang.ref.SoftReference}'s.
* @since API 3.0.0
*/
IDhApiTerrainDataCache getSoftCache();
} }
@@ -31,7 +31,7 @@ import java.io.IOException;
* *
* @author James Seibel * @author James Seibel
* @version 2023-12-16 * @version 2023-12-16
* @since API 1.1.0 * @since API 2.0.0
*/ */
public interface IDhApiWrapperFactory public interface IDhApiWrapperFactory
{ {
@@ -50,7 +50,7 @@ public interface IDhApiWrapperFactory
* @throws ClassCastException if any of the given parameters is of the wrong type. * @throws ClassCastException if any of the given parameters is of the wrong type.
* If thrown the error message will contain the list of expected object types in order. * If thrown the error message will contain the list of expected object types in order.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper) throws ClassCastException; IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper) throws ClassCastException;
@@ -67,23 +67,46 @@ public interface IDhApiWrapperFactory
* @throws ClassCastException if any of the given parameters is of the wrong type. * @throws ClassCastException if any of the given parameters is of the wrong type.
* If thrown the error message will contain the list of expected object types in order. * If thrown the error message will contain the list of expected object types in order.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
IDhApiBlockStateWrapper getBlockStateWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper) throws ClassCastException; IDhApiBlockStateWrapper getBlockStateWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper) throws ClassCastException;
/** /**
* Returns the {@link IDhApiBlockStateWrapper} representing air. * Returns the {@link IDhApiBlockStateWrapper} representing air.
* @since API 1.1.0 * @since API 2.0.0
*/ */
IDhApiBlockStateWrapper getAirBlockStateWrapper(); IDhApiBlockStateWrapper getAirBlockStateWrapper();
///** /**
// * Specifically designed to be used with the API. * Constructs a {@link IDhApiBiomeWrapper} for use by other DhApi methods.
// * *
// * @throws ClassCastException with instructions on expected objects if the object couldn't be cast * @param resourceLocationString example: "minecraft:plains"
// */ *
//IChunkWrapper createChunkWrapper(Object[] objectArray) throws ClassCastException; * @param levelWrapper Expects a {@link IDhApiLevelWrapper} returned by one of DH's {@link DhApi.Delayed#worldProxy} methods. <br>
* A custom implementation of {@link IDhApiLevelWrapper} will not be accepted.
*
* @throws IOException if the resourceLocationString wasn't able to be parsed or converted into a valid {@link IDhApiBiomeWrapper}
* @throws ClassCastException if the wrong levelWrapper type was given
*
* @since API 3.0.0
*/
IDhApiBiomeWrapper getBiomeWrapper(String resourceLocationString, IDhApiLevelWrapper levelWrapper) throws IOException, ClassCastException;
/**
* Constructs a {@link IDhApiBlockStateWrapper} for use by other DhApi methods.
* This returns the default blockstate for the given resource location.
*
* @param resourceLocationString examples: "minecraft:bedrock", "minecraft:stone", "minecraft:grass_block"
* @param levelWrapper Expects a {@link IDhApiBlockStateWrapper} returned by one of DH's {@link DhApi.Delayed#worldProxy} methods. <br>
* A custom implementation of {@link IDhApiBlockStateWrapper} will not be accepted.
*
* @throws IOException if the resourceLocationString wasn't able to be parsed or converted into a valid {@link IDhApiBlockStateWrapper}
* @throws ClassCastException if the wrong levelWrapper type was given
*
* @since API 3.0.0
*/
IDhApiBlockStateWrapper getDefaultBlockStateWrapper(String resourceLocationString, IDhApiLevelWrapper levelWrapper) throws IOException, ClassCastException;
} }
@@ -21,7 +21,7 @@ package com.seibel.distanthorizons.api.interfaces.override.rendering;
import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel; import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel;
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
/** /**
* Used to determine if a LOD should be rendered or is outside the * Used to determine if a LOD should be rendered or is outside the
@@ -29,7 +29,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
* *
* @author James Seibel * @author James Seibel
* @version 2024-2-6 * @version 2024-2-6
* @since API 1.1.0 * @since API 2.0.0
*/ */
public interface IDhApiCullingFrustum extends IDhApiOverrideable public interface IDhApiCullingFrustum extends IDhApiOverrideable
{ {
@@ -41,7 +41,7 @@ public interface IDhApiCullingFrustum extends IDhApiOverrideable
* @param worldMaxBlockY the highest block position this level allows. * @param worldMaxBlockY the highest block position this level allows.
* @param worldViewProjection the projection matrix used in this render pass. * @param worldViewProjection the projection matrix used in this render pass.
*/ */
void update(int worldMinBlockY, int worldMaxBlockY, Mat4f worldViewProjection); void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewProjection);
/** /**
* returns true if the LOD bounds intersect this frustum * returns true if the LOD bounds intersect this frustum
@@ -24,7 +24,7 @@ import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
/** /**
* @author James Seibel * @author James Seibel
* @version 2024-1-24 * @version 2024-1-24
* @since API 1.1.0 * @since API 2.0.0
*/ */
public interface IDhApiFramebuffer extends IDhApiOverrideable public interface IDhApiFramebuffer extends IDhApiOverrideable
{ {
@@ -0,0 +1,80 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.api.interfaces.override.rendering;
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
/**
* @see IDhApiShaderProgram
*
* @author James Seibel
* @version 2024-7-11
* @since API 3.0.0
*/
public interface IDhApiGenericObjectShaderProgram extends IDhApiOverrideable
{
/**
* If this method is called that means this program has the highest priority as defined by {@link IDhApiOverrideable#getPriority()}
* and gets to decide if it wants to be used to render this frame or not. <br><br>
*
* If this method returns true then this program will be used for this frame. <br>
* If this returns false then the default DH {@link IDhApiGenericObjectShaderProgram} will be used instead.
*/
boolean overrideThisFrame();
/** @return the OpenGL ID for this shader program */
int getId();
/** Free any OpenGL objects owned by this program. */
void free();
/** Runs any necessary binding this program needs so rendering can be done. */
void bind(DhApiRenderParam renderEventParam);
/** Runs any necessary unbinding this program needs so rendering can be done by another program. */
void unbind();
/** Binds the given Vertex Buffer Object to this shader program for rendering. */
void bindVertexBuffer(int vbo);
/** sets up the necessary uniforms for rendering */
void fillIndirectUniformData(
DhApiRenderParam renderParameters,
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
DhApiVec3d camPos);
/** sets up the necessary uniforms for rendering */
void fillSharedDirectUniformData(
DhApiRenderParam renderParameters,
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
DhApiVec3d camPos);
void fillDirectUniformData(
DhApiRenderParam renderParameters,
IDhApiRenderableBoxGroup boxGroup, DhApiRenderableBox box,
DhApiVec3d camPos);
}
@@ -21,13 +21,14 @@ package com.seibel.distanthorizons.api.interfaces.override.rendering;
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
/** /**
* @see IDhApiGenericObjectShaderProgram
*
* @author James Seibel * @author James Seibel
* @version 2024-1-24 * @version 2024-1-24
* @since API 1.1.0 * @since API 2.0.0
*/ */
public interface IDhApiShaderProgram extends IDhApiOverrideable public interface IDhApiShaderProgram extends IDhApiOverrideable
{ {
@@ -57,7 +58,7 @@ public interface IDhApiShaderProgram extends IDhApiOverrideable
void fillUniformData(DhApiRenderParam renderParameters); void fillUniformData(DhApiRenderParam renderParameters);
/** sets the vec3 that all DH verticies should be offset by when rendering */ /** sets the vec3 that all DH verticies should be offset by when rendering */
void setModelOffsetPos(Vec3f modelPos); void setModelOffsetPos(DhApiVec3f modelPos);
/** Binds the given Vertex Buffer Object to this shader program for rendering. */ /** Binds the given Vertex Buffer Object to this shader program for rendering. */
void bindVertexBuffer(int vbo); void bindVertexBuffer(int vbo);
@@ -19,10 +19,6 @@
package com.seibel.distanthorizons.api.interfaces.override.rendering; package com.seibel.distanthorizons.api.interfaces.override.rendering;
import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel;
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
/** /**
* The culling frustum used during Distant Horizons' shadow pass * The culling frustum used during Distant Horizons' shadow pass
* if another mod has enabled Distant Horizons' shadow * if another mod has enabled Distant Horizons' shadow
@@ -35,7 +31,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
* *
* @author James Seibel * @author James Seibel
* @version 2024-2-10 * @version 2024-2-10
* @since API 1.1.0 * @since API 2.0.0
*/ */
public interface IDhApiShadowCullingFrustum extends IDhApiCullingFrustum public interface IDhApiShadowCullingFrustum extends IDhApiCullingFrustum
{ {
@@ -22,6 +22,8 @@ package com.seibel.distanthorizons.api.interfaces.override.worldGenerator;
import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel; import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
import com.seibel.distanthorizons.api.objects.data.DhApiChunk;
import com.seibel.distanthorizons.api.objects.data.DhApiTerrainDataPoint;
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
import java.io.Closeable; import java.io.Closeable;
@@ -77,13 +79,41 @@ public abstract class AbstractDhApiChunkWorldGenerator implements Closeable, IDh
}, worldGeneratorThreadPool); }, worldGeneratorThreadPool);
} }
@Override
public final CompletableFuture<Void> generateApiChunks(
int chunkPosMinX,
int chunkPosMinZ,
byte granularity,
byte targetDataDetail,
EDhApiDistantGeneratorMode generatorMode,
ExecutorService worldGeneratorThreadPool,
Consumer<DhApiChunk> resultConsumer
)
{
return CompletableFuture.runAsync(() ->
{
// TODO what does this mean?
int genChunkWidth = BitShiftUtil.powerOfTwo(granularity - 4);
for (int chunkX = chunkPosMinX; chunkX < chunkPosMinX + genChunkWidth; chunkX++)
{
for (int chunkZ = chunkPosMinZ; chunkZ < chunkPosMinZ + genChunkWidth; chunkZ++)
{
DhApiChunk apiChunk = this.generateApiChunk(chunkX, chunkZ, generatorMode);
resultConsumer.accept(apiChunk);
}
}
}, worldGeneratorThreadPool);
}
/** /**
* This method is called to generate terrain over a given area * This method is called to generate terrain over a given area
* from a thread defined by Distant Horizons. <br><br> * from a thread defined by Distant Horizons. <br><br>
* *
* @param chunkPosX the chunk X position in the level (not to be confused with the chunk's BlockPos in the level) * @param chunkPosX the chunk X position in the level (not to be confused with the chunk's BlockPos in the level)
* @param chunkPosZ the chunk Z position in the level (not to be confused with the chunk's BlockPos in the level) * @param chunkPosZ the chunk Z position in the level (not to be confused with the chunk's BlockPos in the level)
* @param generatorMode how far into the world gen pipeline this method run. See {@link EDhApiDistantGeneratorMode} for additional documentation. * @param generatorMode how far into the world gen pipeline this method should run. See {@link EDhApiDistantGeneratorMode} for additional documentation.
* *
* @return See {@link IDhApiWorldGenerator#generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer) IDhApiWorldGenerator.generateChunks} * @return See {@link IDhApiWorldGenerator#generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer) IDhApiWorldGenerator.generateChunks}
* for the list of Object's this method should return along with additional documentation. * for the list of Object's this method should return along with additional documentation.
@@ -92,4 +122,21 @@ public abstract class AbstractDhApiChunkWorldGenerator implements Closeable, IDh
*/ */
public abstract Object[] generateChunk(int chunkPosX, int chunkPosZ, EDhApiDistantGeneratorMode generatorMode); public abstract Object[] generateChunk(int chunkPosX, int chunkPosZ, EDhApiDistantGeneratorMode generatorMode);
/**
* This method is called to generate terrain over a given area
* from a thread defined by Distant Horizons. <br><br>
*
* @param chunkPosX the chunk X position in the level (not to be confused with the chunk's BlockPos in the level)
* @param chunkPosZ the chunk Z position in the level (not to be confused with the chunk's BlockPos in the level)
* @param generatorMode how far into the world gen pipeline this method should run. See {@link EDhApiDistantGeneratorMode} for additional documentation.
*
* @return A {@link DhApiChunk} with the generated {@link DhApiTerrainDataPoint} including air blocks.
* Note: if air blocks aren't included with the proper lighting, lower detail levels will appear as black/unlit.
*
* @see IDhApiWorldGenerator#generateApiChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer)
*
* @since API 3.0.0
*/
public abstract DhApiChunk generateApiChunk(int chunkPosX, int chunkPosZ, EDhApiDistantGeneratorMode generatorMode);
} }
@@ -90,11 +90,29 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
*/ */
default byte getMaxGenerationGranularity() { return (byte) (EDhApiDetailLevel.CHUNK.detailLevel + 2); } default byte getMaxGenerationGranularity() { return (byte) (EDhApiDetailLevel.CHUNK.detailLevel + 2); }
/** /**
* @return true if the generator is unable to accept new generation requests. * Starting in API 3.0.0 DH now handles future queuing/management internally. <br><br>
*
* Previous description: <br>
* true if the generator is unable to accept new generation requests. <br>
*
* @since API 1.0.0 * @since API 1.0.0
* @deprecated API 3.0.0
*/ */
boolean isBusy(); @Deprecated
default boolean isBusy() { return false; }
/**
* Only used if {@link #getReturnType()} returns {@link EDhApiWorldGeneratorReturnType#API_CHUNKS}. <Br>
* If true DH will run additional validation on the {@link DhApiChunk}'s returned. <Br>
* This should be disabled during release but should be enabled during development to help spot issues with your data format.
*
* @see #getReturnType()
* @see DhApiChunk
* @see EDhApiWorldGeneratorReturnType#API_CHUNKS
* @since API 3.0.0
*/
default boolean runApiChunkValidation() { return true; }
@@ -154,6 +172,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
* *
* After the {@link DhApiChunk} has been generated, it should be passed into the * After the {@link DhApiChunk} has been generated, it should be passed into the
* resultConsumer's {@link Consumer#accept(Object)} method. * resultConsumer's {@link Consumer#accept(Object)} method.
* Note: if air blocks aren't included in the with the {@link DhApiChunk} with proper lighting, lower detail levels will appear as black/unlit.
* *
* @implNote the default implementation of this method throws an {@link UnsupportedOperationException}, * @implNote the default implementation of this method throws an {@link UnsupportedOperationException},
* and must be overridden when {@link #getReturnType()} returns {@link EDhApiWorldGeneratorReturnType#API_CHUNKS}. * and must be overridden when {@link #getReturnType()} returns {@link EDhApiWorldGeneratorReturnType#API_CHUNKS}.
@@ -168,7 +187,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
* *
* @return a future that should run on the worldGeneratorThreadPool and complete once the given generation task has completed. * @return a future that should run on the worldGeneratorThreadPool and complete once the given generation task has completed.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
default CompletableFuture<Void> generateApiChunks( default CompletableFuture<Void> generateApiChunks(
int chunkPosMinX, int chunkPosMinX,
@@ -189,7 +208,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
* which means that {@link #generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer)} * which means that {@link #generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer)}
* will be invoked whenever Distant Horizons wants to generate terrain with this world generator. * will be invoked whenever Distant Horizons wants to generate terrain with this world generator.
* *
* @since API 1.1.0 * @since API 2.0.0
*/ */
default EDhApiWorldGeneratorReturnType getReturnType() { return EDhApiWorldGeneratorReturnType.VANILLA_CHUNKS; } default EDhApiWorldGeneratorReturnType getReturnType() { return EDhApiWorldGeneratorReturnType.VANILLA_CHUNKS; }
@@ -0,0 +1,67 @@
package com.seibel.distanthorizons.api.interfaces.render;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import java.util.List;
/**
* Handles creating
* {@link IDhApiRenderableBoxGroup} objects,
* which can be added via a {@link IDhApiCustomRenderRegister}.
*
* @see IDhApiCustomRenderRegister
* @see IDhApiRenderableBoxGroup
*
* @author James Seibel
* @version 2024-7-3
* @since API 3.0.0
*/
public interface IDhApiCustomRenderObjectFactory
{
/**
* Creates a {@link IDhApiRenderableBoxGroup} from for the given {@link DhApiRenderableBox}
* where the box is positioned relative to the level's origin.
*
* @param resourceLocation A colon separated Resource Location string, similar to vanilla Minecraft, for example: "DistantHorizons:Clouds"
*
* @see DhApiRenderableBox
* @see IDhApiRenderableBoxGroup#getResourceLocationNamespace()
* @see IDhApiRenderableBoxGroup#getResourceLocationPath()
*
* @throws IllegalArgumentException if <code>resourceLocation</code> is null, isn't separated by a colon, or has multiple colons.
*/
IDhApiRenderableBoxGroup createForSingleBox(String resourceLocation, DhApiRenderableBox cube) throws IllegalArgumentException;
/**
* Creates a {@link IDhApiRenderableBoxGroup} from the given list of {@link DhApiRenderableBox} where each
* one is positioned relative to given <code>originBlockPos</code>, which in turn is relative to the level's origin.
*
* @param resourceLocation A colon separated Resource Location string, similar to vanilla Minecraft, for example: "DistantHorizons:Clouds"
* @param originBlockPos The starting position for this {@link IDhApiRenderableBoxGroup}, can be changed during runtime.
*
*
* @see DhApiRenderableBox
* @see IDhApiRenderableBoxGroup#getResourceLocationNamespace()
* @see IDhApiRenderableBoxGroup#getResourceLocationPath()
*
* @throws IllegalArgumentException if <code>resourceLocation</code> is null, isn't separated by a colon, or has multiple colons.
*/
IDhApiRenderableBoxGroup createRelativePositionedGroup(String resourceLocation, DhApiVec3d originBlockPos, List<DhApiRenderableBox> cubeList);
/**
* Creates a {@link IDhApiRenderableBoxGroup} from the given list of {@link DhApiRenderableBox} where each
* one is positioned relative to the level's origin.
*
* @param resourceLocation A colon separated Resource Location string, similar to vanilla Minecraft, for example: "DistantHorizons:Clouds"
*
* @see DhApiRenderableBox
* @see IDhApiRenderableBoxGroup#getResourceLocationNamespace()
* @see IDhApiRenderableBoxGroup#getResourceLocationPath()
*
* @throws IllegalArgumentException if <code>resourceLocation</code> is null, isn't separated by a colon, or has multiple colons.
*/
IDhApiRenderableBoxGroup createAbsolutePositionedGroup(String resourceLocation, List<DhApiRenderableBox> cubeList);
}
@@ -0,0 +1,30 @@
package com.seibel.distanthorizons.api.interfaces.render;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiWorldProxy;
/**
* Handles adding and removing
* {@link IDhApiRenderableBoxGroup} objects,
* from DH's renderer. <br><br>
*
* Can be accessed in
* {@link DhApi.Delayed#worldProxy} -> {@link IDhApiLevelWrapper}.
*
* @see IDhApiCustomRenderObjectFactory
* @see IDhApiRenderableBoxGroup
* @see IDhApiWorldProxy
* @see IDhApiLevelWrapper
*
* @author James Seibel
* @version 2024-7-3
* @since API 3.0.0
*/
public interface IDhApiCustomRenderRegister
{
void add(IDhApiRenderableBoxGroup cubeGroup) throws IllegalArgumentException;
IDhApiRenderableBoxGroup remove(long id);
}
@@ -26,7 +26,7 @@ import com.seibel.distanthorizons.api.objects.DhApiResult;
* Used to interact with Distant Horizons' rendering system. * Used to interact with Distant Horizons' rendering system.
* *
* @author James Seibel * @author James Seibel
* @version 2023-10-13 * @version 2024-7-27
* @since API 1.0.0 * @since API 1.0.0
*/ */
public interface IDhApiRenderProxy public interface IDhApiRenderProxy
@@ -39,10 +39,8 @@ public interface IDhApiRenderProxy
* If this is called on a dedicated server it won't do anything and will return {@link DhApiResult#success} = false <Br><Br> * If this is called on a dedicated server it won't do anything and will return {@link DhApiResult#success} = false <Br><Br>
* *
* Background: <Br> * Background: <Br>
* Distant Horizons has two different file formats: Full data and Render data. <Br> * When rendering Distant Horizons bakes each block's color into the geometry that's rendered. <Br>
* - Full data files store the block, biome, etc. information and is the result of loading or generating new chunks. <Br> * This improves rendering speed and VRAM size, but prevents dynamically changing LOD colors. <Br>
* - Render data files store LOD colors and are created using the Full data and currently loaded resource packs. <Br>
* This is the data cleared by this method.
*/ */
DhApiResult<Boolean> clearRenderDataCache(); DhApiResult<Boolean> clearRenderDataCache();
@@ -0,0 +1,98 @@
package com.seibel.distanthorizons.api.interfaces.render;
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import java.util.List;
import java.util.function.Consumer;
/**
* A list of {@link DhApiRenderableBox}'s that
* can be rendered to DH's terrain pass.
*
* @see DhApiRenderableBox
*
* @author James Seibel
* @version 2024-6-30
* @since API 3.0.0
*/
public interface IDhApiRenderableBoxGroup extends List<DhApiRenderableBox>
{
/**
* A unique numerical ID used by DH during rendering.
* This can also be used to bind/unbind specific {@link IDhApiRenderableBoxGroup}'s from the renderer.
* @return the ID for this specific group
*/
long getId();
/**
* Used to determine which mods have added what to the DH renderer.
* This can be used both by the F3 pie chart so you as a mod developer can profile your code
* or by shader developers who want to render your objects differently. <br><br>
*
* Should be used the same as a vanilla Minecraft ResourceLocation.
* For example if your mod named "Heavy Thunder" adds additional clouds named "Storm Front",
* your Resource Location would be something like "HeavyThunder:StormFront"
* and this method would return "HeavyThunder".
*/
String getResourceLocationNamespace();
/**
* Used to determine what type of object mods have added what to the DH renderer.
* This can be used both by the F3 pie chart so you as a mod developer can profile your code
* or by shader developers who want to render your objects differently. <br><br>
*
* Should be used the same as a vanilla Minecraft ResourceLocation.
* For example if your mod named "Heavy Thunder" adds additional clouds named "Storm Front",
* your Resource Location would be something like "HeavyThunder:StormFront"
* and this method would return "StormFront".
*/
String getResourceLocationPath();
/** Sets whether this group should render or not. */
void setActive(boolean active);
/** @return if active this group will render. */
boolean isActive();
/** Sets whether this group should render with Screen Space Ambient Occlusioning. */
void setSsaoEnabled(boolean ssaoEnabled);
/** @return if active this group will render with Screen Space Ambient Occlusioning. */
boolean isSsaoEnabled();
/** Sets where this group will render in the level. */
void setOriginBlockPos(DhApiVec3d pos);
/** @return the block position in the level that all {@see DhApiRenderableBox} will render relative to. */
DhApiVec3d getOriginBlockPos();
/**
* Called right before this group is rendered. <br>
* This is a good place to change the origin or notify of any box changes.
*/
void setPreRenderFunc(Consumer<DhApiRenderParam> renderEventParam);
void setPostRenderFunc(Consumer<DhApiRenderParam> renderEventParam); // TODO name?
/**
* If a cube's color, position, or other property is changed this method
* must be called for those changes to render. <br><br>
*
* Note: changing the group's position via {@link #setOriginBlockPos} doesn't
* require calling this method.
*/
void triggerBoxChange();
/** Only accepts values between 0 and 15 */
void setSkyLight(int skyLight);
int getSkyLight();
/** Only accepts values between 0 and 15 */
void setBlockLight(int blockLight);
int getBlockLight();
void setShading(DhApiRenderableBoxGroupShading shading);
DhApiRenderableBoxGroupShading getShading();
}
@@ -0,0 +1,18 @@
package com.seibel.distanthorizons.api.interfaces.util;
/**
* Used for objects that need deep clones. <br>
* Replacement for {@link Cloneable}.
*
* @see Cloneable
*
* @author James Seibel
* @version 2024-7-12
* @since API 3.0.0
*/
public interface IDhApiCopyable
{
/** Returns a deep clone of all parameters whenever possible. */
IDhApiCopyable copy();
}
@@ -28,10 +28,8 @@ import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper;
*/ */
public interface IDhApiDimensionTypeWrapper extends IDhApiUnsafeWrapper public interface IDhApiDimensionTypeWrapper extends IDhApiUnsafeWrapper
{ {
String getDimensionName();
boolean hasCeiling(); boolean hasCeiling();
boolean hasSkyLight(); boolean hasSkyLight();
} }
@@ -21,27 +21,41 @@ package com.seibel.distanthorizons.api.interfaces.world;
import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper; import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
/** /**
* Can be either a Server or Client level.<br> * Can be either a Server or Client level.<br>
* A level is equivalent to a dimension in vanilla Minecraft. * A level is equivalent to a dimension in vanilla Minecraft.
* *
* @author James Seibel * @author James Seibel
* @version 2022-7-14 * @version 2024-7-28
* @since API 1.0.0 * @since API 1.0.0
*/ */
public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper
{ {
IDhApiDimensionTypeWrapper getDimensionType(); IDhApiDimensionTypeWrapper getDimensionType();
String getDimensionName();
EDhApiLevelType getLevelType(); EDhApiLevelType getLevelType();
boolean hasCeiling(); boolean hasCeiling();
boolean hasSkyLight(); boolean hasSkyLight();
/** Returns the max block height of the level(?) */ /**
int getHeight(); * Deprecated, use {@link IDhApiLevelWrapper#getMaxHeight} instead. <br>
* Returns the max block height of the level.
*
* @see IDhApiLevelWrapper#getMaxHeight
*/
@Deprecated
default int getHeight() { return this.getMaxHeight(); }
/**
* Returns the max block height of the level
* @since API 3.0.0
*/
int getMaxHeight();
/** /**
* Returns the lowest possible block position for the level. <br> * Returns the lowest possible block position for the level. <br>
@@ -49,4 +63,12 @@ public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper
*/ */
default int getMinHeight() { return 0; } default int getMinHeight() { return 0; }
} /**
* Will return null if called on the server,
* or if called before the renderer has been set up.
*
* @since API 3.0.0
*/
IDhApiCustomRenderRegister getRenderRegister();
}
@@ -26,17 +26,20 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
/** /**
* Fired after Distant Horizons finishes rendering a frame. <br> * Fired after Distant Horizons finishes rendering a frame. <br>
* At this point DH will have also finished cleaning up any modifications it * At this point DH will have also finished cleaning up any modifications it
* did to the OpenGL state, so the state should be back to Minecraft's defaults. * did to the OpenGL state, so the state should be back to Minecraft's defaults. <br><br>
* *
* Note: as of API v 3.0.0 no {@link DhApiRenderParam} is included in this event
* because the specific parameters may change
* depending on whether deferred rendering is enabled or not.
*
* @author James Seibel * @author James Seibel
* @version 2024-1-31 * @version 2024-7-14
* @see DhApiRenderParam
* @since API 1.0.0 * @since API 1.0.0
*/ */
public abstract class DhApiAfterRenderEvent implements IDhApiEvent<DhApiRenderParam> public abstract class DhApiAfterRenderEvent implements IDhApiEvent<Void>
{ {
/** Fired after Distant Horizons finishes rendering fake chunks. */ /** Fired after Distant Horizons finishes rendering fake chunks. */
public abstract void afterRender(DhApiEventParam<DhApiRenderParam> event); public abstract void afterRender(DhApiEventParam<Void> event);
//=========================// //=========================//
@@ -44,6 +47,6 @@ public abstract class DhApiAfterRenderEvent implements IDhApiEvent<DhApiRenderPa
//=========================// //=========================//
@Override @Override
public final void fireEvent(DhApiEventParam<DhApiRenderParam> event) { this.afterRender(event); } public final void fireEvent(DhApiEventParam<Void> event) { this.afterRender(event); }
} }
@@ -31,7 +31,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
* *
* @author James Seibel * @author James Seibel
* @version 2024-1-31 * @version 2024-1-31
* @since API 1.1.0 * @since API 2.0.0
*/ */
public abstract class DhApiBeforeApplyShaderRenderEvent implements IDhApiCancelableEvent<DhApiRenderParam> public abstract class DhApiBeforeApplyShaderRenderEvent implements IDhApiCancelableEvent<DhApiRenderParam>
{ {
@@ -20,9 +20,10 @@
package com.seibel.distanthorizons.api.methods.events.abstractEvents; package com.seibel.distanthorizons.api.methods.events.abstractEvents;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f; import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
/** /**
* Called before Distant Horizons starts rendering a buffer. <br> * Called before Distant Horizons starts rendering a buffer. <br>
@@ -30,7 +31,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
* *
* @author James Seibel * @author James Seibel
* @version 2023-1-31 * @version 2023-1-31
* @since API 1.1.0 * @since API 2.0.0
* *
* @see DhApiBeforeRenderEvent * @see DhApiBeforeRenderEvent
*/ */
@@ -52,20 +53,29 @@ public abstract class DhApiBeforeBufferRenderEvent implements IDhApiEvent<DhApiB
// parameter object // // parameter object //
//==================// //==================//
public static class EventParam extends DhApiRenderParam public static class EventParam extends DhApiRenderParam implements IDhApiEventParam
{ {
/** /**
* Measured in blocks. * Measured in blocks.
* Should be applied to the model view matrix to move the buffer into its proper place. * Should be applied to the model view matrix to move the buffer into its proper place.
*/ */
public final Vec3f modelPos; public final DhApiVec3f modelPos;
public EventParam(DhApiRenderParam parent, Vec3f modelPos) public EventParam(DhApiRenderParam parent, DhApiVec3f modelPos)
{ {
super(parent); super(parent);
this.modelPos = modelPos; this.modelPos = modelPos;
} }
@Override
public EventParam copy()
{
return new EventParam(
this, this.modelPos.copy()
);
}
} }
} }
@@ -29,7 +29,7 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy;
* *
* @author James Seibel * @author James Seibel
* @version 2024-1-22 * @version 2024-1-22
* @since API 1.1.0 * @since API 2.0.0
*/ */
public abstract class DhApiBeforeDeferredRenderEvent extends DhApiBeforeRenderEvent public abstract class DhApiBeforeDeferredRenderEvent extends DhApiBeforeRenderEvent
{ {
@@ -0,0 +1,97 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.api.methods.events.abstractEvents;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiCancelableEvent;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiCancelableEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
/**
* Called before Distant Horizons starts rendering a generic object. <br>
* Canceling this event will prevent the triggering {@link IDhApiRenderableBoxGroup} from rendering this frame.
*
* @author James Seibel
* @version 2024-7-11
* @since API 3.0.0
*/
public abstract class DhApiBeforeGenericObjectRenderEvent implements IDhApiCancelableEvent<DhApiBeforeGenericObjectRenderEvent.EventParam>
{
/** Fired before Distant Horizons renders a generic object. */
public abstract void beforeRender(DhApiCancelableEventParam<EventParam> event);
//=========================//
// internal DH API methods //
//=========================//
@Override
public final void fireEvent(DhApiCancelableEventParam<EventParam> input) { this.beforeRender(input); }
//==================//
// parameter object //
//==================//
public static class EventParam extends DhApiRenderParam implements IDhApiEventParam
{
public final long boxGroupId;
public final String resourceLocationNamespace;
public final String resourceLocationPath;
public EventParam(
DhApiRenderParam renderParam,
IDhApiRenderableBoxGroup boxGroup
)
{
super(renderParam);
this.boxGroupId = boxGroup.getId();
this.resourceLocationNamespace = boxGroup.getResourceLocationNamespace();
this.resourceLocationPath = boxGroup.getResourceLocationPath();
}
public EventParam(
DhApiRenderParam renderParam,
long boxGroupId, String resourceLocationNamespace, String resourceLocationPath
)
{
super(renderParam);
this.boxGroupId = boxGroupId;
this.resourceLocationNamespace = resourceLocationNamespace;
this.resourceLocationPath = resourceLocationPath;
}
@Override
public EventParam copy()
{
return new EventParam(
this,
this.boxGroupId, this.resourceLocationNamespace, this.resourceLocationPath
);
}
}
}
@@ -0,0 +1,47 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.api.methods.events.abstractEvents;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
/**
* Called before Distant Horizons starts the cleanup process done after rendering generic objects. <br>
* This is called after all generic objects have finished rendering.
*
* @author James Seibel
* @version 2024-7-13
* @since API 3.0.0
*/
public abstract class DhApiBeforeGenericRenderCleanupEvent implements IDhApiEvent<DhApiRenderParam>
{
/** Fired before Distant Horizons starts the cleanup process once rendering has finished. */
public abstract void beforeCleanup(DhApiEventParam<DhApiRenderParam> event);
//=========================//
// internal DH API methods //
//=========================//
@Override
public final void fireEvent(DhApiEventParam<DhApiRenderParam> event) { this.beforeCleanup(event); }
}
@@ -0,0 +1,50 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.api.methods.events.abstractEvents;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
/**
* Called before Distant Horizons has started setting up OpenGL objects for rendering generic objects. <br>
* If you want to modify already bound DH OpenGL objects try using {@link DhApiBeforeGenericObjectRenderEvent}.
*
* @author James Seibel
* @version 2024-7-12
* @since API 3.0.0
*
* @see DhApiBeforeGenericObjectRenderEvent
*/
public abstract class DhApiBeforeGenericRenderSetupEvent implements IDhApiEvent<DhApiRenderParam>
{
/** Fired before Distant Horizons has started setting up OpenGL objects for rendering generic objects. */
public abstract void beforeSetup(DhApiEventParam<DhApiRenderParam> input);
//=========================//
// internal DH API methods //
//=========================//
@Override
public final void fireEvent(DhApiEventParam<DhApiRenderParam> input) { this.beforeSetup(input); }
}
@@ -29,11 +29,11 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
* *
* @author James Seibel * @author James Seibel
* @version 2024-1-31 * @version 2024-1-31
* @since API 1.1.0 * @since API 2.0.0
*/ */
public abstract class DhApiBeforeRenderCleanupEvent implements IDhApiEvent<DhApiRenderParam> public abstract class DhApiBeforeRenderCleanupEvent implements IDhApiEvent<DhApiRenderParam>
{ {
/** Fired before Distant Horizons renders LODs. */ /** Fired before Distant Horizons starts the cleanup process once rendering has finished. */
public abstract void beforeCleanup(DhApiEventParam<DhApiRenderParam> event); public abstract void beforeCleanup(DhApiEventParam<DhApiRenderParam> event);
@@ -31,7 +31,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
* *
* @author James Seibel * @author James Seibel
* @version 2023-1-31 * @version 2023-1-31
* @since API 1.1.0 * @since API 2.0.0
* *
* @see DhApiBeforeRenderEvent * @see DhApiBeforeRenderEvent
*/ */
@@ -29,7 +29,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
* *
* @author James Seibel * @author James Seibel
* @version 2024-1-31 * @version 2024-1-31
* @since API 1.1.0 * @since API 2.0.0
* *
* @see DhApiBeforeRenderPassEvent * @see DhApiBeforeRenderPassEvent
*/ */
@@ -31,7 +31,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
* *
* @author James Seibel * @author James Seibel
* @version 2024-1-31 * @version 2024-1-31
* @since API 1.1.0 * @since API 2.0.0
*/ */
public abstract class DhApiBeforeTextureClearEvent implements IDhApiCancelableEvent<DhApiRenderParam> public abstract class DhApiBeforeTextureClearEvent implements IDhApiCancelableEvent<DhApiRenderParam>
{ {
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.api.methods.events.abstractEvents;
import com.seibel.distanthorizons.api.interfaces.data.IDhApiTerrainDataRepo; import com.seibel.distanthorizons.api.interfaces.data.IDhApiTerrainDataRepo;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
/** /**
@@ -53,7 +54,7 @@ public abstract class DhApiChunkModifiedEvent implements IDhApiEvent<DhApiChunkM
// parameter object // // parameter object //
//==================// //==================//
public static class EventParam public static class EventParam implements IDhApiEventParam
{ {
/** The saved level. */ /** The saved level. */
public final IDhApiLevelWrapper levelWrapper; public final IDhApiLevelWrapper levelWrapper;
@@ -71,6 +72,15 @@ public abstract class DhApiChunkModifiedEvent implements IDhApiEvent<DhApiChunkM
this.chunkZ = chunkZ; this.chunkZ = chunkZ;
} }
@Override
public EventParam copy()
{
return new EventParam(
this.levelWrapper,
this.chunkX, this.chunkZ
);
}
} }
} }
@@ -20,6 +20,7 @@
package com.seibel.distanthorizons.api.methods.events.abstractEvents; package com.seibel.distanthorizons.api.methods.events.abstractEvents;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
/** /**
@@ -28,7 +29,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
* *
* @author James Seibel * @author James Seibel
* @version 2024-3-2 * @version 2024-3-2
* @since API 1.1.0 * @since API 2.0.0
*/ */
public abstract class DhApiColorDepthTextureCreatedEvent implements IDhApiEvent<DhApiColorDepthTextureCreatedEvent.EventParam> public abstract class DhApiColorDepthTextureCreatedEvent implements IDhApiEvent<DhApiColorDepthTextureCreatedEvent.EventParam>
{ {
@@ -48,7 +49,7 @@ public abstract class DhApiColorDepthTextureCreatedEvent implements IDhApiEvent<
// parameter object // // parameter object //
//==================// //==================//
public static class EventParam public static class EventParam implements IDhApiEventParam
{ {
/** Measured in pixels */ /** Measured in pixels */
public final int previousWidth; public final int previousWidth;
@@ -72,6 +73,16 @@ public abstract class DhApiColorDepthTextureCreatedEvent implements IDhApiEvent<
this.newHeight = newHeight; this.newHeight = newHeight;
} }
@Override
public EventParam copy()
{
return new EventParam(
this.previousWidth, this.previousHeight,
this.newWidth, this.newHeight
);
}
} }
} }
@@ -21,6 +21,7 @@ package com.seibel.distanthorizons.api.methods.events.abstractEvents;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
/** /**
@@ -49,13 +50,16 @@ public abstract class DhApiLevelLoadEvent implements IDhApiEvent<DhApiLevelLoadE
// parameter object // // parameter object //
//==================// //==================//
public static class EventParam public static class EventParam implements IDhApiEventParam
{ {
/** The newly loaded level. */ /** The newly loaded level. */
public final IDhApiLevelWrapper levelWrapper; public final IDhApiLevelWrapper levelWrapper;
public EventParam(IDhApiLevelWrapper newLevelWrapper) { this.levelWrapper = newLevelWrapper; } public EventParam(IDhApiLevelWrapper newLevelWrapper) { this.levelWrapper = newLevelWrapper; }
@Override
public EventParam copy() { return new EventParam(this.levelWrapper); }
} }
} }
@@ -19,9 +19,9 @@
package com.seibel.distanthorizons.api.methods.events.abstractEvents; package com.seibel.distanthorizons.api.methods.events.abstractEvents;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
/** /**
@@ -49,13 +49,16 @@ public abstract class DhApiLevelUnloadEvent implements IDhApiEvent<DhApiLevelUnl
// parameter object // // parameter object //
//==================// //==================//
public static class EventParam public static class EventParam implements IDhApiEventParam
{ {
/** The recently unloaded level. */ /** The recently unloaded level. */
public final IDhApiLevelWrapper levelWrapper; public final IDhApiLevelWrapper levelWrapper;
public EventParam(IDhApiLevelWrapper newLevelWrapper) { this.levelWrapper = newLevelWrapper; } public EventParam(IDhApiLevelWrapper newLevelWrapper) { this.levelWrapper = newLevelWrapper; }
@Override
public EventParam copy() { return new EventParam(this.levelWrapper); }
} }
} }
@@ -0,0 +1,13 @@
package com.seibel.distanthorizons.api.methods.events.interfaces;
import com.seibel.distanthorizons.api.interfaces.util.IDhApiCopyable;
/**
* @author James Seibel
* @version 2024-7-12
* @since API 3.0.0
*/
public interface IDhApiEventParam extends IDhApiCopyable
{
}
@@ -20,7 +20,8 @@
package com.seibel.distanthorizons.api.methods.events.sharedParameterObjects; package com.seibel.distanthorizons.api.methods.events.sharedParameterObjects;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass; import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
/** /**
* Contains information relevant to Distant Horizons and Minecraft rendering. * Contains information relevant to Distant Horizons and Minecraft rendering.
@@ -29,7 +30,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
* @version 2024-1-31 * @version 2024-1-31
* @since API 1.0.0 * @since API 1.0.0
*/ */
public class DhApiRenderParam public class DhApiRenderParam implements IDhApiEventParam
{ {
/** Indicates what render pass DH is currently rendering */ /** Indicates what render pass DH is currently rendering */
public final EDhApiRenderPass renderPass; public final EDhApiRenderPass renderPass;
@@ -49,18 +50,15 @@ public class DhApiRenderParam
public final float farClipPlane; public final float farClipPlane;
/** The projection matrix Minecraft is using to render this frame. */ /** The projection matrix Minecraft is using to render this frame. */
public final Mat4f mcProjectionMatrix; public final DhApiMat4f mcProjectionMatrix;
/** The model view matrix Minecraft is using to render this frame. */ /** The model view matrix Minecraft is using to render this frame. */
public final Mat4f mcModelViewMatrix; public final DhApiMat4f mcModelViewMatrix;
/** The projection matrix Distant Horizons is using to render this frame. */ /** The projection matrix Distant Horizons is using to render this frame. */
public final Mat4f dhProjectionMatrix; public final DhApiMat4f dhProjectionMatrix;
/** The model view matrix Distant Horizons is using to render this frame. */ /** The model view matrix Distant Horizons is using to render this frame. */
public final Mat4f dhModelViewMatrix; public final DhApiMat4f dhModelViewMatrix;
public final int lightmapBindingIndex = 0;
// TODO why is this here? wouldn't it make more sense to have this built into the vertex buffer data?
public final int worldYOffset; public final int worldYOffset;
@@ -69,24 +67,24 @@ public class DhApiRenderParam
// constructors // // constructors //
//==============// //==============//
public DhApiRenderParam(DhApiRenderParam parent) public DhApiRenderParam(DhApiRenderParam parent)
{ {
this( this(
parent.renderPass, parent.renderPass,
parent.partialTicks, parent.partialTicks,
parent.nearClipPlane, parent.farClipPlane, parent.nearClipPlane, parent.farClipPlane,
parent.mcProjectionMatrix, parent.mcModelViewMatrix, parent.mcProjectionMatrix.copy(), parent.mcModelViewMatrix.copy(),
parent.dhProjectionMatrix, parent.dhModelViewMatrix, parent.dhProjectionMatrix.copy(), parent.dhModelViewMatrix.copy(),
parent.worldYOffset parent.worldYOffset
); );
} }
public DhApiRenderParam( public DhApiRenderParam(
EDhApiRenderPass renderPass, EDhApiRenderPass renderPass,
float newPartialTicks, float newPartialTicks,
float nearClipPlane, float farClipPlane, float nearClipPlane, float farClipPlane,
Mat4f newMcProjectionMatrix, Mat4f newMcModelViewMatrix, DhApiMat4f newMcProjectionMatrix, DhApiMat4f newMcModelViewMatrix,
Mat4f newDhProjectionMatrix, Mat4f newDhModelViewMatrix, DhApiMat4f newDhProjectionMatrix, DhApiMat4f newDhModelViewMatrix,
int worldYOffset int worldYOffset
) )
{ {
@@ -107,4 +105,16 @@ public class DhApiRenderParam
} }
//================//
// base overrides //
//================//
@Override
public DhApiRenderParam copy()
{
return new DhApiRenderParam(this);
}
} }
@@ -21,16 +21,18 @@ package com.seibel.distanthorizons.api.objects.data;
import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory; import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory;
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator; import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
import org.apache.logging.log4j.LogManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* Contains a list of {@link DhApiTerrainDataPoint} representing the blocks in a Minecraft chunk. * Contains a list of {@link DhApiTerrainDataPoint} representing the blocks in a Minecraft chunk.
* *
* @author Builderb0y, James Seibel * @author Builderb0y, James Seibel
* @version 2023-12-21 * @version 2024-7-21
* @since API 1.1.0 * @since API 2.0.0
* *
* @see IDhApiWrapperFactory * @see IDhApiWrapperFactory
* @see DhApiTerrainDataPoint * @see DhApiTerrainDataPoint
@@ -41,8 +43,8 @@ public class DhApiChunk
public final int chunkPosX; public final int chunkPosX;
public final int chunkPosZ; public final int chunkPosZ;
public final int topYBlockPos;
public final int bottomYBlockPos; public final int bottomYBlockPos;
public final int topYBlockPos;
private final List<List<DhApiTerrainDataPoint>> dataPoints; private final List<List<DhApiTerrainDataPoint>> dataPoints;
@@ -52,12 +54,32 @@ public class DhApiChunk
// constructors // // constructors //
//==============// //==============//
/**
* Deprecated due to the topYBlockPos and bottomYBlockPos variables being put in the wrong order.
* They should have been in bottom -> top order.
*
* @see DhApiChunk#create(int, int, int, int)
*/
@Deprecated
public DhApiChunk(int chunkPosX, int chunkPosZ, int topYBlockPos, int bottomYBlockPos) public DhApiChunk(int chunkPosX, int chunkPosZ, int topYBlockPos, int bottomYBlockPos)
{ this(chunkPosX, chunkPosZ, bottomYBlockPos, topYBlockPos, false); }
/**
* @since API 3.0.0
*/
public static DhApiChunk create(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos)
{ return new DhApiChunk(chunkPosX, chunkPosZ, bottomYBlockPos, topYBlockPos, false); }
/**
* Only visible to internal DH methods
* @param ignoredParameter is only present to differentiate the two constructors and isn't actually used
*/
private DhApiChunk(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos, boolean ignoredParameter)
{ {
this.chunkPosX = chunkPosX; this.chunkPosX = chunkPosX;
this.chunkPosZ = chunkPosZ; this.chunkPosZ = chunkPosZ;
this.topYBlockPos = topYBlockPos;
this.bottomYBlockPos = bottomYBlockPos; this.bottomYBlockPos = bottomYBlockPos;
this.topYBlockPos = topYBlockPos;
// populate the array to prevent null pointers // populate the array to prevent null pointers
this.dataPoints = new ArrayList<>(16 * 16); // 256 this.dataPoints = new ArrayList<>(16 * 16); // 256
@@ -94,27 +116,34 @@ public class DhApiChunk
*/ */
public void setDataPoints(int relX, int relZ, List<DhApiTerrainDataPoint> dataPoints) throws IndexOutOfBoundsException, IllegalArgumentException public void setDataPoints(int relX, int relZ, List<DhApiTerrainDataPoint> dataPoints) throws IndexOutOfBoundsException, IllegalArgumentException
{ {
//==================//
// basic validation //
//==================//
// heavier validation is done in the world generator if requested
int internalArrayIndex = (relZ << 4) | relX;
throwIfRelativePosOutOfBounds(relX, relZ); throwIfRelativePosOutOfBounds(relX, relZ);
// validate the incoming datapoints if (dataPoints == null)
if (dataPoints != null)
{ {
for (int i = 0; i < dataPoints.size(); i++) // standard for-loop used instead of an enhanced for-loop to slightly reduce GC overhead due to iterator allocation // we don't allow null columns
{ throw new IllegalArgumentException("Null columns aren't allowed. If you want to remove all data from a column please clear the list or pass in an empty list.");
DhApiTerrainDataPoint dataPoint = dataPoints.get(i);
if (dataPoint == null)
{
throw new IllegalArgumentException("Null DhApiTerrainDataPoints are not allowed. If you want to represent empty terrain, please use AIR.");
}
if (dataPoint.detailLevel != 0)
{
throw new IllegalArgumentException("DhApiTerrainDataPoints has the wrong detail level ["+dataPoint.detailLevel+"], all data points must be block sized; IE their detail level must be [0].");
}
}
} }
this.dataPoints.set((relZ << 4) | relX, dataPoints);
//================//
// set datapoints //
//================//
List<DhApiTerrainDataPoint> column = this.dataPoints.get(internalArrayIndex);
if (column == null)
{
column = new ArrayList<>();
this.dataPoints.set(internalArrayIndex, column);
}
column.addAll(dataPoints);
} }
@@ -20,7 +20,6 @@
package com.seibel.distanthorizons.api.objects.data; package com.seibel.distanthorizons.api.objects.data;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i; import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
import com.seibel.distanthorizons.coreapi.util.math.Vec3i;
/** /**
* Holds a single datapoint of terrain data * Holds a single datapoint of terrain data
@@ -47,7 +46,7 @@ public class DhApiRaycastResult
public DhApiRaycastResult(DhApiTerrainDataPoint dataPoint, Vec3i blockPos) public DhApiRaycastResult(DhApiTerrainDataPoint dataPoint, DhApiVec3i blockPos)
{ {
this.dataPoint = dataPoint; this.dataPoint = dataPoint;
this.pos = blockPos; this.pos = blockPos;
@@ -19,14 +19,17 @@
package com.seibel.distanthorizons.api.objects.data; package com.seibel.distanthorizons.api.objects.data;
import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel;
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper; import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper;
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
import java.util.ArrayList;
/** /**
* Holds a single datapoint of terrain data. * Holds a single datapoint of terrain data.
* *
* @author James Seibel * @author James Seibel
* @version 2022-11-13 * @version 2024-7-20
* @since API 1.0.0 * @since API 1.0.0
*/ */
public class DhApiTerrainDataPoint public class DhApiTerrainDataPoint
@@ -37,27 +40,79 @@ public class DhApiTerrainDataPoint
* 2 = 4x4 blocks <br> * 2 = 4x4 blocks <br>
* 4 = chunk (16x16 blocks) <br> * 4 = chunk (16x16 blocks) <br>
* 9 = region (512x512 blocks) <br> * 9 = region (512x512 blocks) <br>
*
* @see EDhApiDetailLevel
*/ */
public final byte detailLevel; public final byte detailLevel;
public final int blockLightLevel; public final int blockLightLevel;
public final int skyLightLevel; public final int skyLightLevel;
public final int topYBlockPos;
public final int bottomYBlockPos; public final int bottomYBlockPos;
public final int topYBlockPos;
public final IDhApiBlockStateWrapper blockStateWrapper; public final IDhApiBlockStateWrapper blockStateWrapper;
public final IDhApiBiomeWrapper biomeWrapper; public final IDhApiBiomeWrapper biomeWrapper;
public DhApiTerrainDataPoint(byte detailLevel, int blockLightLevel, int skyLightLevel, int topYBlockPos, int bottomYBlockPos, IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper) //==============//
// constructors //
//==============//
/**
* Deprecated due to the topYBlockPos and bottomYBlockPos variables being put in the wrong order.
* They should have been in bottom -> top order.
*
* @see DhApiTerrainDataPoint#create(byte, int, int, int, int, IDhApiBlockStateWrapper, IDhApiBiomeWrapper)
*/
@Deprecated
public DhApiTerrainDataPoint(
byte detailLevel,
int blockLightLevel, int skyLightLevel,
int topYBlockPos, int bottomYBlockPos,
IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper)
{
this(detailLevel, blockLightLevel, skyLightLevel,
bottomYBlockPos, topYBlockPos,
blockStateWrapper, biomeWrapper,
false);
}
/**
* @since API 3.0.0
*/
public static DhApiTerrainDataPoint create(
byte detailLevel,
int blockLightLevel, int skyLightLevel,
int bottomYBlockPos, int topYBlockPos,
IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper
)
{
return new DhApiTerrainDataPoint(
detailLevel, blockLightLevel, skyLightLevel,
bottomYBlockPos, topYBlockPos,
blockStateWrapper, biomeWrapper,
false);
}
/**
* Only visible to internal DH methods
* @param ignoredParameter is only present to differentiate the two constructors and isn't actually used
*/
private DhApiTerrainDataPoint(
byte detailLevel,
int blockLightLevel, int skyLightLevel,
int bottomYBlockPos, int topYBlockPos,
IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper,
boolean ignoredParameter
)
{ {
this.detailLevel = detailLevel; this.detailLevel = detailLevel;
this.blockLightLevel = blockLightLevel; this.blockLightLevel = blockLightLevel;
this.skyLightLevel = skyLightLevel; this.skyLightLevel = skyLightLevel;
this.topYBlockPos = topYBlockPos;
this.bottomYBlockPos = bottomYBlockPos; this.bottomYBlockPos = bottomYBlockPos;
this.topYBlockPos = topYBlockPos;
this.blockStateWrapper = blockStateWrapper; this.blockStateWrapper = blockStateWrapper;
this.biomeWrapper = biomeWrapper; this.biomeWrapper = biomeWrapper;
@@ -17,46 +17,55 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.seibel.distanthorizons.coreapi.util.math; package com.seibel.distanthorizons.api.objects.math;
import org.joml.Matrix4f; import com.seibel.distanthorizons.api.interfaces.util.IDhApiCopyable;
import org.joml.Matrix4fc;
import java.nio.FloatBuffer;
/** /**
* An (almost) exact copy of Minecraft's 1.16.5 * An (almost) exact copy of Minecraft's 1.16.5
* implementation of a 4x4 float matrix. * implementation of a 4x4 float matrix. <br><br>
* *
* <code>
* m00, m10, m20, m30, <br>
* m01, m11, m21, m31, <br>
* m02, m12, m22, m32, <br>
* m03, m13, m23, m33 <br>
* </code>
*
* @author James Seibel * @author James Seibel
* @version 11-11-2021 * @version 2024-6-30
*/ */
public class Mat4f public class DhApiMat4f implements IDhApiCopyable
{ {
private float m00; public float m00;
private float m01; public float m01;
private float m02; public float m02;
private float m03; public float m03;
private float m10;
private float m11; public float m10;
private float m12; public float m11;
private float m13; public float m12;
private float m20; public float m13;
private float m21;
private float m22; public float m20;
private float m23; public float m21;
private float m30; public float m22;
private float m31; public float m23;
private float m32;
private float m33; public float m30;
public float m31;
public float m32;
public float m33;
public Mat4f()
{
}
public Mat4f(Mat4f sourceMatrix) //==============//
// constructors //
//==============//
public DhApiMat4f() { /* all values are 0 */ }
public DhApiMat4f(DhApiMat4f sourceMatrix)
{ {
this.m00 = sourceMatrix.m00; this.m00 = sourceMatrix.m00;
this.m01 = sourceMatrix.m01; this.m01 = sourceMatrix.m01;
@@ -76,163 +85,36 @@ public class Mat4f
this.m33 = sourceMatrix.m33; this.m33 = sourceMatrix.m33;
} }
public Mat4f(Matrix4fc sourceMatrix) { this(convertJomlMatrixToArray(sourceMatrix)); } /** Expects the values of the input array to be in row major order (AKA rows then columns) */
private static float[] convertJomlMatrixToArray(Matrix4fc sourceMatrix) public DhApiMat4f(float[] values)
{ {
FloatBuffer buffer = FloatBuffer.allocate(16); m00 = values[0];
m01 = values[1];
m02 = values[2];
m03 = values[3];
buffer.put(bufferIndex(0, 0), sourceMatrix.m00()); m10 = values[4];
buffer.put(bufferIndex(0, 1), sourceMatrix.m01()); m11 = values[5];
buffer.put(bufferIndex(0, 2), sourceMatrix.m02()); m12 = values[6];
buffer.put(bufferIndex(0, 3), sourceMatrix.m03()); m13 = values[7];
buffer.put(bufferIndex(1, 0), sourceMatrix.m10());
buffer.put(bufferIndex(1, 1), sourceMatrix.m11());
buffer.put(bufferIndex(1, 2), sourceMatrix.m12());
buffer.put(bufferIndex(1, 3), sourceMatrix.m13());
buffer.put(bufferIndex(2, 0), sourceMatrix.m20());
buffer.put(bufferIndex(2, 1), sourceMatrix.m21());
buffer.put(bufferIndex(2, 2), sourceMatrix.m22());
buffer.put(bufferIndex(2, 3), sourceMatrix.m23());
buffer.put(bufferIndex(3, 0), sourceMatrix.m30());
buffer.put(bufferIndex(3, 1), sourceMatrix.m31());
buffer.put(bufferIndex(3, 2), sourceMatrix.m32());
buffer.put(bufferIndex(3, 3), sourceMatrix.m33());
return buffer.array(); m20 = values[8];
} m21 = values[9];
m22 = values[10];
/* Quaternions are not currently needed/implemented m23 = values[11];
public Matrix4float(Quaternion p_i48104_1_)
{ m30 = values[12];
float f = p_i48104_1_.i(); m31 = values[13];
float f1 = p_i48104_1_.j(); m32 = values[14];
float f2 = p_i48104_1_.k(); m33 = values[15];
float f3 = p_i48104_1_.r();
float f4 = 2.0F * f * f;
float f5 = 2.0F * f1 * f1;
float f6 = 2.0F * f2 * f2;
this.m00 = 1.0F - f5 - f6;
this.m11 = 1.0F - f6 - f4;
this.m22 = 1.0F - f4 - f5;
this.m33 = 1.0F;
float f7 = f * f1;
float f8 = f1 * f2;
float f9 = f2 * f;
float f10 = f * f3;
float f11 = f1 * f3;
float f12 = f2 * f3;
this.m10 = 2.0F * (f7 + f12);
this.m01 = 2.0F * (f7 - f12);
this.m20 = 2.0F * (f9 - f11);
this.m02 = 2.0F * (f9 + f11);
this.m21 = 2.0F * (f8 + f10);
this.m12 = 2.0F * (f8 - f10);
}
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
else if (obj != null && this.getClass() == obj.getClass())
{
Mat4f otherMatrix = (Mat4f) obj;
return Float.compare(otherMatrix.m00, this.m00) == 0
&& Float.compare(otherMatrix.m01, this.m01) == 0
&& Float.compare(otherMatrix.m02, this.m02) == 0
&& Float.compare(otherMatrix.m03, this.m03) == 0
&& Float.compare(otherMatrix.m10, this.m10) == 0
&& Float.compare(otherMatrix.m11, this.m11) == 0
&& Float.compare(otherMatrix.m12, this.m12) == 0
&& Float.compare(otherMatrix.m13, this.m13) == 0
&& Float.compare(otherMatrix.m20, this.m20) == 0
&& Float.compare(otherMatrix.m21, this.m21) == 0
&& Float.compare(otherMatrix.m22, this.m22) == 0
&& Float.compare(otherMatrix.m23, this.m23) == 0
&& Float.compare(otherMatrix.m30, this.m30) == 0
&& Float.compare(otherMatrix.m31, this.m31) == 0
&& Float.compare(otherMatrix.m32, this.m32) == 0
&& Float.compare(otherMatrix.m33, this.m33) == 0;
}
else
{
return false;
}
}
@Override
public int hashCode()
{
int i = this.m00 != 0.0F ? Float.floatToIntBits(this.m00) : 0;
i = 31 * i + (this.m01 != 0.0F ? Float.floatToIntBits(this.m01) : 0);
i = 31 * i + (this.m02 != 0.0F ? Float.floatToIntBits(this.m02) : 0);
i = 31 * i + (this.m03 != 0.0F ? Float.floatToIntBits(this.m03) : 0);
i = 31 * i + (this.m10 != 0.0F ? Float.floatToIntBits(this.m10) : 0);
i = 31 * i + (this.m11 != 0.0F ? Float.floatToIntBits(this.m11) : 0);
i = 31 * i + (this.m12 != 0.0F ? Float.floatToIntBits(this.m12) : 0);
i = 31 * i + (this.m13 != 0.0F ? Float.floatToIntBits(this.m13) : 0);
i = 31 * i + (this.m20 != 0.0F ? Float.floatToIntBits(this.m20) : 0);
i = 31 * i + (this.m21 != 0.0F ? Float.floatToIntBits(this.m21) : 0);
i = 31 * i + (this.m22 != 0.0F ? Float.floatToIntBits(this.m22) : 0);
i = 31 * i + (this.m23 != 0.0F ? Float.floatToIntBits(this.m23) : 0);
i = 31 * i + (this.m30 != 0.0F ? Float.floatToIntBits(this.m30) : 0);
i = 31 * i + (this.m31 != 0.0F ? Float.floatToIntBits(this.m31) : 0);
i = 31 * i + (this.m32 != 0.0F ? Float.floatToIntBits(this.m32) : 0);
return 31 * i + (this.m33 != 0.0F ? Float.floatToIntBits(this.m33) : 0);
} }
@Override
public String toString()
{
return "Matrix4f:\n" +
this.m00 + " " + this.m01 + " " + this.m02 + " " + this.m03 + "\n" +
this.m10 + " " + this.m11 + " " + this.m12 + " " + this.m13 + "\n" +
this.m20 + " " + this.m21 + " " + this.m22 + " " + this.m23 + "\n" +
this.m30 + " " + this.m31 + " " + this.m32 + " " + this.m33 + "\n";
}
public void store(FloatBuffer floatBuffer) //=========//
{ // methods //
floatBuffer.put(bufferIndex(0, 0), this.m00); //=========//
floatBuffer.put(bufferIndex(0, 1), this.m01);
floatBuffer.put(bufferIndex(0, 2), this.m02);
floatBuffer.put(bufferIndex(0, 3), this.m03);
floatBuffer.put(bufferIndex(1, 0), this.m10);
floatBuffer.put(bufferIndex(1, 1), this.m11);
floatBuffer.put(bufferIndex(1, 2), this.m12);
floatBuffer.put(bufferIndex(1, 3), this.m13);
floatBuffer.put(bufferIndex(2, 0), this.m20);
floatBuffer.put(bufferIndex(2, 1), this.m21);
floatBuffer.put(bufferIndex(2, 2), this.m22);
floatBuffer.put(bufferIndex(2, 3), this.m23);
floatBuffer.put(bufferIndex(3, 0), this.m30);
floatBuffer.put(bufferIndex(3, 1), this.m31);
floatBuffer.put(bufferIndex(3, 2), this.m32);
floatBuffer.put(bufferIndex(3, 3), this.m33);
}
public Matrix4f createJomlMatrix()
{
return new Matrix4f(
this.m00, this.m10, this.m20, this.m30,
this.m01, this.m11, this.m21, this.m31,
this.m02, this.m12, this.m22, this.m32,
this.m03, this.m13, this.m23, this.m33
);
}
private static int bufferIndex(int xIndex, int zIndex)
{
return (zIndex * 4) + xIndex;
}
public void setIdentity() public void setIdentity()
{ {
@@ -341,7 +223,7 @@ public class Mat4f
} }
} }
public void multiply(Mat4f multMatrix) public void multiply(DhApiMat4f multMatrix)
{ {
float f = this.m00 * multMatrix.m00 + this.m01 * multMatrix.m10 + this.m02 * multMatrix.m20 + this.m03 * multMatrix.m30; float f = this.m00 * multMatrix.m00 + this.m01 * multMatrix.m10 + this.m02 * multMatrix.m20 + this.m03 * multMatrix.m30;
float f1 = this.m00 * multMatrix.m01 + this.m01 * multMatrix.m11 + this.m02 * multMatrix.m21 + this.m03 * multMatrix.m31; float f1 = this.m00 * multMatrix.m01 + this.m01 * multMatrix.m11 + this.m02 * multMatrix.m21 + this.m03 * multMatrix.m31;
@@ -377,13 +259,6 @@ public class Mat4f
this.m33 = f15; this.m33 = f15;
} }
/* Quaternions aren't currently needed/implemented
public void multiply(Quaternion p_226596_1_)
{
this.multiply(new Matrix4f(p_226596_1_));
}
*/
public void multiply(float scalar) public void multiply(float scalar)
{ {
this.m00 *= scalar; this.m00 *= scalar;
@@ -404,81 +279,6 @@ public class Mat4f
this.m33 *= scalar; this.m33 *= scalar;
} }
public static Mat4f perspective(double fov, float widthHeightRatio, float nearClipPlane, float farClipPlane)
{
float f = (float) (1.0D / Math.tan(fov * ((float) Math.PI / 180F) / 2.0D));
Mat4f matrix = new Mat4f();
matrix.m00 = f / widthHeightRatio;
matrix.m11 = f;
matrix.m22 = (farClipPlane + nearClipPlane) / (nearClipPlane - farClipPlane);
matrix.m32 = -1.0F;
matrix.m23 = 2.0F * farClipPlane * nearClipPlane / (nearClipPlane - farClipPlane);
return matrix;
}
/* not currently needed/implemented
* Also the parameter names should be double checked as they may be incorrect
public static Matrix4Float orthographic(float left, float right, float top, float bottom)
{
Matrix4Float matrix4f = new Matrix4Float();
matrix4f.m00 = 2.0F / left;
matrix4f.m11 = 2.0F / right;
float f = bottom - top;
matrix4f.m22 = -2.0F / f;
matrix4f.m33 = 1.0F;
matrix4f.m03 = -1.0F;
matrix4f.m13 = -1.0F;
matrix4f.m23 = -(bottom + top) / f;
return matrix4f;
}
*/
/**
* TODO: what kind of translation is this?
* and how is this different from "multiplyTranslationMatrix"?
* Answer: This is faster and direct (but only if this is pure translation matrix without rotate)
*/
public void translate(Vec3f vec)
{
this.m03 += vec.x;
this.m13 += vec.y;
this.m23 += vec.z;
}
/** originally "translate" from Minecraft's MatrixStack */
public void multiplyTranslationMatrix(double x, double y, double z)
{
multiply(createTranslateMatrix((float) x, (float) y, (float) z));
}
public Mat4f copy()
{
return new Mat4f(this);
}
public static Mat4f createScaleMatrix(float x, float y, float z)
{
Mat4f matrix = new Mat4f();
matrix.m00 = x;
matrix.m11 = y;
matrix.m22 = z;
matrix.m33 = 1.0F;
return matrix;
}
public static Mat4f createTranslateMatrix(float x, float y, float z)
{
Mat4f matrix = new Mat4f();
matrix.m00 = 1.0F;
matrix.m11 = 1.0F;
matrix.m22 = 1.0F;
matrix.m33 = 1.0F;
matrix.m03 = x;
matrix.m13 = y;
matrix.m23 = z;
return matrix;
}
@@ -487,6 +287,8 @@ public class Mat4f
// methods // // methods //
//==================// //==================//
private static int getArrayIndex(int xIndex, int zIndex) { return (zIndex * 4) + xIndex; }
/** Returns the values of this matrix in row major order (AKA rows then columns) */ /** Returns the values of this matrix in row major order (AKA rows then columns) */
public float[] getValuesAsArray() public float[] getValuesAsArray()
{ {
@@ -513,113 +315,77 @@ public class Mat4f
}; };
} }
public Vec3f asNonNormalizedLookForwardVector()
//================//
// base overrides //
//================//
@Override
public boolean equals(Object obj)
{ {
return new Vec3f(this.m02, this.m12, this.m22); if (this == obj)
{
return true;
}
else if (obj != null && this.getClass() == obj.getClass())
{
DhApiMat4f otherMatrix = (DhApiMat4f) obj;
return Float.compare(otherMatrix.m00, this.m00) == 0
&& Float.compare(otherMatrix.m01, this.m01) == 0
&& Float.compare(otherMatrix.m02, this.m02) == 0
&& Float.compare(otherMatrix.m03, this.m03) == 0
&& Float.compare(otherMatrix.m10, this.m10) == 0
&& Float.compare(otherMatrix.m11, this.m11) == 0
&& Float.compare(otherMatrix.m12, this.m12) == 0
&& Float.compare(otherMatrix.m13, this.m13) == 0
&& Float.compare(otherMatrix.m20, this.m20) == 0
&& Float.compare(otherMatrix.m21, this.m21) == 0
&& Float.compare(otherMatrix.m22, this.m22) == 0
&& Float.compare(otherMatrix.m23, this.m23) == 0
&& Float.compare(otherMatrix.m30, this.m30) == 0
&& Float.compare(otherMatrix.m31, this.m31) == 0
&& Float.compare(otherMatrix.m32, this.m32) == 0
&& Float.compare(otherMatrix.m33, this.m33) == 0;
}
else
{
return false;
}
} }
//===============// @Override
// Forge methods // public int hashCode()
//===============//
public Mat4f(float[] values)
{ {
m00 = values[0]; int i = this.m00 != 0.0F ? Float.floatToIntBits(this.m00) : 0;
m01 = values[1]; i = 31 * i + (this.m01 != 0.0F ? Float.floatToIntBits(this.m01) : 0);
m02 = values[2]; i = 31 * i + (this.m02 != 0.0F ? Float.floatToIntBits(this.m02) : 0);
m03 = values[3]; i = 31 * i + (this.m03 != 0.0F ? Float.floatToIntBits(this.m03) : 0);
m10 = values[4]; i = 31 * i + (this.m10 != 0.0F ? Float.floatToIntBits(this.m10) : 0);
m11 = values[5]; i = 31 * i + (this.m11 != 0.0F ? Float.floatToIntBits(this.m11) : 0);
m12 = values[6]; i = 31 * i + (this.m12 != 0.0F ? Float.floatToIntBits(this.m12) : 0);
m13 = values[7]; i = 31 * i + (this.m13 != 0.0F ? Float.floatToIntBits(this.m13) : 0);
m20 = values[8]; i = 31 * i + (this.m20 != 0.0F ? Float.floatToIntBits(this.m20) : 0);
m21 = values[9]; i = 31 * i + (this.m21 != 0.0F ? Float.floatToIntBits(this.m21) : 0);
m22 = values[10]; i = 31 * i + (this.m22 != 0.0F ? Float.floatToIntBits(this.m22) : 0);
m23 = values[11]; i = 31 * i + (this.m23 != 0.0F ? Float.floatToIntBits(this.m23) : 0);
m30 = values[12]; i = 31 * i + (this.m30 != 0.0F ? Float.floatToIntBits(this.m30) : 0);
m31 = values[13]; i = 31 * i + (this.m31 != 0.0F ? Float.floatToIntBits(this.m31) : 0);
m32 = values[14]; i = 31 * i + (this.m32 != 0.0F ? Float.floatToIntBits(this.m32) : 0);
m33 = values[15]; return 31 * i + (this.m33 != 0.0F ? Float.floatToIntBits(this.m33) : 0);
} }
public Mat4f(FloatBuffer buffer) @Override
public String toString()
{ {
this(buffer.array()); return "Matrix4f:\n" +
this.m00 + " " + this.m01 + " " + this.m02 + " " + this.m03 + "\n" +
this.m10 + " " + this.m11 + " " + this.m12 + " " + this.m13 + "\n" +
this.m20 + " " + this.m21 + " " + this.m22 + " " + this.m23 + "\n" +
this.m30 + " " + this.m31 + " " + this.m32 + " " + this.m33 + "\n";
} }
public void set(Mat4f mat) @Override
{ public DhApiMat4f copy() { return new DhApiMat4f(this); }
this.m00 = mat.m00;
this.m01 = mat.m01;
this.m02 = mat.m02;
this.m03 = mat.m03;
this.m10 = mat.m10;
this.m11 = mat.m11;
this.m12 = mat.m12;
this.m13 = mat.m13;
this.m20 = mat.m20;
this.m21 = mat.m21;
this.m22 = mat.m22;
this.m23 = mat.m23;
this.m30 = mat.m30;
this.m31 = mat.m31;
this.m32 = mat.m32;
this.m33 = mat.m33;
}
public void add(Mat4f other)
{
m00 += other.m00;
m01 += other.m01;
m02 += other.m02;
m03 += other.m03;
m10 += other.m10;
m11 += other.m11;
m12 += other.m12;
m13 += other.m13;
m20 += other.m20;
m21 += other.m21;
m22 += other.m22;
m23 += other.m23;
m30 += other.m30;
m31 += other.m31;
m32 += other.m32;
m33 += other.m33;
}
public void multiplyBackward(Mat4f other)
{
Mat4f copy = other.copy();
copy.multiply(this);
this.set(copy);
}
public void setTranslation(float x, float y, float z)
{
this.m00 = 1.0F;
this.m11 = 1.0F;
this.m22 = 1.0F;
this.m33 = 1.0F;
this.m03 = x;
this.m13 = y;
this.m23 = z;
}
/**
* Changes the values that store the clipping planes.
* Formula for calculating matrix values is the same that OpenGL uses when making matrices.
*
* @param nearClip New near clipping plane value.
* @param farClip New far clipping plane value.
*/
public void setClipPlanes(float nearClip, float farClip)
{
//convert to matrix values, formula copied from a textbook / openGL specification.
float matNearClip = -((farClip + nearClip) / (farClip - nearClip));
float matFarClip = -((2 * farClip * nearClip) / (farClip - nearClip));
//set new values for the clip planes.
this.m22 = matNearClip;
this.m23 = matFarClip;
}
} }
@@ -0,0 +1,94 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.api.objects.math;
/**
* Often used to store block positions or any other
* position in 3D space.
*
* @author James Seibel
* @version 2024-7-9
* @since API 3.0.0
*/
public class DhApiVec3d
{
public double x;
public double y;
public double z;
/** creates a Vec3 at (0,0,0) */
public DhApiVec3d()
{
this.x = 0;
this.y = 0;
this.z = 0;
}
public DhApiVec3d(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
else if (obj != null && this.getClass() == obj.getClass())
{
DhApiVec3d Vec3d = (DhApiVec3d) obj;
if (Double.compare(Vec3d.x, this.x) != 0)
{
return false;
}
else if (Double.compare(Vec3d.y, this.y) != 0)
{
return false;
}
else
{
return Double.compare(Vec3d.z, this.z) == 0;
}
}
else
{
return false;
}
}
@Override
public int hashCode()
{
long i = Double.doubleToLongBits(this.x);
i = 31 * i + Double.doubleToLongBits(this.y);
i = 31 * i + Double.doubleToLongBits(this.z);
return Long.hashCode(i);
}
@Override
public String toString() { return "[" + this.x + ", " + this.y + ", " + this.z + "]"; }
}
@@ -0,0 +1,98 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.api.objects.math;
import com.seibel.distanthorizons.api.interfaces.util.IDhApiCopyable;
/**
* Often used to store block positions or any other
* position in 3D space.
*
* @author James Seibel
* @version 2024-6-3
* @since API 2.2.0
*/
public class DhApiVec3f implements IDhApiCopyable
{
public float x;
public float y;
public float z;
/** creates a Vec3 at (0,0,0) */
public DhApiVec3f()
{
this.x = 0;
this.y = 0;
this.z = 0;
}
public DhApiVec3f(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
else if (obj != null && this.getClass() == obj.getClass())
{
DhApiVec3f Vec3f = (DhApiVec3f) obj;
if (Float.compare(Vec3f.x, this.x) != 0)
{
return false;
}
else if (Float.compare(Vec3f.y, this.y) != 0)
{
return false;
}
else
{
return Float.compare(Vec3f.z, this.z) == 0;
}
}
else
{
return false;
}
}
@Override
public int hashCode()
{
int i = Float.floatToIntBits(this.x);
i = 31 * i + Float.floatToIntBits(this.y);
return 31 * i + Float.floatToIntBits(this.z);
}
@Override
public String toString() { return "[" + this.x + ", " + this.y + ", " + this.z + "]"; }
@Override
public DhApiVec3f copy() { return new DhApiVec3f(this.x, this.y, this.z); }
}
@@ -0,0 +1,52 @@
package com.seibel.distanthorizons.api.objects.render;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import java.awt.*;
/**
* @see IDhApiRenderableBoxGroup
*
* @author James Seibel
* @version 2024-6-30
* @since API 3.0.0
*/
public class DhApiRenderableBox
{
/** the position closest to (-inf,-inf) */
public DhApiVec3d minPos;
/** the position closest to (+inf,+inf) */
public DhApiVec3d maxPos;
public Color color;
public byte material;
//==============//
// constructors //
//==============//
public DhApiRenderableBox(DhApiVec3d minPos, float width, Color color, EDhApiBlockMaterial material)
{
this(minPos, new DhApiVec3d(
minPos.x + width,
minPos.y + width,
minPos.z + width
), color, material);
}
public DhApiRenderableBox(DhApiVec3d minPos, DhApiVec3d maxPos, Color color, EDhApiBlockMaterial material)
{
this.minPos = minPos;
this.maxPos = maxPos;
this.color = color;
this.material = material.index;
}
}
@@ -0,0 +1,93 @@
package com.seibel.distanthorizons.api.objects.render;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import java.awt.*;
/**
* @see IDhApiRenderableBoxGroup
*
* Shading values are multiplied against the color for each direction,
* for example: <br>
* A shading value of 1.0 indicates the color is unchanged. <br>
* A shading value of 0.0 changes the color to black. <br>
*
* @author James Seibel
* @version 2024-7-7
* @since API 3.0.0
*/
public class DhApiRenderableBoxGroupShading
{
/** negative X */
public float north = 1.0f;
/** positive X */
public float south = 1.0f;
/** positive X */
public float east = 1.0f;
/** negative X */
public float west = 1.0f;
/** positive Y */
public float top = 1.0f;
/** negative Y */
public float bottom = 1.0f;
//==============//
// constructors //
//==============//
public static DhApiRenderableBoxGroupShading getDefaultShaded()
{
DhApiRenderableBoxGroupShading shading = new DhApiRenderableBoxGroupShading();
shading.setDefaultShaded();
return shading;
}
public static DhApiRenderableBoxGroupShading getUnshaded()
{
DhApiRenderableBoxGroupShading shading = new DhApiRenderableBoxGroupShading();
shading.setUnshaded();
return shading;
}
//=========//
// methods //
//=========//
/**
* Directions will have different brightness similar to Minecraft blocks. <br>
* This is a good default for un-lit objects.
*/
public void setDefaultShaded()
{
this.north = 0.8f;
this.south = 0.8f;
this.east = 0.6f;
this.west = 0.6f;
this.top = 1.0f;
this.bottom = 0.5f;
}
/**
* All directions render with the same brightness. <br>
* This is best used for glowing objects like beacons.
*/
public void setUnshaded()
{
this.north = 1.0f;
this.south = 1.0f;
this.east = 1.0f;
this.west = 1.0f;
this.top = 1.0f;
this.bottom = 1.0f;
}
}
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.coreapi.DependencyInjection;
import com.seibel.distanthorizons.api.interfaces.events.IDhApiEventInjector; import com.seibel.distanthorizons.api.interfaces.events.IDhApiEventInjector;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiCancelableEvent; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiCancelableEvent;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEvent;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiOneTimeEvent; import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiOneTimeEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiCancelableEventParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiCancelableEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
@@ -140,7 +141,26 @@ public class ApiEventInjector extends DependencyInjector<IDhApiEvent> implements
// fire each event and record if any of them // fire each event and record if any of them
// request to cancel the event. // request to cancel the event.
DhApiEventParam<T> eventParam = createEventParamWrapper(event, eventInput);
// attempt to clone the event input if possible
// this is done to reduce the likely hood that one event listener
// will make change the event parameter for other listeners
T input = eventInput;
if (eventInput instanceof IDhApiEventParam)
{
try
{
//noinspection unchecked
input = (T) ((IDhApiEventParam) eventInput).copy();
}
catch (Exception e)
{
LOGGER.error("Unable to clone event parameter ["+eventInput.getClass().getSimpleName()+"], error: ["+e.getMessage()+"].", e);
}
}
DhApiEventParam<T> eventParam = createEventParamWrapper(event, input);
event.fireEvent(eventParam); event.fireEvent(eventParam);
if (eventParam instanceof DhApiCancelableEventParam) if (eventParam instanceof DhApiCancelableEventParam)
@@ -26,29 +26,33 @@ package com.seibel.distanthorizons.coreapi;
public final class ModInfo public final class ModInfo
{ {
public static final String ID = "distanthorizons"; public static final String ID = "distanthorizons";
/** The internal protocol version used for networking */
public static final int PROTOCOL_VERSION = 1; public static final String RESOURCE_NAMESPACE = "distant_horizons";
/** The protocol version used for multiverse networking */ public static final String DEDICATED_SERVER_INITIAL_PATH = "dedicated_server_initial";
public static final int MULTIVERSE_PLUGIN_PROTOCOL_VERSION = 1;
// region Protocol versions
// Incremented every time any packets are added, changed or removed, with a few exceptions.
public static final int PROTOCOL_VERSION = 3;
public static final String WRAPPER_PACKET_PATH = "message";
// endregion
/** The internal mod name */ /** The internal mod name */
public static final String NAME = "DistantHorizons"; public static final String NAME = "DistantHorizons";
/** Human-readable version of NAME */ /** Human-readable version of NAME */
public static final String READABLE_NAME = "Distant Horizons"; public static final String READABLE_NAME = "Distant Horizons";
public static final String VERSION = "2.0.4-a-dev"; public static final String VERSION = "2.2.2-a-dev";
/** Returns true if the current build is an unstable developer build, false otherwise. */ /** Returns true if the current build is an unstable developer build, false otherwise. */
public static boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev"); public static boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
/** This version should only be updated when breaking changes are introduced to the DH API */ /** This version should only be updated when breaking changes are introduced to the DH API */
public static final int API_MAJOR_VERSION = 1; public static final int API_MAJOR_VERSION = 3;
/** This version should be updated whenever new methods are added to the DH API */ /** This version should be updated whenever new methods are added to the DH API */
public static final int API_MINOR_VERSION = 1; public static final int API_MINOR_VERSION = 0;
/** This version should be updated whenever non-breaking fixes are added to the DH API */ /** This version should be updated whenever non-breaking fixes are added to the DH API */
public static final int API_PATH_VERSION = 0; public static final int API_PATCH_VERSION = 1;
public static final String NETWORKING_RESOURCE_NAMESPACE = "distant_horizons";
public static final String MULTIVERSE_PLUGIN_NAMESPACE = "world_control";
/** All DH owned threads should start with this string to allow for easier debugging and profiling. */ /** All DH owned threads should start with this string to allow for easier debugging and profiling. */
public static final String THREAD_NAME_PREFIX = "DH-"; public static final String THREAD_NAME_PREFIX = "DH-";
} }
@@ -67,10 +67,11 @@ public interface IConfigEntry<T>
* Checks if the option is valid * Checks if the option is valid
* *
* 0 == valid * 0 == valid
* 2 == invalid
* 1 == number too high * 1 == number too high
* -1 == number too low * -1 == number too low
*/ */
byte isValid(); byte isValid(); // TODO replace with an enum
/** Checks if a value is valid */ /** Checks if a value is valid */
byte isValid(T value); byte isValid(T value);
@@ -24,12 +24,12 @@ import java.util.Arrays;
/** /**
* Miscellaneous string helper functions. * Miscellaneous string helper functions.
*
* @author James Seibel
* @version 2022-7-19
*/ */
public class StringUtil public class StringUtil
{ {
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
/** /**
* Returns the n-th index of the given string. <br> <br> * Returns the n-th index of the given string. <br> <br>
* *
@@ -67,8 +67,6 @@ public class StringUtil
return stringBuilder.toString(); return stringBuilder.toString();
} }
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
/** /**
* Converts the given byte array into a hex string representation. <br> * Converts the given byte array into a hex string representation. <br>
* source: https://stackoverflow.com/a/9855338 * source: https://stackoverflow.com/a/9855338
@@ -85,4 +83,20 @@ public class StringUtil
return new String(hexChars); return new String(hexChars);
} }
/**
* Returns a shortened version of the given string that is no longer than maxLength. <br>
* If null returns the empty string.
*/
public static String shortenString(String str, int maxLength)
{
if (str == null)
{
return "";
}
else
{
return str.substring(0, Math.min(str.length(), maxLength));
}
}
} }
@@ -1,263 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.coreapi.util.math;
import com.seibel.distanthorizons.coreapi.util.MathUtil;
/**
* A (almost) exact copy of Minecraft's 1.16.5
* implementation of a 3 element float vector.
*
* @author James Seibel
* @version 11-11-2021
*/
public class Vec3f
{
public static Vec3f XNeg = new Vec3f(-1.0F, 0.0F, 0.0F);
public static Vec3f XPos = new Vec3f(1.0F, 0.0F, 0.0F);
public static Vec3f YNeg = new Vec3f(0.0F, -1.0F, 0.0F);
public static Vec3f YPos = new Vec3f(0.0F, 1.0F, 0.0F);
public static Vec3f ZNeg = new Vec3f(0.0F, 0.0F, -1.0F);
public static Vec3f ZPos = new Vec3f(0.0F, 0.0F, 1.0F);
public float x;
public float y;
public float z;
public Vec3f()
{
}
public Vec3f(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
else if (obj != null && this.getClass() == obj.getClass())
{
Vec3f Vec3f = (Vec3f) obj;
if (Float.compare(Vec3f.x, this.x) != 0)
{
return false;
}
else if (Float.compare(Vec3f.y, this.y) != 0)
{
return false;
}
else
{
return Float.compare(Vec3f.z, this.z) == 0;
}
}
else
{
return false;
}
}
@Override
public int hashCode()
{
int i = Float.floatToIntBits(this.x);
i = 31 * i + Float.floatToIntBits(this.y);
return 31 * i + Float.floatToIntBits(this.z);
}
public void mul(float scalar)
{
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
}
public void mul(float x, float y, float z)
{
this.x *= x;
this.y *= y;
this.z *= z;
}
public void clamp(float min, float max)
{
this.x = MathUtil.clamp(min, this.x, max);
this.y = MathUtil.clamp(min, this.y, max);
this.z = MathUtil.clamp(min, this.z, max);
}
public void set(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
public void add(float x, float y, float z)
{
this.x += x;
this.y += y;
this.z += z;
}
public void add(Vec3f vector)
{
this.x += vector.x;
this.y += vector.y;
this.z += vector.z;
}
public void subtract(Vec3f vector)
{
this.x -= vector.x;
this.y -= vector.y;
this.z -= vector.z;
}
public float dotProduct(Vec3f vector)
{
return this.x * vector.x + this.y * vector.y + this.z * vector.z;
}
/** Returns true if normalization had to be done */
public boolean normalize()
{
float squaredSum = this.x * this.x + this.y * this.y + this.z * this.z;
if (squaredSum < 1.0E-5D)
{
return false;
}
else
{
float f1 = MathUtil.fastInvSqrt(squaredSum);
this.x *= f1;
this.y *= f1;
this.z *= f1;
return true;
}
}
public void crossProduct(Vec3f vector)
{
float f = this.x;
float f1 = this.y;
float f2 = this.z;
float f3 = vector.x;
float f4 = vector.y;
float f5 = vector.z;
this.x = f1 * f5 - f2 * f4;
this.y = f2 * f3 - f * f5;
this.z = f * f4 - f1 * f3;
}
/* Matrix3f is not currently needed/implemented
public void transform(Matrix3f p_229188_1_)
{
float f = this.x;
float f1 = this.y;
float f2 = this.z;
this.x = p_229188_1_.m00 * f + p_229188_1_.m01 * f1 + p_229188_1_.m02 * f2;
this.y = p_229188_1_.m10 * f + p_229188_1_.m11 * f1 + p_229188_1_.m12 * f2;
this.z = p_229188_1_.m20 * f + p_229188_1_.m21 * f1 + p_229188_1_.m22 * f2;
}
*/
/* Quaternions are not currently needed/implemented
public void transform(Quaternion p_214905_1_)
{
Quaternion quaternion = new Quaternion(p_214905_1_);
quaternion.mul(new Quaternion(this.x(), this.y(), this.z(), 0.0F));
Quaternion quaternion1 = new Quaternion(p_214905_1_);
quaternion1.conj();
quaternion.mul(quaternion1);
this.set(quaternion.i(), quaternion.j(), quaternion.k());
}
*/
/* not currently needed
* percent may actually be partial ticks (which is available when rendering)
public void linearInterp(Vec3f resultingVector, float percent)
{
float f = 1.0F - percent;
this.x = this.x * f + resultingVector.x * percent;
this.y = this.y * f + resultingVector.y * percent;
this.z = this.z * f + resultingVector.z * percent;
}
*/
/* Quaternions are not currently needed/implemented
public Quaternion rotation(float p_229193_1_)
{
return new Quaternion(this, p_229193_1_, false);
}
@OnlyIn(Dist.CLIENT)
public Quaternion rotationDegrees(float p_229187_1_)
{
return new Quaternion(this, p_229187_1_, true);
}
*/
public Vec3f copy()
{
return new Vec3f(this.x, this.y, this.z);
}
/* not currently needed/implemented
public void map(Float2FloatFunction p_229191_1_)
{
this.x = p_229191_1_.get(this.x);
this.y = p_229191_1_.get(this.y);
this.z = p_229191_1_.get(this.z);
}
*/
@Override
public String toString()
{
return "[" + this.x + ", " + this.y + ", " + this.z + "]";
}
// Forge start
public Vec3f(float[] values)
{
set(values);
}
public void set(float[] values)
{
this.x = values[0];
this.y = values[1];
this.z = values[2];
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
plugins { plugins {
id "java" id "java"
id "com.github.johnrengelman.shadow" version '7.1.2' apply false // Set this to true if you're using the standalone Core project id "com.github.johnrengelman.shadow" version '8.1.1' apply false // Set this to true if you're using the standalone Core project
} }
apply plugin: "application" apply plugin: "application"
@@ -57,7 +57,7 @@ artifacts {
} }
shadowJar { shadowJar {
def librariesLocation = "distanthorizons.libraries" def librariesLocation = "DistantHorizons.libraries"
// relocate "it.unimi.dsi.fastutil", "${librariesLocation}.unimi.dsi.fastutil" // relocate "it.unimi.dsi.fastutil", "${librariesLocation}.unimi.dsi.fastutil"
mergeServiceFiles() mergeServiceFiles()
} }
@@ -20,8 +20,10 @@
package com.seibel.distanthorizons.core; package com.seibel.distanthorizons.core;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.renderer.generic.GenericRenderObjectFactory;
import com.seibel.distanthorizons.core.sql.DatabaseUpdater; import com.seibel.distanthorizons.core.sql.DatabaseUpdater;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.world.DhApiWorldProxy; import com.seibel.distanthorizons.core.world.DhApiWorldProxy;
import com.seibel.distanthorizons.core.api.external.methods.config.DhApiConfig; import com.seibel.distanthorizons.core.api.external.methods.config.DhApiConfig;
@@ -76,16 +78,18 @@ public class Initializer
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if (SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class) != null)
// attempt to setup Swing so we can display dialogs (popup windows)
System.setProperty("java.awt.headless", "false");
if (GraphicsEnvironment.isHeadless())
{ {
LOGGER.warn("Java.awt.headless is false. This means Distant Horizons can't display error and info dialog windows."); // attempt to setup Swing so we can display dialogs (popup windows)
} System.setProperty("java.awt.headless", "false");
else if (GraphicsEnvironment.isHeadless())
{ {
LOGGER.info("Java.awt.headless set to true. Distant Horizons can correctly display error and info dialog windows."); LOGGER.warn("Java.awt.headless is false. This means Distant Horizons can't display error and info dialog windows.");
}
else
{
LOGGER.info("Java.awt.headless set to true. Distant Horizons can correctly display error and info dialog windows.");
}
} }
// link Core's config to the API // link Core's config to the API
@@ -93,6 +97,7 @@ public class Initializer
DhApi.Delayed.terrainRepo = DhApiTerrainDataRepo.INSTANCE; DhApi.Delayed.terrainRepo = DhApiTerrainDataRepo.INSTANCE;
DhApi.Delayed.worldProxy = DhApiWorldProxy.INSTANCE; DhApi.Delayed.worldProxy = DhApiWorldProxy.INSTANCE;
DhApi.Delayed.renderProxy = DhApiRenderProxy.INSTANCE; DhApi.Delayed.renderProxy = DhApiRenderProxy.INSTANCE;
DhApi.Delayed.customRenderObjectFactory = GenericRenderObjectFactory.INSTANCE;
DhApi.Delayed.wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class); DhApi.Delayed.wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
if (DhApi.Delayed.wrapperFactory == null) if (DhApi.Delayed.wrapperFactory == null)
{ {
@@ -101,4 +106,4 @@ public class Initializer
} }
} }
@@ -42,8 +42,6 @@ public class DhApiConfig implements IDhApiConfig
@Override @Override
public IDhApiMultiThreadingConfig multiThreading() { return DhApiMultiThreadingConfig.INSTANCE; } public IDhApiMultiThreadingConfig multiThreading() { return DhApiMultiThreadingConfig.INSTANCE; }
@Override @Override
public IDhApiGpuBuffersConfig gpuBuffers() { return DhApiGpuBuffersConfig.INSTANCE; }
@Override
public IDhApiDebuggingConfig debugging() { return DhApiDebuggingConfig.INSTANCE; } public IDhApiDebuggingConfig debugging() { return DhApiDebuggingConfig.INSTANCE; }
} }
@@ -20,23 +20,27 @@
package com.seibel.distanthorizons.core.api.external.methods.config.client; package com.seibel.distanthorizons.core.api.external.methods.config.client;
import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue; import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue;
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiGpuBuffersConfig; import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiGenericRenderingConfig;
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiNoiseTextureConfig;
import com.seibel.distanthorizons.api.objects.config.DhApiConfigValue; import com.seibel.distanthorizons.api.objects.config.DhApiConfigValue;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
public class DhApiGpuBuffersConfig implements IDhApiGpuBuffersConfig public class DhApiGenericRenderingConfig implements IDhApiGenericRenderingConfig
{ {
public static DhApiGpuBuffersConfig INSTANCE = new DhApiGpuBuffersConfig(); public static DhApiGenericRenderingConfig INSTANCE = new DhApiGenericRenderingConfig();
private DhApiGpuBuffersConfig() { } private DhApiGenericRenderingConfig() { }
public IDhApiConfigValue<EDhApiGpuUploadMethod> gpuUploadMethod() @Override
{ return new DhApiConfigValue<>(Config.Client.Advanced.GpuBuffers.gpuUploadMethod); } public IDhApiConfigValue<Boolean> renderingEnabled()
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.GenericRendering.enableRendering); }
public IDhApiConfigValue<Integer> gpuUploadPerMegabyteInMilliseconds() @Override
{ return new DhApiConfigValue<>(Config.Client.Advanced.GpuBuffers.gpuUploadPerMegabyteInMilliseconds); } public IDhApiConfigValue<Boolean> beaconRenderingEnabled()
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.GenericRendering.enableBeaconRendering); }
@Override
public IDhApiConfigValue<Boolean> cloudRenderingEnabled()
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.GenericRendering.enableCloudRendering); }
} }
@@ -22,10 +22,7 @@ package com.seibel.distanthorizons.core.api.external.methods.config.client;
import com.seibel.distanthorizons.api.enums.config.*; import com.seibel.distanthorizons.api.enums.config.*;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiTransparency; import com.seibel.distanthorizons.api.enums.rendering.EDhApiTransparency;
import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue; import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue;
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiAmbientOcclusionConfig; import com.seibel.distanthorizons.api.interfaces.config.client.*;
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiFogConfig;
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiGraphicsConfig;
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiNoiseTextureConfig;
import com.seibel.distanthorizons.api.objects.config.DhApiConfigValue; import com.seibel.distanthorizons.api.objects.config.DhApiConfigValue;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRendererMode; import com.seibel.distanthorizons.api.enums.rendering.EDhApiRendererMode;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
@@ -42,9 +39,14 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
// inner layers // // inner layers //
//==============// //==============//
@Override
public IDhApiFogConfig fog() { return DhApiFogConfig.INSTANCE; } public IDhApiFogConfig fog() { return DhApiFogConfig.INSTANCE; }
@Override
public IDhApiAmbientOcclusionConfig ambientOcclusion() { return DhApiAmbientOcclusionConfig.INSTANCE; } public IDhApiAmbientOcclusionConfig ambientOcclusion() { return DhApiAmbientOcclusionConfig.INSTANCE; }
@Override
public IDhApiNoiseTextureConfig noiseTexture() { return DhApiNoiseTextureConfig.INSTANCE; } public IDhApiNoiseTextureConfig noiseTexture() { return DhApiNoiseTextureConfig.INSTANCE; }
@Override
public IDhApiGenericRenderingConfig genericRendering() { return DhApiGenericRenderingConfig.INSTANCE; }
@@ -0,0 +1,87 @@
package com.seibel.distanthorizons.core.api.external.methods.data;
import com.seibel.distanthorizons.api.interfaces.data.IDhApiTerrainDataCache;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.lang.ref.SoftReference;
public class DhApiTerrainDataCache implements IDhApiTerrainDataCache
{
private final Object modificationLock = new Object();
private Long2ReferenceOpenHashMap<SoftReference<FullDataSourceV2>> posToFullDataRef = new Long2ReferenceOpenHashMap<>();
private static final Logger LOGGER = LogManager.getLogger(DhApiTerrainDataCache.class.getSimpleName());
//==================//
// internal methods //
//==================//
public void add(long pos, FullDataSourceV2 dataSource)
{
synchronized (this.modificationLock)
{
this.posToFullDataRef.put(pos, new SoftReference<>(dataSource));
}
}
@Nullable
public FullDataSourceV2 get(long pos)
{
synchronized (this.modificationLock)
{
SoftReference<FullDataSourceV2> ref = this.posToFullDataRef.get(pos);
if (ref != null)
{
return ref.get();
}
else
{
return null;
}
}
}
//=============//
// API methods //
//=============//
@Override
public void clear()
{
synchronized (this.modificationLock)
{
LongSet keySet = this.posToFullDataRef.keySet();
for (long pos : keySet)
{
SoftReference<FullDataSourceV2> dataRef = this.posToFullDataRef.remove(pos);
if (dataRef != null)
{
FullDataSourceV2 dataSource = dataRef.get();
if (dataSource != null)
{
try
{
dataSource.close();
}
catch (Exception e)
{
LOGGER.warn("Unable to close data source, error: [" + e.getMessage() + "].", e);
}
}
}
}
}
}
}
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.core.api.external.methods.data; package com.seibel.distanthorizons.core.api.external.methods.data;
import com.seibel.distanthorizons.api.interfaces.data.IDhApiTerrainDataCache;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.objects.DhApiResult; import com.seibel.distanthorizons.api.objects.DhApiResult;
import com.seibel.distanthorizons.api.objects.data.DhApiRaycastResult; import com.seibel.distanthorizons.api.objects.data.DhApiRaycastResult;
@@ -35,6 +36,7 @@ import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.util.FullDataPointUtil; import com.seibel.distanthorizons.core.util.FullDataPointUtil;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.RayCastUtil; import com.seibel.distanthorizons.core.util.RayCastUtil;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.world.AbstractDhWorld; import com.seibel.distanthorizons.core.world.AbstractDhWorld;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
@@ -43,12 +45,12 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRen
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
import com.seibel.distanthorizons.coreapi.util.math.Vec3d; import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f; import com.seibel.distanthorizons.core.util.math.Vec3i;
import com.seibel.distanthorizons.coreapi.util.math.Vec3i;
import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongArrayList;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@@ -56,9 +58,6 @@ import java.util.concurrent.ExecutionException;
/** /**
* Allows interfacing with the terrain data Distant Horizons has stored. * Allows interfacing with the terrain data Distant Horizons has stored.
*
* @author James Seibel
* @version 2022-11-19
*/ */
public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
{ {
@@ -68,12 +67,15 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
// debugging values // debugging values
private static volatile boolean debugThreadRunning = false; private static volatile boolean debugThreadRunning = false;
private static String currentDebugBiomeName = ""; private static DhApiTerrainDataCache debugDataCache = new DhApiTerrainDataCache();
private static int currentDebugBlockColorInt = -1;
private static DhApiVec3i currentDebugVec3i = new Vec3i(); private static DhApiVec3i currentDebugVec3i = new Vec3i();
//=============//
// constructor //
//=============//
private DhApiTerrainDataRepo() private DhApiTerrainDataRepo()
{ {
@@ -86,41 +88,32 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
//================// //================//
@Override @Override
public DhApiResult<DhApiTerrainDataPoint> getSingleDataPointAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosY, int blockPosZ) public DhApiResult<DhApiTerrainDataPoint> getSingleDataPointAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosY, int blockPosZ, @Nullable IDhApiTerrainDataCache dataCache)
{ { return getTerrainDataAtBlockYPos(levelWrapper, new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ), blockPosY, dataCache); }
return getTerrainDataAtBlockYPos(levelWrapper, new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ), blockPosY);
}
@Override @Override
public DhApiResult<DhApiTerrainDataPoint[]> getColumnDataAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosZ) public DhApiResult<DhApiTerrainDataPoint[]> getColumnDataAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosZ, @Nullable IDhApiTerrainDataCache dataCache)
{ { return getTerrainDataColumnArray(levelWrapper, new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ), null, dataCache); }
return getTerrainDataColumnArray(levelWrapper, new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ), null);
}
@Override @Override
public DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtChunkPos(IDhApiLevelWrapper levelWrapper, int chunkPosX, int chunkPosZ) public DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtChunkPos(IDhApiLevelWrapper levelWrapper, int chunkPosX, int chunkPosZ, @Nullable IDhApiTerrainDataCache dataCache)
{ { return getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, new DhLodPos(LodUtil.CHUNK_DETAIL_LEVEL, chunkPosX, chunkPosZ), dataCache); }
return getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, new DhLodPos(LodUtil.CHUNK_DETAIL_LEVEL, chunkPosX, chunkPosZ));
}
@Override @Override
public DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtRegionPos(IDhApiLevelWrapper levelWrapper, int regionPosX, int regionPosZ) public DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtRegionPos(IDhApiLevelWrapper levelWrapper, int regionPosX, int regionPosZ, @Nullable IDhApiTerrainDataCache dataCache)
{ { return getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, new DhLodPos(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ), dataCache); }
return getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, new DhLodPos(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ));
}
@Override @Override
public DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtDetailLevelAndPos(IDhApiLevelWrapper levelWrapper, byte detailLevel, int posX, int posZ) public DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtDetailLevelAndPos(IDhApiLevelWrapper levelWrapper, byte detailLevel, int posX, int posZ, @Nullable IDhApiTerrainDataCache dataCache)
{ { return getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, new DhLodPos(detailLevel, posX, posZ), dataCache); }
return getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, new DhLodPos(detailLevel, posX, posZ));
}
// private getters // // private getters //
/** Returns a single API terrain datapoint that contains the given Y block position */ /** Returns a single API terrain datapoint that contains the given Y block position */
private static DhApiResult<DhApiTerrainDataPoint> getTerrainDataAtBlockYPos(IDhApiLevelWrapper levelWrapper, DhLodPos requestedColumnPos, Integer blockYPos) private static DhApiResult<DhApiTerrainDataPoint> getTerrainDataAtBlockYPos(IDhApiLevelWrapper levelWrapper, DhLodPos requestedColumnPos, Integer blockYPos, @Nullable IDhApiTerrainDataCache dataCache)
{ {
DhApiResult<DhApiTerrainDataPoint[]> result = getTerrainDataColumnArray(levelWrapper, requestedColumnPos, blockYPos); DhApiResult<DhApiTerrainDataPoint[]> result = getTerrainDataColumnArray(levelWrapper, requestedColumnPos, blockYPos, dataCache);
if (result.success && result.payload.length > 0) if (result.success && result.payload.length > 0)
{ {
return DhApiResult.createSuccess(result.message, result.payload[0]); return DhApiResult.createSuccess(result.message, result.payload[0]);
@@ -140,7 +133,9 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
* *
* will stop and return the in progress data if any errors are encountered. * will stop and return the in progress data if any errors are encountered.
*/ */
private static DhApiResult<DhApiTerrainDataPoint[][][]> getTerrainDataOverAreaForPositionDetailLevel(IDhApiLevelWrapper levelWrapper, DhLodPos requestedAreaPos) private static DhApiResult<DhApiTerrainDataPoint[][][]> getTerrainDataOverAreaForPositionDetailLevel(
IDhApiLevelWrapper levelWrapper, DhLodPos requestedAreaPos,
@Nullable IDhApiTerrainDataCache dataCache)
{ {
DhLodPos startingBlockPos = requestedAreaPos.getCornerLodPos(LodUtil.BLOCK_DETAIL_LEVEL); DhLodPos startingBlockPos = requestedAreaPos.getCornerLodPos(LodUtil.BLOCK_DETAIL_LEVEL);
int widthOfAreaInBlocks = BitShiftUtil.powerOfTwo(requestedAreaPos.detailLevel); int widthOfAreaInBlocks = BitShiftUtil.powerOfTwo(requestedAreaPos.detailLevel);
@@ -154,7 +149,7 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
for (int z = 0; z < widthOfAreaInBlocks; z++) for (int z = 0; z < widthOfAreaInBlocks; z++)
{ {
DhLodPos blockColumnPos = new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, startingBlockPos.x + x, startingBlockPos.z + z); DhLodPos blockColumnPos = new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, startingBlockPos.x + x, startingBlockPos.z + z);
DhApiResult<DhApiTerrainDataPoint[]> result = getTerrainDataColumnArray(levelWrapper, blockColumnPos, null); DhApiResult<DhApiTerrainDataPoint[]> result = getTerrainDataColumnArray(levelWrapper, blockColumnPos, null, dataCache);
if (result.success) if (result.success)
{ {
returnArray[x][z] = result.payload; returnArray[x][z] = result.payload;
@@ -177,8 +172,15 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
* If the ApiResult is successful there will be an array of data. <br> * If the ApiResult is successful there will be an array of data. <br>
* The returned array will be empty if no data could be retrieved. * The returned array will be empty if no data could be retrieved.
*/ */
private static DhApiResult<DhApiTerrainDataPoint[]> getTerrainDataColumnArray(IDhApiLevelWrapper levelWrapper, DhLodPos requestedColumnPos, Integer nullableBlockYPos) private static DhApiResult<DhApiTerrainDataPoint[]> getTerrainDataColumnArray(
IDhApiLevelWrapper levelWrapper,
DhLodPos requestedColumnPos, Integer nullableBlockYPos,
@Nullable IDhApiTerrainDataCache apiDataCache)
{ {
//============//
// validation //
//============//
AbstractDhWorld currentWorld = SharedApi.getAbstractDhWorld(); AbstractDhWorld currentWorld = SharedApi.getAbstractDhWorld();
if (currentWorld == null) if (currentWorld == null)
{ {
@@ -194,6 +196,15 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper; ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
if (!(apiDataCache instanceof DhApiTerrainDataCache))
{
// custom level wrappers aren't supported,
// the API user must get a level wrapper from our code somewhere
return DhApiResult.createFail("Unsupported [" + IDhApiTerrainDataCache.class.getSimpleName() + "] implementation, only the core class [" + DhApiTerrainDataCache.class.getSimpleName() + "] is a valid parameter.");
}
DhApiTerrainDataCache dataCache = (DhApiTerrainDataCache) apiDataCache;
IDhLevel level = currentWorld.getLevel(coreLevelWrapper); IDhLevel level = currentWorld.getLevel(coreLevelWrapper);
if (level == null) if (level == null)
{ {
@@ -209,70 +220,96 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
DhLodPos relativePos = requestedColumnPos.getDhSectionRelativePositionForDetailLevel(); DhLodPos relativePos = requestedColumnPos.getDhSectionRelativePositionForDetailLevel();
//=====================//
// get the data source //
//=====================//
try try
{ {
// attempt to get/generate the data source for this section FullDataSourceV2 dataSource = null;
FullDataSourceV2 dataSource = level.getFullDataProvider().getAsync(sectionPos).get();
// try using the cached data if possible
if (dataCache != null)
{
dataSource = dataCache.get(sectionPos);
}
if (dataSource == null) if (dataSource == null)
{ {
return DhApiResult.createFail("Unable to find/generate any data at the " + DhSectionPos.class.getSimpleName() + " [" + DhSectionPos.toString(sectionPos) + "]."); // attempt to get/generate the data source for this section
} dataSource = level.getFullDataProvider().getAsync(sectionPos).get();
else if (dataSource == null)
{
// attempt to get the LOD data from the data source
FullDataPointIdMap mapping = dataSource.mapping;
LongArrayList dataColumn = dataSource.get(relativePos.x, relativePos.z);
if (dataColumn != null)
{ {
int dataColumnIndexCount = dataColumn.size(); return DhApiResult.createFail("Unable to find/generate any data at the " + DhSectionPos.class.getSimpleName() + " [" + DhSectionPos.toString(sectionPos) + "].");
DhApiTerrainDataPoint[] returnArray = new DhApiTerrainDataPoint[dataColumnIndexCount]; }
long dataPoint; dataCache.add(sectionPos, dataSource);
}
//===============================//
// get LOD data from data source //
//===============================//
FullDataPointIdMap mapping = dataSource.mapping;
LongArrayList dataColumn = dataSource.get(relativePos.x, relativePos.z);
if (dataColumn != null)
{
int dataColumnIndexCount = dataColumn.size();
DhApiTerrainDataPoint[] returnArray = new DhApiTerrainDataPoint[dataColumnIndexCount];
long dataPoint;
boolean getSpecificYCoordinate = nullableBlockYPos != null;
int levelMinimumHeight = levelWrapper.getMinHeight();
// search for a datapoint that contains the block y position
for (int i = 0; i < dataColumnIndexCount; i++)
{
dataPoint = dataColumn.getLong(i);
boolean getSpecificYCoordinate = nullableBlockYPos != null; if (!getSpecificYCoordinate)
int levelMinimumHeight = levelWrapper.getMinHeight();
// search for a datapoint that contains the block y position
for (int i = 0; i < dataColumnIndexCount; i++)
{ {
dataPoint = dataColumn.getLong(i); // if we aren't look for a specific datapoint, add each datapoint to the return array
returnArray[i] = generateApiDatapoint(levelWrapper, mapping, requestedDetailLevel, dataPoint);
if (!getSpecificYCoordinate) }
else
{
// we are looking for a specific datapoint,
// don't look at null ones
if (dataPoint != 0)
{ {
// if we aren't look for a specific datapoint, add each datapoint to the return array int requestedY = nullableBlockYPos;
returnArray[i] = generateApiDatapoint(levelWrapper, mapping, requestedDetailLevel, dataPoint); int bottomY = FullDataPointUtil.getBottomY(dataPoint) + levelMinimumHeight;
} int height = FullDataPointUtil.getHeight(dataPoint);
else int topY = bottomY + height;
{
// we are looking for a specific datapoint, // does this datapoint contain the requested Y position?
// don't look at null ones if (bottomY <= requestedY && requestedY < topY) // blockPositions start from the bottom of the block, thus "<=" for bottomY, just "<" for topY
if (dataPoint != 0)
{ {
int requestedY = nullableBlockYPos; // this datapoint contains the requested block position, return it
int bottomY = FullDataPointUtil.getBottomY(dataPoint) + levelMinimumHeight; DhApiTerrainDataPoint apiTerrainData = generateApiDatapoint(levelWrapper, mapping, requestedDetailLevel, dataPoint);
int height = FullDataPointUtil.getHeight(dataPoint); return DhApiResult.createSuccess(new DhApiTerrainDataPoint[]{apiTerrainData});
int topY = bottomY + height;
// does this datapoint contain the requested Y position?
if (bottomY <= requestedY && requestedY < topY) // blockPositions start from the bottom of the block, thus "<=" for bottomY, just "<" for topY
{
// this datapoint contains the requested block position, return it
DhApiTerrainDataPoint apiTerrainData = generateApiDatapoint(levelWrapper, mapping, requestedDetailLevel, dataPoint);
return DhApiResult.createSuccess(new DhApiTerrainDataPoint[]{apiTerrainData});
}
} }
} }
} }
// return all collected data
return DhApiResult.createSuccess(returnArray);
} }
// the requested data wasn't present in this column (and/or the column wasn't able to be accessed/generated) // return all collected data
return DhApiResult.createSuccess(new DhApiTerrainDataPoint[0]); return DhApiResult.createSuccess(returnArray);
} }
// the requested data wasn't present in this column (and/or the column wasn't able to be accessed/generated)
return DhApiResult.createSuccess(new DhApiTerrainDataPoint[0]);
} }
catch (InterruptedException | ExecutionException e) catch (InterruptedException | ExecutionException e)
{
// shouldn't normally happen, but just in case
LOGGER.error("getTerrainDataColumnArray operation canceled. Error: [" + e.getMessage() + "]", e);
return DhApiResult.createFail("Operation cancled before it could complete: [" + e.getMessage() + "].");
}
catch (Exception e)
{ {
// shouldn't normally happen, but just in case // shouldn't normally happen, but just in case
LOGGER.error("Unexpected exception in getTerrainDataColumnArray. Error: [" + e.getMessage() + "]", e); LOGGER.error("Unexpected exception in getTerrainDataColumnArray. Error: [" + e.getMessage() + "]", e);
@@ -289,9 +326,10 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
int height = FullDataPointUtil.getHeight(dataPoint); int height = FullDataPointUtil.getHeight(dataPoint);
int topY = bottomY + height; int topY = bottomY + height;
return new DhApiTerrainDataPoint(detailLevel, return DhApiTerrainDataPoint.create(
detailLevel,
FullDataPointUtil.getBlockLight(dataPoint), FullDataPointUtil.getSkyLight(dataPoint), FullDataPointUtil.getBlockLight(dataPoint), FullDataPointUtil.getSkyLight(dataPoint),
topY, bottomY, bottomY, topY,
blockState, biomeWrapper); blockState, biomeWrapper);
} }
@@ -306,9 +344,11 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
IDhApiLevelWrapper levelWrapper, IDhApiLevelWrapper levelWrapper,
double rayOriginX, double rayOriginY, double rayOriginZ, double rayOriginX, double rayOriginY, double rayOriginZ,
float rayDirectionX, float rayDirectionY, float rayDirectionZ, float rayDirectionX, float rayDirectionY, float rayDirectionZ,
int maxRayBlockLength) int maxRayBlockLength,
@Nullable
IDhApiTerrainDataCache dataCache)
{ {
return this.raycastLodData(levelWrapper, new Vec3d(rayOriginX, rayOriginY, rayOriginZ), new Vec3f(rayDirectionX, rayDirectionY, rayDirectionZ), maxRayBlockLength); return this.raycastLodData(levelWrapper, new Vec3d(rayOriginX, rayOriginY, rayOriginZ), new Vec3f(rayDirectionX, rayDirectionY, rayDirectionZ), maxRayBlockLength, dataCache);
} }
/** /**
@@ -317,12 +357,17 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
* Works by walking through the world and attempting to get the LOD <br> * Works by walking through the world and attempting to get the LOD <br>
* data present at each step. * data present at each step.
*/ */
private DhApiResult<DhApiRaycastResult> raycastLodData(IDhApiLevelWrapper levelWrapper, Vec3d rayOrigin, Vec3f rayDirection, int maxRayBlockLength) private DhApiResult<DhApiRaycastResult> raycastLodData(
IDhApiLevelWrapper levelWrapper,
Vec3d rayOrigin, Vec3f rayDirection,
int maxRayBlockLength,
@Nullable
IDhApiTerrainDataCache dataCache)
{ {
rayDirection.normalize(); rayDirection.normalize();
int minBlockHeight = levelWrapper.getMinHeight(); int minBlockHeight = levelWrapper.getMinHeight();
int maxBlockHeight = levelWrapper.getHeight(); int maxBlockHeight = levelWrapper.getMaxHeight();
@@ -346,7 +391,7 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
for (Vec3i columnPos : columnPositions) for (Vec3i columnPos : columnPositions)
{ {
// check each column // check each column
DhApiResult<DhApiTerrainDataPoint[]> result = this.getColumnDataAtBlockPos(levelWrapper, columnPos.x, columnPos.z); DhApiResult<DhApiTerrainDataPoint[]> result = this.getColumnDataAtBlockPos(levelWrapper, columnPos.x, columnPos.z, dataCache);
if (!result.success) if (!result.success)
{ {
// if there was an error, stop and return it // if there was an error, stop and return it
@@ -414,7 +459,7 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
*/ */
private static ArrayList<Vec3i> getIntersectingColumnsAtPosition(Vec3i rayEndingPos, Vec3f rayDirection) private static ArrayList<Vec3i> getIntersectingColumnsAtPosition(Vec3i rayEndingPos, Vec3f rayDirection)
{ {
ArrayList<Vec3i> returnList = new ArrayList<Vec3i>(9); ArrayList<Vec3i> returnList = new ArrayList<>(9);
for (int x = -1; x <= 1; x++) for (int x = -1; x <= 1; x++)
{ {
@@ -469,6 +514,15 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
//=============//
// API helpers //
//=============//
@Override
public IDhApiTerrainDataCache getSoftCache() { return new DhApiTerrainDataCache(); }
//===============// //===============//
// debug methods // // debug methods //
//===============// //===============//
@@ -485,15 +539,15 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
Thread thread = new Thread(() -> { Thread thread = new Thread(() -> {
try try
{ {
DhApiResult<DhApiTerrainDataPoint> single = getTerrainDataAtBlockYPos(levelWrapper, new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ), blockPosY); DhApiResult<DhApiTerrainDataPoint> single = getTerrainDataAtBlockYPos(levelWrapper, new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ), blockPosY, debugDataCache);
DhApiResult<DhApiTerrainDataPoint[]> column = getTerrainDataColumnArray(levelWrapper, new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ), null); DhApiResult<DhApiTerrainDataPoint[]> column = getTerrainDataColumnArray(levelWrapper, new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ), null, debugDataCache);
DhLodPos chunkPos = new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ).convertToDetailLevel(LodUtil.CHUNK_DETAIL_LEVEL); DhLodPos chunkPos = new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ).convertToDetailLevel(LodUtil.CHUNK_DETAIL_LEVEL);
DhApiResult<DhApiTerrainDataPoint[][][]> area = getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, chunkPos); DhApiResult<DhApiTerrainDataPoint[][][]> area = getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, chunkPos, debugDataCache);
IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
DhApiResult<DhApiRaycastResult> rayCast = INSTANCE.raycastLodData(levelWrapper, MC_RENDER.getCameraExactPosition(), MC_RENDER.getLookAtVector(), 1000); DhApiResult<DhApiRaycastResult> rayCast = INSTANCE.raycastLodData(levelWrapper, MC_RENDER.getCameraExactPosition(), MC_RENDER.getLookAtVector(), 1000, debugDataCache);
if (rayCast.payload != null && !rayCast.payload.pos.equals(currentDebugVec3i)) if (rayCast.payload != null && !rayCast.payload.pos.equals(currentDebugVec3i))
{ {
currentDebugVec3i = rayCast.payload.pos; currentDebugVec3i = rayCast.payload.pos;
@@ -23,39 +23,43 @@ import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass; import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*; import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.render.DhApiRenderProxy; import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
import com.seibel.distanthorizons.core.util.TimerUtil;
import com.seibel.distanthorizons.core.util.objects.Pair; import com.seibel.distanthorizons.core.util.objects.Pair;
import com.seibel.distanthorizons.core.world.*;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.level.IDhClientLevel;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
import com.seibel.distanthorizons.core.network.session.Session;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiDebugRendering; import com.seibel.distanthorizons.api.enums.rendering.EDhApiDebugRendering;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRendererMode; import com.seibel.distanthorizons.api.enums.rendering.EDhApiRendererMode;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger; import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger;
import com.seibel.distanthorizons.core.logging.SpamReducedLogger; import com.seibel.distanthorizons.core.logging.SpamReducedLogger;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.render.glObject.GLProxy; import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.render.renderer.TestRenderer; import com.seibel.distanthorizons.core.render.renderer.TestRenderer;
import com.seibel.distanthorizons.core.util.RenderUtil; import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.world.AbstractDhWorld;
import com.seibel.distanthorizons.core.world.DhClientServerWorld;
import com.seibel.distanthorizons.core.world.DhClientWorld;
import com.seibel.distanthorizons.core.world.IDhClientWorld;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
//import io.netty.buffer.ByteBuf;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import java.util.HashMap; import java.io.File;
import java.util.HashSet; import java.util.*;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -71,15 +75,14 @@ public class ClientApi
public static boolean prefLoggerEnabled = false; public static boolean prefLoggerEnabled = false;
public static final ClientApi INSTANCE = new ClientApi(); public static final ClientApi INSTANCE = new ClientApi();
public static TestRenderer testRenderer = new TestRenderer(); public static final TestRenderer TEST_RENDERER = new TestRenderer();
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class);
public static final long SPAM_LOGGER_FLUSH_NS = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); public static final long SPAM_LOGGER_FLUSH_NS = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
private boolean configOverrideReminderPrinted = false; private boolean configOverrideReminderPrinted = false;
private boolean lowMemoryWarningPrinted = false;
private final Queue<String> chatMessageQueueForNextFrame = new LinkedBlockingQueue<>(); private final Queue<String> chatMessageQueueForNextFrame = new LinkedBlockingQueue<>();
@@ -87,10 +90,11 @@ public class ClientApi
private long lastFlushNanoTime = 0; private long lastFlushNanoTime = 0;
private boolean isServerCommunicationEnabled = false; private final ClientPluginChannelApi pluginChannelApi = new ClientPluginChannelApi(this::clientLevelLoadEvent, this::clientLevelUnloadEvent);
/** set to true if any unexpected responses are received from the server */ // Delay loading the first level to give server some time to respond with level to actually load
private boolean serverNetworkingIsMalformed = false; private Timer firstLevelLoadTimer;
private static final long FIRST_LEVEL_LOAD_DELAY = 1000;
/** Holds any levels that were loaded before the {@link ClientApi#onClientOnlyConnected} was fired. */ /** Holds any levels that were loaded before the {@link ClientApi#onClientOnlyConnected} was fired. */
public final HashSet<IClientLevelWrapper> waitingClientLevels = new HashSet<>(); public final HashSet<IClientLevelWrapper> waitingClientLevels = new HashSet<>();
@@ -124,14 +128,36 @@ public class ClientApi
public synchronized void onClientOnlyConnected() public synchronized void onClientOnlyConnected()
{ {
// only continue if the client is connected to a different server // only continue if the client is connected to a different server
if (MC.clientConnectedToDedicatedServer()) boolean connectedToServer = MC.clientConnectedToDedicatedServer();
boolean connectedToReplay = MC.connectedToReplay();
if (connectedToServer || connectedToReplay)
{ {
LOGGER.info("Client on ClientOnly mode connecting."); if (connectedToServer)
{
LOGGER.info("Client on ClientOnly mode connecting.");
}
else
{
LOGGER.info("Replay on ClientServer mode connecting.");
if (Config.Client.Advanced.Logging.showReplayWarningOnStartup.get())
{
MC.sendChatMessage("\u00A76" + "Distant Horizons: Replay detected." + "\u00A7r"); // gold color
MC.sendChatMessage("DH may behave strangely or have missing functionality.");
MC.sendChatMessage("In order to use pre-generated LODs, put your DH database(s) in:");
MC.sendChatMessage("\u00A77"+".Minecraft" + File.separator + ClientOnlySaveStructure.SERVER_DATA_FOLDER_NAME + File.separator + ClientOnlySaveStructure.REPLAY_SERVER_FOLDER_NAME + File.separator + "DIMENSION_NAME"+"\u00A7r"); // light gray color
MC.sendChatMessage("This can be disabled in DH's config under Advanced -> Logging.");
MC.sendChatMessage("");
}
}
// firing after clientLevelLoadEvent // firing after clientLevelLoadEvent
// TODO if level has prepped to load it should fire level load event // TODO if level has prepped to load it should fire level load event
SharedApi.setDhWorld(new DhClientWorld()); DhClientWorld world = new DhClientWorld();
SharedApi.setDhWorld(world);
this.pluginChannelApi.onJoin(world.networkState.getSession());
world.networkState.sendConfigMessage();
LOGGER.info("Loading [" + this.waitingClientLevels.size() + "] waiting client level wrappers."); LOGGER.info("Loading [" + this.waitingClientLevels.size() + "] waiting client level wrappers.");
for (IClientLevelWrapper level : this.waitingClientLevels) for (IClientLevelWrapper level : this.waitingClientLevels)
@@ -146,6 +172,12 @@ public class ClientApi
/** Synchronized to prevent a rare issue where multiple disconnect events are triggered on top of each other. */ /** Synchronized to prevent a rare issue where multiple disconnect events are triggered on top of each other. */
public synchronized void onClientOnlyDisconnected() public synchronized void onClientOnlyDisconnected()
{ {
if (this.firstLevelLoadTimer != null)
{
this.firstLevelLoadTimer.cancel();
this.firstLevelLoadTimer = null;
}
AbstractDhWorld world = SharedApi.getAbstractDhWorld(); AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world != null) if (world != null)
{ {
@@ -155,11 +187,7 @@ public class ClientApi
SharedApi.setDhWorld(null); SharedApi.setDhWorld(null);
} }
// clear the previous server's information this.pluginChannelApi.reset();
this.isServerCommunicationEnabled = false;
this.serverNetworkingIsMalformed = false;
KEYED_CLIENT_LEVEL_MANAGER.setUseOverrideWrapper(false);
KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(null);
// remove any waiting items // remove any waiting items
this.waitingChunkByClientLevelAndPos.clear(); this.waitingChunkByClientLevelAndPos.clear();
@@ -172,16 +200,21 @@ public class ClientApi
// level events // // level events //
//==============// //==============//
public void clientLevelUnloadEvent(@Nullable IClientLevelWrapper level) public void clientLevelUnloadEvent(IClientLevelWrapper level)
{
this.clientLevelUnloadEvent(level, false);
}
public void clientLevelUnloadEvent(IClientLevelWrapper level, boolean respawn)
{ {
try try
{ {
if (level == null) LOGGER.info("Unloading client level [" + level + "]-["+level.getDimensionName()+"].");
if (level instanceof IServerKeyedClientLevel && !respawn)
{ {
// can happen on certain multiverse servers this.pluginChannelApi.onClientLevelUnload();
return;
} }
LOGGER.info("Unloading client level [" + level + "]-["+level.getDimensionType().getDimensionName()+"].");
AbstractDhWorld world = SharedApi.getAbstractDhWorld(); AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world != null) if (world != null)
@@ -201,30 +234,42 @@ public class ClientApi
} }
} }
public void clientLevelLoadEvent(@Nullable IClientLevelWrapper level) { this.clientLevelLoadEvent(level, false); } public void clientLevelLoadEvent(IClientLevelWrapper level)
public void multiverseClientLevelLoadEvent(@Nullable IClientLevelWrapper level) { this.clientLevelLoadEvent(level, true); }
private void clientLevelLoadEvent(@Nullable IClientLevelWrapper level, boolean isServerCommunication)
{ {
if (MC.clientConnectedToDedicatedServer())
{
if (this.firstLevelLoadTimer == null)
{
this.firstLevelLoadTimer = TimerUtil.CreateTimer("FirstLevelLoadTimer");
this.firstLevelLoadTimer.schedule(new TimerTask()
{
@Override
public void run()
{
ClientApi.this.clientLevelLoadEvent(level);
}
}, FIRST_LEVEL_LOAD_DELAY);
return;
}
this.firstLevelLoadTimer.cancel();
}
try try
{ {
if (this.isServerCommunicationEnabled && !isServerCommunication) LOGGER.info("Loading client level [" + level + "]-["+level.getDimensionName()+"].");
{
LOGGER.info("Server supports communication, deferring loading.");
return;
}
if (level == null)
{
// can happen on certain multiverse servers
return;
}
LOGGER.info("Loading " + (isServerCommunication ? "Multiverse" : "") + " client level [" + level + "]-["+level.getDimensionType().getDimensionName()+"].");
AbstractDhWorld world = SharedApi.getAbstractDhWorld(); AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world != null) if (world != null)
{ {
if (!this.pluginChannelApi.allowLevelLoading(level))
{
LOGGER.info("Levels in this connection are managed by the server, skipping auto-load.");
// Instead of attempting to load themselves, send config and wait for level key.
((DhClientWorld) world).networkState.sendConfigMessage();
return;
}
world.getOrLoadLevel(level); world.getOrLoadLevel(level);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level)); ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level));
@@ -241,6 +286,7 @@ public class ClientApi
LOGGER.error("Unexpected error in ClientApi.clientLevelLoadEvent(), error: "+e.getMessage(), e); LOGGER.error("Unexpected error in ClientApi.clientLevelLoadEvent(), error: "+e.getMessage(), e);
} }
} }
private void loadWaitingChunksForLevel(IClientLevelWrapper level) private void loadWaitingChunksForLevel(IClientLevelWrapper level)
{ {
HashSet<Pair<IClientLevelWrapper, DhChunkPos>> keysToRemove = new HashSet<>(); HashSet<Pair<IClientLevelWrapper, DhChunkPos>> keysToRemove = new HashSet<>();
@@ -333,124 +379,15 @@ public class ClientApi
//============// //============//
// networking // // networking //
//============// //============//
// /** @param byteBuf is Netty's {@link ByteBuffer} wrapper. */ public void pluginMessageReceived(@NotNull NetworkMessage message)
// public void serverMessageReceived(ByteBuf byteBuf) {
// { Session session = this.pluginChannelApi.session;
// if (!Config.Client.Advanced.Multiplayer.enableMultiverseNetworking.get()) if (session != null)
// { {
// // multiverse networking disabled, ignore anything sent from the server session.tryHandleMessage(message);
// return; }
// } }
//
//
//
// // either value can be set to true to debug the received byte stream
// boolean stopAndDisplayInputAsByteArray = false;
// boolean stopAndDisplayInputAsString = false;
// if (stopAndDisplayInputAsByteArray || stopAndDisplayInputAsString)
// {
// String messageString = "";
// if (stopAndDisplayInputAsByteArray)
// {
// int byteCount = byteBuf.readableBytes();
// byte[] arr = new byte[byteCount];
// StringBuilder stringBuilder = new StringBuilder("Server message received: [");
// for (int i = 0; i < byteCount; i++)
// {
// arr[i] = byteBuf.readByte();
// stringBuilder.append(arr[i]);
// }
// stringBuilder.append("]");
//
// messageString = stringBuilder.toString();
// }
// else if (stopAndDisplayInputAsString)
// {
// messageString = byteBuf.toString(StandardCharsets.UTF_8);
// }
//
// // this is logged as an error so it is easier to see in an Intellij log
// LOGGER.error(messageString);
// return;
// }
//
//
//
//
// // It is important to ensure malicious server input is ignored.
// if (this.serverNetworkingIsMalformed)
// {
// return;
// }
//
// // check that the incoming message is within the expected size
// short commandLength = byteBuf.readShort();
// if (commandLength < 1 || commandLength > 32)
// {
// LOGGER.error("Server command length ["+commandLength+"] outside the expected range of 1 to 32 (inclusive).");
// ClientApi.INSTANCE.serverNetworkingIsMalformed = true;
// return;
// }
//
// // parse the command
// String eventType;
// try
// {
// eventType = byteBuf.readCharSequence(commandLength, StandardCharsets.UTF_8).toString();
// }
// catch (Exception e)
// {
// LOGGER.error("Server sent un-parsable command. Error: "+e.getMessage());
// return;
// }
//
// switch (eventType)
// {
// case "ServerCommsEnabled":
// LOGGER.info("Server supports DH multiverse protocol.");
// ClientApi.INSTANCE.isServerCommunicationEnabled = true;
// KEYED_CLIENT_LEVEL_MANAGER.setUseOverrideWrapper(true);
// MC.executeOnRenderThread(() ->
// {
// // Unload the current world, since it may be wrong.
// // A followup WorldChanged event should be received from the server soon after this.
// LOGGER.info("Unloading current client level so the server can define the correct multiverse level.");
// this.clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld());
// });
// break;
//
// case "LevelChanged":
// short levelKeyLength = byteBuf.readShort();
// if (levelKeyLength < 1 || levelKeyLength > 128) // TODO 128 should be put into a constant somewhere
// {
// LOGGER.error("Server [LevelChanged] command length ["+commandLength+"] outside the expected range of 1 to 128 (inclusive).");
// this.serverNetworkingIsMalformed = true;
// return;
// }
//
// String levelKey = byteBuf.readCharSequence(levelKeyLength, StandardCharsets.UTF_8).toString();
// if (!levelKey.matches("[a-zA-Z0-9_]+"))
// {
// LOGGER.error("Server sent invalid world key name, and is being ignored.");
// this.isServerCommunicationEnabled = false;
// this.serverNetworkingIsMalformed = true;
// return;
// }
//
// LOGGER.info("Server level change event received, changing the level to ["+levelKey+"].");
// MC.executeOnRenderThread(() -> {
// if (MC.getWrappedClientWorld() != null)
// {
// this.clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld());
// }
// IServerKeyedClientLevel clientLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel(MC.getWrappedClientWorld(), levelKey);
// KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(clientLevel);
// this.multiverseClientLevelLoadEvent(clientLevel);
// });
// break;
// }
// }
@@ -475,29 +412,7 @@ public class ClientApi
{ {
// logging // // logging //
// dev build this.sendQueuedChatMessages();
if (ModInfo.IS_DEV_BUILD && !this.configOverrideReminderPrinted && MC.playerExists())
{
this.configOverrideReminderPrinted = true;
// remind the user that this is a development build
MC.sendChatMessage("Distant Horizons nightly/unstable build, version: [" + ModInfo.VERSION+"].");
MC.sendChatMessage("Issues may occur with this version.");
MC.sendChatMessage("Here be dragons!");
MC.sendChatMessage("");
}
// generic messages
while (!this.chatMessageQueueForNextFrame.isEmpty())
{
String message = this.chatMessageQueueForNextFrame.poll();
if (message == null)
{
// done to prevent potential null pointers
message = "";
}
MC.sendChatMessage(message);
}
IProfilerWrapper profiler = MC.getProfiler(); IProfilerWrapper profiler = MC.getProfiler();
profiler.pop(); // get out of "terrain" profiler.pop(); // get out of "terrain"
@@ -550,10 +465,24 @@ public class ClientApi
{ {
return; return;
} }
IDhClientLevel level = dhClientWorld.getOrLoadClientLevel(levelWrapper);
IDhClientLevel level = (IDhClientLevel) dhClientWorld.getLevel(levelWrapper);
if (level == null)
{
return;
}
if (this.rendererDisabledBecauseOfExceptions) if (this.rendererDisabledBecauseOfExceptions)
{ {
// re-enable rendering if the user toggles DH rendering
if (!Config.Client.quickEnableRendering.get())
{
LOGGER.info("DH Renderer re-enabled after exception. Some rendering issues may occur. Please reboot Minecraft if you see any rendering issues.");
this.rendererDisabledBecauseOfExceptions = false;
Config.Client.quickEnableRendering.set(true);
}
return; return;
} }
@@ -573,13 +502,13 @@ public class ClientApi
if (!DhApi.Delayed.renderProxy.getDeferTransparentRendering()) if (!DhApi.Delayed.renderProxy.getDeferTransparentRendering())
{ {
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterRenderEvent.class, renderEventParam); ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterRenderEvent.class, null);
} }
} }
else if (Config.Client.Advanced.Debugging.rendererMode.get() == EDhApiRendererMode.DEBUG) else if (Config.Client.Advanced.Debugging.rendererMode.get() == EDhApiRendererMode.DEBUG)
{ {
profiler.push("Render Debug"); profiler.push("Render Debug");
ClientApi.testRenderer.render(); ClientApi.TEST_RENDERER.render();
profiler.pop(); profiler.pop();
} }
} }
@@ -594,7 +523,7 @@ public class ClientApi
if (DhApi.Delayed.renderProxy.getDeferTransparentRendering()) if (DhApi.Delayed.renderProxy.getDeferTransparentRendering())
{ {
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterRenderEvent.class, renderEventParam); ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterRenderEvent.class, null);
} }
} }
} }
@@ -604,11 +533,23 @@ public class ClientApi
LOGGER.error("Unexpected Renderer error in render pass [" + renderPass + "]. Error: " + e.getMessage(), e); LOGGER.error("Unexpected Renderer error in render pass [" + renderPass + "]. Error: " + e.getMessage(), e);
MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons renderer has encountered an exception!"); MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons renderer has encountered an exception!");
MC.sendChatMessage("\u00A74Renderer is now disabled to prevent further issues."); MC.sendChatMessage("\u00A74Renderer disabled to try preventing GL state corruption.");
MC.sendChatMessage("\u00A74Exception detail: " + e); MC.sendChatMessage("\u00A74Toggle DH rendering via the config UI to re-activate DH rendering.");
MC.sendChatMessage("\u00A74Error: " + e);
} }
finally finally
{ {
try
{
// these tasks always need to be called, regardless of whether the renderer is enabled or not to prevent memory leaks
GLProxy.getInstance().runRenderThreadTasks();
}
catch (Exception e)
{
LOGGER.error("Unexpected issue running render thread tasks.", e);
}
profiler.pop(); // end LOD profiler.pop(); // end LOD
profiler.push("terrain"); // go back into "terrain" profiler.push("terrain"); // go back into "terrain"
} }
@@ -648,10 +589,61 @@ public class ClientApi
} }
} }
private void sendQueuedChatMessages()
{
// dev build
if (ModInfo.IS_DEV_BUILD && !this.configOverrideReminderPrinted && MC.playerExists())
{
this.configOverrideReminderPrinted = true;
// remind the user that this is a development build
String message =
// green text
"\u00A72" + "Distant Horizons: nightly/unstable build, version: [" + ModInfo.VERSION+"]." + "\u00A7r\n" +
"Issues may occur with this version.\n" +
"Here be dragons!\n";
MC.sendChatMessage(message);
}
// memory
if (!this.lowMemoryWarningPrinted && Config.Client.Advanced.Logging.showLowMemoryWarningOnStartup.get())
{
this.lowMemoryWarningPrinted = true;
// 4 GB
long minimumRecommendedMemoryInBytes = 4L * 1_000_000_000L;
// Java returned 17,171,480,576 for 16 GB so it might be slightly off what you'd expect
long maxMemoryInBytes = Runtime.getRuntime().maxMemory();
if (maxMemoryInBytes < minimumRecommendedMemoryInBytes)
{
String message =
// orange text
"\u00A76" + "Distant Horizons: Low memory detected." + "\u00A7r \n" +
"Stuttering or low FPS may occur. \n" +
"Please increase Minecraft's available memory to 4 gigabytes. \n" +
"This warning can be disabled in DH's config under Advanced -> Logging. \n";
MC.sendChatMessage(message);
}
}
// generic messages
while (!this.chatMessageQueueForNextFrame.isEmpty())
{
String message = this.chatMessageQueueForNextFrame.poll();
if (message == null)
{
// done to prevent potential null pointers
message = "";
}
MC.sendChatMessage(message);
}
}
/** /**
* Queues the given message to appear in chat the next valid frame. * Queues the given message to appear in chat the next valid frame.
* Useful for queueing up messages that may be triggered before the user has loaded into the world. * Useful for queueing up messages that may be triggered before the user has loaded into the world.
*/ */
public void showChatMessageNextFrame(String chatMessage) { this.chatMessageQueueForNextFrame.add(chatMessage); } public void showChatMessageNextFrame(String chatMessage) { this.chatMessageQueueForNextFrame.add(chatMessage); }
} }
@@ -0,0 +1,116 @@
package com.seibel.distanthorizons.core.api.internal;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.network.event.internal.CloseEvent;
import com.seibel.distanthorizons.core.network.messages.base.CurrentLevelKeyMessage;
import com.seibel.distanthorizons.core.network.session.Session;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import org.apache.logging.log4j.LogManager;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Consumer;
/**
* This class is used to manage the level keys.
*/
public class ClientPluginChannelApi
{
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class);
private final Consumer<IServerKeyedClientLevel> levelLoadHandler;
private final Consumer<IClientLevelWrapper> levelUnloadHandler;
@Nullable
public Session session;
public boolean allowLevelLoading(IClientLevelWrapper level)
{
return (KEYED_CLIENT_LEVEL_MANAGER.isEnabled() && level instanceof IServerKeyedClientLevel)
|| !KEYED_CLIENT_LEVEL_MANAGER.isEnabled();
}
public ClientPluginChannelApi(Consumer<IServerKeyedClientLevel> levelLoadHandler, Consumer<IClientLevelWrapper> levelUnloadHandler)
{
this.levelLoadHandler = levelLoadHandler;
this.levelUnloadHandler = levelUnloadHandler;
}
public void onJoin(@NonNull Session session)
{
Objects.requireNonNull(session);
this.session = session;
session.registerHandler(CurrentLevelKeyMessage.class, this::onCurrentLevelKeyMessage);
session.registerHandler(CloseEvent.class, this::onClose);
}
private void onCurrentLevelKeyMessage(CurrentLevelKeyMessage msg)
{
// prefix@namespace:path
// 1-50 characters in total, all parts except namespace can be omitted
if (!msg.levelKey.matches("^(?=.{1,50}$)([a-zA-Z0-9-_]+@)?[a-zA-Z0-9-_]+(:[a-zA-Z0-9-_]+)?$"))
{
throw new IllegalArgumentException("Server sent invalid level key.");
}
LOGGER.info("Server level key received: " + msg.levelKey);
MC.executeOnRenderThread(() -> {
IClientLevelWrapper clientLevel = MC.getWrappedClientLevel(true);
IServerKeyedClientLevel existingKeyedClientLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel();
if (existingKeyedClientLevel != null)
{
if (!existingKeyedClientLevel.getServerLevelKey().equals(msg.levelKey))
{
LOGGER.info("Unloading previous level with key: " + existingKeyedClientLevel.getServerLevelKey());
this.levelUnloadHandler.accept(existingKeyedClientLevel);
}
else
{
LOGGER.info("Level key matches the previous level key, ignoring the message.");
}
}
else
{
LOGGER.info("Unloading non-keyed level: " + clientLevel.getDimensionName());
this.levelUnloadHandler.accept(clientLevel);
}
if (existingKeyedClientLevel == null || !existingKeyedClientLevel.getServerLevelKey().equals(msg.levelKey))
{
LOGGER.info("Loading level with key: " + msg.levelKey);
IServerKeyedClientLevel keyedLevel = KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(clientLevel, msg.levelKey);
this.levelLoadHandler.accept(keyedLevel);
}
});
}
public void onClientLevelUnload()
{
KEYED_CLIENT_LEVEL_MANAGER.clearServerKeyedLevel();
}
private void onClose(CloseEvent event)
{
this.reset();
}
public void reset()
{
this.session = null;
KEYED_CLIENT_LEVEL_MANAGER.disable();
}
}
@@ -21,13 +21,9 @@ package com.seibel.distanthorizons.core.api.internal;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.world.AbstractDhWorld; import com.seibel.distanthorizons.core.world.AbstractDhWorld;
import com.seibel.distanthorizons.core.world.DhClientServerWorld; import com.seibel.distanthorizons.core.world.DhClientServerWorld;
import com.seibel.distanthorizons.core.world.DhServerWorld; import com.seibel.distanthorizons.core.world.DhServerWorld;
@@ -37,6 +33,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
/** /**
* This holds the methods that should be called by the host mod loader (Fabric, * This holds the methods that should be called by the host mod loader (Fabric,
@@ -141,7 +138,7 @@ public class ServerApi
//=======================// //=======================//
public void serverChunkLoadEvent(IChunkWrapper chunkWrapper, ILevelWrapper level) { SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, level, false); } public void serverChunkLoadEvent(IChunkWrapper chunkWrapper, ILevelWrapper level) { SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, level, false); }
public void serverChunkSaveEvent(IChunkWrapper chunkWrapper, ILevelWrapper level) { SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, level, false); } public void serverChunkSaveEvent(IChunkWrapper chunkWrapper, ILevelWrapper level) { SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, level, true); }
@@ -154,7 +151,7 @@ public class ServerApi
IDhServerWorld serverWorld = SharedApi.getIDhServerWorld(); IDhServerWorld serverWorld = SharedApi.getIDhServerWorld();
if (serverWorld instanceof DhServerWorld) // TODO add support for DhClientServerWorld's (lan worlds) as well if (serverWorld instanceof DhServerWorld) // TODO add support for DhClientServerWorld's (lan worlds) as well
{ {
LOGGER.debug("Waiting for player to connect: " + player.getUUID()); LOGGER.info("Creating state for player: " + player.getName());
((DhServerWorld) serverWorld).addPlayer(player); ((DhServerWorld) serverWorld).addPlayer(player);
} }
} }
@@ -163,9 +160,27 @@ public class ServerApi
IDhServerWorld serverWorld = SharedApi.getIDhServerWorld(); IDhServerWorld serverWorld = SharedApi.getIDhServerWorld();
if (serverWorld instanceof DhServerWorld) // TODO add support for DhClientServerWorld's (lan worlds) as well if (serverWorld instanceof DhServerWorld) // TODO add support for DhClientServerWorld's (lan worlds) as well
{ {
LOGGER.debug("Removing player from connect wait list: " + player.getUUID()); LOGGER.info("Destroying state for player: " + player.getName());
((DhServerWorld) serverWorld).removePlayer(player); ((DhServerWorld) serverWorld).removePlayer(player);
} }
} }
public void serverPlayerLevelChangeEvent(IServerPlayerWrapper player, IServerLevelWrapper origin, IServerLevelWrapper dest)
{
IDhServerWorld serverWorld = SharedApi.getIDhServerWorld();
if (serverWorld instanceof DhServerWorld) // TODO add support for DhClientServerWorld's (lan worlds) as well
{
LOGGER.info("Player changed level: " + player.getName());
((DhServerWorld) serverWorld).changePlayerLevel(player, origin, dest);
}
}
} public void pluginMessageReceived(IServerPlayerWrapper player, @NotNull NetworkMessage message)
{
IDhServerWorld serverWorld = SharedApi.getIDhServerWorld();
if (serverWorld instanceof DhServerWorld) // TODO add support for DhClientServerWorld's (lan worlds) as well
{
((DhServerWorld) serverWorld).remotePlayerConnectionHandler.handlePluginMessage(player, message);
}
}
}
@@ -26,9 +26,10 @@ import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen; import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.TimerUtil; import com.seibel.distanthorizons.core.util.TimerUtil;
import com.seibel.distanthorizons.core.util.objects.Pair; import com.seibel.distanthorizons.core.util.objects.Pair;
@@ -41,13 +42,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.*;
import java.util.Set; import java.util.concurrent.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
/** Contains code and variables used by both {@link ClientApi} and {@link ServerApi} */ /** Contains code and variables used by both {@link ClientApi} and {@link ServerApi} */
public class SharedApi public class SharedApi
@@ -59,32 +55,23 @@ public class SharedApi
private static final Set<DhChunkPos> UPDATING_CHUNK_POS_SET = ConcurrentHashMap.newKeySet(); private static final Set<DhChunkPos> UPDATING_CHUNK_POS_SET = ConcurrentHashMap.newKeySet();
/** how many chunks can be queued for updating per thread, used to prevent updates from infinitely pilling up if the user flys around extremely fast */ /** how many chunks can be queued for updating per thread, used to prevent updates from infinitely pilling up if the user flys around extremely fast */
private static final int MAX_UPDATING_CHUNK_COUNT_PER_THREAD = 500; private static final int MAX_UPDATING_CHUNK_COUNT_PER_THREAD = 500;
private static final int MIN_MS_BETWEEN_OVERLOADED_LOG_MESSAGE = 5_000; private static final int MIN_MS_BETWEEN_OVERLOADED_LOG_MESSAGE = 30_000;
private static final Timer CHUNK_UPDATE_TIMER = TimerUtil.CreateTimer("ChunkUpdateTimer"); private static final Timer CHUNK_UPDATE_TIMER = TimerUtil.CreateTimer("ChunkUpdateTimer");
private static AbstractDhWorld currentWorld; private static AbstractDhWorld currentWorld;
private static int lastWorldGenTickDelta = 0; private static int lastWorldGenTickDelta = 0;
private static long lastOverloadedLogMessageMsTime = 0; private static long lastOverloadedLogMessageMsTime = 0;
public F3Screen.DynamicMessage f3Message;
//=============// //=============//
// constructor // // constructor //
//=============// //=============//
private SharedApi() private SharedApi() { }
{
this.f3Message = new F3Screen.DynamicMessage(() ->
{
int maxUpdateCount = MAX_UPDATING_CHUNK_COUNT_PER_THREAD * Config.Client.Advanced.MultiThreading.numberOfLodBuilderThreads.get();
return LodUtil.formatLog("Queued chunk updates: " + UPDATING_CHUNK_POS_SET.size() + " / " + maxUpdateCount);
});
}
public static void init() { Initializer.init(); } public static void init() { Initializer.init(); }
@@ -97,6 +84,7 @@ public class SharedApi
public static void setDhWorld(AbstractDhWorld newWorld) public static void setDhWorld(AbstractDhWorld newWorld)
{ {
AbstractDhWorld prevWorld = currentWorld;
currentWorld = newWorld; currentWorld = newWorld;
// starting and stopping the DataRenderTransformer is necessary to prevent attempting to // starting and stopping the DataRenderTransformer is necessary to prevent attempting to
@@ -108,10 +96,16 @@ public class SharedApi
else else
{ {
ThreadPoolUtil.shutdownThreadPools(); ThreadPoolUtil.shutdownThreadPools();
DebugRenderer.clearRenderables();
MC_RENDER.clearTargetFrameBuffer(); if (prevWorld != null && prevWorld.environment != EWorldEnvironment.Server_Only)
{
DebugRenderer.clearRenderables();
MC_RENDER.clearTargetFrameBuffer();
// shouldn't be necessary, but if we missed closing one of the connections this should make sure they're all closed
AbstractDhRepo.closeAllConnections();
// needs to be closed on world shutdown to clear out un-processed chunks // needs to be closed on world shutdown to clear out un-processed chunks
UPDATING_CHUNK_POS_SET.clear(); UPDATING_CHUNK_POS_SET.clear();
}
// recommend that the garbage collector cleans up any objects from the old world and thread pools // recommend that the garbage collector cleans up any objects from the old world and thread pools
System.gc(); System.gc();
@@ -146,25 +140,16 @@ public class SharedApi
* Used to prevent getting a full chunk from MC if it isn't necessary. <br> * Used to prevent getting a full chunk from MC if it isn't necessary. <br>
* This is important since asking MC for a chunk is slow and may block the render thread. * This is important since asking MC for a chunk is slow and may block the render thread.
*/ */
public static boolean isChunkAtBlockPosAlreadyUpdating(int blockPosX, int blockPosZ) { return UPDATING_CHUNK_POS_SET.contains(new DhChunkPos(new DhBlockPos2D(blockPosX, blockPosZ))); } public static boolean isChunkAtBlockPosAlreadyUpdating(int blockPosX, int blockPosZ)
{ return UPDATING_CHUNK_POS_SET.contains(new DhChunkPos(new DhBlockPos2D(blockPosX, blockPosZ))); }
public static boolean isChunkAtChunkPosAlreadyUpdating(int chunkPosX, int chunkPosZ)
{ return UPDATING_CHUNK_POS_SET.contains(new DhChunkPos(chunkPosX, chunkPosZ)); }
/** handles both block place and break events */ /** handles both block place and break events */
public void chunkBlockChangedEvent(IChunkWrapper chunk, ILevelWrapper level) { this.applyChunkUpdate(chunk, level, true); } public void chunkBlockChangedEvent(IChunkWrapper chunk, ILevelWrapper level) { this.applyChunkUpdate(chunk, level, true); }
public void chunkLoadEvent(IChunkWrapper chunk, ILevelWrapper level) { this.applyChunkUpdate(chunk, level, false); } public void chunkLoadEvent(IChunkWrapper chunk, ILevelWrapper level) { this.applyChunkUpdate(chunk, level, false); }
public void chunkUnloadEvent(IChunkWrapper chunk, ILevelWrapper level)
{
// temporarily disabled since this was originally incorrectly designated as "chunkSaveEvent"
// but didn't actually fire on chunk save
// and generally this is unnecessary and drastically reduces LOD building performance
// when traveling around the world
if (false)
{
this.applyChunkUpdate(chunk, level, false);
}
}
public void applyChunkUpdate(IChunkWrapper chunkWrapper, ILevelWrapper level, boolean updateNeighborChunks) public void applyChunkUpdate(IChunkWrapper chunkWrapper, ILevelWrapper level, boolean updateNeighborChunks)
{ {
@@ -223,7 +208,13 @@ public class SharedApi
if (msBetweenLastLog >= MIN_MS_BETWEEN_OVERLOADED_LOG_MESSAGE) if (msBetweenLastLog >= MIN_MS_BETWEEN_OVERLOADED_LOG_MESSAGE)
{ {
lastOverloadedLogMessageMsTime = System.currentTimeMillis(); lastOverloadedLogMessageMsTime = System.currentTimeMillis();
LOGGER.warn("Too many chunks queued for updating, max queue count ["+maxQueueCount+"] (["+MAX_UPDATING_CHUNK_COUNT_PER_THREAD+"] per thread). Some LODs may not be updated or may be missing. Please move through the world slower, decrease your vanilla render distance, or increase the CPU load config.");
String message = "Distant Horizons overloaded, too many chunks queued for updating. " +
"\nThis may result in holes in your LODs. " +
"\nPlease move through the world slower, decrease your vanilla render distance, slow down your world pre-generator, or increase the Distant Horizons' CPU load config. " +
"\nMax queue count ["+maxQueueCount+"] (["+MAX_UPDATING_CHUNK_COUNT_PER_THREAD+"] per thread).";
ClientApi.INSTANCE.showChatMessageNextFrame(message);
LOGGER.warn(message);
} }
return; return;
@@ -268,7 +259,7 @@ public class SharedApi
else else
{ {
// neighboring chunk // neighboring chunk
DhChunkPos neighbourPos = new DhChunkPos(chunkWrapper.getChunkPos().x + xOffset, chunkWrapper.getChunkPos().z + zOffset); DhChunkPos neighbourPos = new DhChunkPos(chunkWrapper.getChunkPos().getX() + xOffset, chunkWrapper.getChunkPos().getZ() + zOffset);
IChunkWrapper neighbourChunk = dhLevel.getLevelWrapper().tryGetChunk(neighbourPos); IChunkWrapper neighbourChunk = dhLevel.getLevelWrapper().tryGetChunk(neighbourPos);
if (neighbourChunk != null) if (neighbourChunk != null)
{ {
@@ -285,57 +276,97 @@ public class SharedApi
} }
} }
} }
private static void bakeChunkLightingAndSendToLevelAsync(IChunkWrapper chunkWrapper, @Nullable ArrayList<IChunkWrapper> neighbourChunkList, IDhLevel dhLevel) /** returning a {@link CompletableFuture} isn't necessary, but allows Intellij to properly show the full stack trace when debugging. */
@SuppressWarnings("UnusedReturnValue")
private static CompletableFuture<Void> bakeChunkLightingAndSendToLevelAsync(IChunkWrapper chunkWrapper, @Nullable ArrayList<IChunkWrapper> neighbourChunkList, IDhLevel dhLevel)
{ {
// lighting the chunk needs to be done on a separate thread to prevent lagging any of the event threads // lighting the chunk needs to be done on a separate thread to prevent lagging any of the event threads
ThreadPoolExecutor executor = ThreadPoolUtil.getLightPopulatorExecutor(); ThreadPoolExecutor executor = ThreadPoolUtil.getChunkToLodBuilderExecutor();
if (executor == null) if (executor == null)
{ {
return; return CompletableFuture.completedFuture(null);
} }
try try
{ {
executor.execute(() -> return CompletableFuture.runAsync(() ->
{ {
//LOGGER.trace(chunkWrapper.getChunkPos() + " " + executor.getActiveCount() + " / " + executor.getQueue().size() + " - " + executor.getCompletedTaskCount()); //LOGGER.trace(chunkWrapper.getChunkPos() + " " + executor.getActiveCount() + " / " + executor.getQueue().size() + " - " + executor.getCompletedTaskCount());
try try
{ {
// Save or populate the chunk wrapper's lighting boolean checkChunkHash = !Config.Client.Advanced.LodBuilding.disableUnchangedChunkCheck.get();
// this is done so we don't have to worry about MC unloading the lighting data for this chunk
boolean onlyUseDhLighting = Config.Client.Advanced.LodBuilding.onlyUseDhLightingEngine.get(); // check if this chunk has been converted into an LOD already
if (!onlyUseDhLighting && chunkWrapper.isLightCorrect()) int oldChunkHash = dhLevel.getChunkHash(chunkWrapper.getChunkPos()); // shouldn't happen on the render thread since it may take a few moments to run
int newChunkHash = chunkWrapper.getBlockBiomeHashCode();
if (checkChunkHash)
{ {
try if (oldChunkHash == newChunkHash)
{
// if the chunk hashes are the same then we don't need to bother with lighting the chunk
// or creating/updating the LODs
//LOGGER.info("skipping: "+chunkWrapper.getChunkPos()+" "+newChunkHash);
return;
}
else
{
//LOGGER.info("g: "+chunkWrapper.getChunkPos()+" "+newChunkHash);
}
}
// having a list of the nearby chunks is needed for lighting and beacon generation
ArrayList<IChunkWrapper> nearbyChunkList;
if (neighbourChunkList != null)
{
nearbyChunkList = neighbourChunkList;
}
else
{
nearbyChunkList = new ArrayList<>(1);
nearbyChunkList.add(chunkWrapper);
}
// chunk light baking is disabled since profiling revealed it used
// roughly the same amount of time as generating the lighting ourselves and
// was much more likely to have issues with corrupt (all black or all bright) chunks
boolean tryUsingMcLightingEngine = false;
if (tryUsingMcLightingEngine)
{
// Save or populate the chunk wrapper's lighting
// this is done so we don't have to worry about MC unloading the lighting data for this chunk
boolean chunkLightPopulated = false;
boolean onlyUseDhLighting = Config.Client.Advanced.LodBuilding.onlyUseDhLightingEngine.get();
if (!onlyUseDhLighting && chunkWrapper.isLightCorrect())
{ {
// If MC's lighting engine isn't thread safe this may cause the server thread to lag // If MC's lighting engine isn't thread safe this may cause the server thread to lag
chunkWrapper.bakeDhLightingUsingMcLightingEngine(); chunkLightPopulated = chunkWrapper.bakeDhLightingUsingMcLightingEngine(dhLevel.getLevelWrapper());
if (!chunkLightPopulated)
{
// clear any existing data to prevent partial or corrupt lighting
// when re-generating it
chunkWrapper.clearDhBlockLighting();
chunkWrapper.clearDhSkyLighting();
}
} }
catch (IllegalStateException e)
// something went wrong during the baking process so we have to generate the lighting ourselves
if (!chunkLightPopulated)
{ {
LOGGER.warn("Chunk light baking error: " + e.getMessage(), e); DhLightingEngine.INSTANCE.lightChunk(chunkWrapper, nearbyChunkList, dhLevel.hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT);
} }
} }
else else
{ {
// generate the chunk's lighting, using neighboring chunks if present DhLightingEngine.INSTANCE.lightChunk(chunkWrapper, nearbyChunkList, dhLevel.hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT);
ArrayList<IChunkWrapper> nearbyChunkList;
if (neighbourChunkList != null)
{
nearbyChunkList = neighbourChunkList;
}
else
{
nearbyChunkList = new ArrayList<>(1);
nearbyChunkList.add(chunkWrapper);
}
DhLightingEngine.INSTANCE.lightChunk(chunkWrapper, nearbyChunkList, dhLevel.hasSkyLight() ? 15 : 0);
} }
dhLevel.updateChunkAsync(chunkWrapper);
dhLevel.updateBeaconBeamsForChunk(chunkWrapper, nearbyChunkList);
dhLevel.updateChunkAsync(chunkWrapper, newChunkHash);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -360,10 +391,28 @@ public class SharedApi
UPDATING_CHUNK_POS_SET.remove(chunkWrapper.getChunkPos()); UPDATING_CHUNK_POS_SET.remove(chunkWrapper.getChunkPos());
} }
} }
}); }, executor);
}
catch (RejectedExecutionException ignore)
{
// the executor was shut down, it should be back up shortly and able to accept new jobs
return CompletableFuture.completedFuture(null);
} }
catch (RejectedExecutionException ignore) { /* the executor was shut down, it should be back up shortly and able to accept new jobs */ }
} }
}
//=========//
// F3 Menu //
//=========//
public String getDebugMenuString()
{
int maxUpdateCount = MAX_UPDATING_CHUNK_COUNT_PER_THREAD * Config.Client.Advanced.MultiThreading.numberOfLodBuilderThreads.get();
String updatingCountStr = F3Screen.NUMBER_FORMAT.format(UPDATING_CHUNK_POS_SET.size());
String maxUpdateCountStr = F3Screen.NUMBER_FORMAT.format(maxUpdateCount);
return "Queued chunk updates: "+updatingCountStr+" / "+maxUpdateCountStr;
}
}
@@ -20,17 +20,21 @@
package com.seibel.distanthorizons.core.config; package com.seibel.distanthorizons.core.config;
import com.google.common.base.Suppliers;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.enums.config.*; import com.seibel.distanthorizons.api.enums.config.*;
import com.seibel.distanthorizons.api.enums.config.quickOptions.*; import com.seibel.distanthorizons.api.enums.config.quickOptions.*;
import com.seibel.distanthorizons.api.enums.rendering.*; import com.seibel.distanthorizons.api.enums.rendering.*;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
import com.seibel.distanthorizons.core.config.eventHandlers.*; import com.seibel.distanthorizons.core.config.eventHandlers.*;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.*; import com.seibel.distanthorizons.core.config.eventHandlers.presets.*;
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
import com.seibel.distanthorizons.core.config.types.*; import com.seibel.distanthorizons.core.config.types.*;
import com.seibel.distanthorizons.core.config.types.enums.*; import com.seibel.distanthorizons.core.config.types.enums.*;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.coreapi.util.StringUtil; import com.seibel.distanthorizons.coreapi.util.StringUtil;
@@ -40,6 +44,7 @@ import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/** /**
@@ -51,7 +56,6 @@ import java.util.List;
* Otherwise, you will have issues where only some of the config entries will exist when your listener is created. * Otherwise, you will have issues where only some of the config entries will exist when your listener is created.
* *
* @author coolGi * @author coolGi
* @version 2023-7-16
*/ */
public class Config public class Config
@@ -104,8 +108,11 @@ public class Config
public static ConfigLinkedEntry quickEnableWorldGenerator = new ConfigLinkedEntry(Advanced.WorldGenerator.enableDistantGeneration); public static ConfigLinkedEntry quickEnableWorldGenerator = new ConfigLinkedEntry(Advanced.WorldGenerator.enableDistantGeneration);
public static ConfigLinkedEntry quickLodCloudRendering = new ConfigLinkedEntry(Advanced.Graphics.GenericRendering.enableCloudRendering);
public static ConfigEntry<Boolean> optionsButton = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> optionsButton = new ConfigEntry.Builder<Boolean>()
.set(true) .set(true)
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.comment("" + .comment("" +
"Should Distant Horizon's config button appear in the options screen next to fov slider?") "Should Distant Horizon's config button appear in the options screen next to fov slider?")
.build(); .build();
@@ -122,7 +129,6 @@ public class Config
public static ConfigCategory multiplayer = new ConfigCategory.Builder().set(Multiplayer.class).build(); public static ConfigCategory multiplayer = new ConfigCategory.Builder().set(Multiplayer.class).build();
public static ConfigCategory lodBuilding = new ConfigCategory.Builder().set(LodBuilding.class).build(); public static ConfigCategory lodBuilding = new ConfigCategory.Builder().set(LodBuilding.class).build();
public static ConfigCategory multiThreading = new ConfigCategory.Builder().set(MultiThreading.class).build(); public static ConfigCategory multiThreading = new ConfigCategory.Builder().set(MultiThreading.class).build();
public static ConfigCategory buffers = new ConfigCategory.Builder().set(GpuBuffers.class).build();
public static ConfigCategory autoUpdater = new ConfigCategory.Builder().set(AutoUpdater.class).build(); public static ConfigCategory autoUpdater = new ConfigCategory.Builder().set(AutoUpdater.class).build();
public static ConfigCategory logging = new ConfigCategory.Builder().set(Logging.class).build(); public static ConfigCategory logging = new ConfigCategory.Builder().set(Logging.class).build();
@@ -135,6 +141,7 @@ public class Config
public static ConfigCategory fog = new ConfigCategory.Builder().set(Fog.class).build(); public static ConfigCategory fog = new ConfigCategory.Builder().set(Fog.class).build();
public static ConfigCategory ssao = new ConfigCategory.Builder().set(Ssao.class).build(); public static ConfigCategory ssao = new ConfigCategory.Builder().set(Ssao.class).build();
public static ConfigCategory noiseTextureSettings = new ConfigCategory.Builder().set(NoiseTextureSettings.class).build(); public static ConfigCategory noiseTextureSettings = new ConfigCategory.Builder().set(NoiseTextureSettings.class).build();
public static ConfigCategory genericRendering = new ConfigCategory.Builder().set(GenericRendering.class).build();
public static ConfigCategory advancedGraphics = new ConfigCategory.Builder().set(AdvancedGraphics.class).build(); public static ConfigCategory advancedGraphics = new ConfigCategory.Builder().set(AdvancedGraphics.class).build();
@@ -158,8 +165,17 @@ public class Config
.build(); .build();
public static ConfigEntry<Integer> lodChunkRenderDistanceRadius = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> lodChunkRenderDistanceRadius = new ConfigEntry.Builder<Integer>()
.setServersideShortName("renderDistanceRadius")
.setMinDefaultMax(32, 128, 4096) .setMinDefaultMax(32, 128, 4096)
.comment("The radius of the mod's render distance. (measured in chunks)") .comment("" +
"The radius of the mod's render distance. (measured in chunks)\n" +
"On server changes the distance players will receive real-time updates for, if enabled." +
"\n" +
"Note for servers:\n" +
"This setting does not prevent players from generating farther out.\n" +
"If you want to limit performance impact, change rate limits\n" +
"and thread count/runtime ratio settings instead.\n" +
"It also does not affect the visuals on clients.")
.setPerformance(EConfigEntryPerformance.HIGH) .setPerformance(EConfigEntryPerformance.HIGH)
.build(); .build();
@@ -174,6 +190,7 @@ public class Config
+ "Lowest Quality: " + EDhApiVerticalQuality.HEIGHT_MAP + "\n" + "Lowest Quality: " + EDhApiVerticalQuality.HEIGHT_MAP + "\n"
+ "Highest Quality: " + EDhApiVerticalQuality.EXTREME) + "Highest Quality: " + EDhApiVerticalQuality.EXTREME)
.setPerformance(EConfigEntryPerformance.VERY_HIGH) .setPerformance(EConfigEntryPerformance.VERY_HIGH)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<EDhApiHorizontalQuality> horizontalQuality = new ConfigEntry.Builder<EDhApiHorizontalQuality>() public static ConfigEntry<EDhApiHorizontalQuality> horizontalQuality = new ConfigEntry.Builder<EDhApiHorizontalQuality>()
@@ -195,6 +212,7 @@ public class Config
+ EDhApiTransparency.DISABLED + ": LODs will be opaque. \n" + EDhApiTransparency.DISABLED + ": LODs will be opaque. \n"
+ "") + "")
.setPerformance(EConfigEntryPerformance.MEDIUM) .setPerformance(EConfigEntryPerformance.MEDIUM)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<EDhApiBlocksToAvoid> blocksToIgnore = new ConfigEntry.Builder<EDhApiBlocksToAvoid>() public static ConfigEntry<EDhApiBlocksToAvoid> blocksToIgnore = new ConfigEntry.Builder<EDhApiBlocksToAvoid>()
@@ -206,6 +224,7 @@ public class Config
+ EDhApiBlocksToAvoid.NON_COLLIDING + ": Only represent solid blocks in the LODs (tall grass, torches, etc. won't count for a LOD's height) \n" + EDhApiBlocksToAvoid.NON_COLLIDING + ": Only represent solid blocks in the LODs (tall grass, torches, etc. won't count for a LOD's height) \n"
+ "") + "")
.setPerformance(EConfigEntryPerformance.NONE) .setPerformance(EConfigEntryPerformance.NONE)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Boolean> tintWithAvoidedBlocks = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> tintWithAvoidedBlocks = new ConfigEntry.Builder<Boolean>()
@@ -217,6 +236,7 @@ public class Config
+ "False: skipped blocks will not change color of surface below them. " + "False: skipped blocks will not change color of surface below them. "
+ "") + "")
.setPerformance(EConfigEntryPerformance.NONE) .setPerformance(EConfigEntryPerformance.NONE)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
// TODO fixme // TODO fixme
@@ -279,7 +299,7 @@ public class Config
private static final Double FOG_RANGE_MAX = Math.sqrt(2.0); private static final Double FOG_RANGE_MAX = Math.sqrt(2.0);
public static ConfigEntry<Double> farFogStart = new ConfigEntry.Builder<Double>() public static ConfigEntry<Double> farFogStart = new ConfigEntry.Builder<Double>()
.setMinDefaultMax(FOG_RANGE_MIN, 0.0, FOG_RANGE_MAX) .setMinDefaultMax(FOG_RANGE_MIN, 0.4, FOG_RANGE_MAX)
.comment("" .comment(""
+ "At what distance should the far fog start? \n" + "At what distance should the far fog start? \n"
+ "\n" + "\n"
@@ -510,7 +530,8 @@ public class Config
public static ConfigEntry<Integer> noiseSteps = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> noiseSteps = new ConfigEntry.Builder<Integer>()
.setMinDefaultMax(1, 4, null) .setMinDefaultMax(1, 4, null)
.comment("" .comment(""
+ "How many steps of noise should be applied to LODs?") + "How many steps of noise should be applied to LODs?"
+ "")
.build(); .build();
public static ConfigEntry<Double> noiseIntensity = new ConfigEntry.Builder<Double>() // TODO: Make this a float (the ClassicConfigGUI doesn't support floats) public static ConfigEntry<Double> noiseIntensity = new ConfigEntry.Builder<Double>() // TODO: Make this a float (the ClassicConfigGUI doesn't support floats)
@@ -523,7 +544,34 @@ public class Config
.setMinDefaultMax(0, 1024, null) .setMinDefaultMax(0, 1024, null)
.comment("" .comment(""
+ "Defines how far should the noise texture render before it fades away. (in blocks) \n" + "Defines how far should the noise texture render before it fades away. (in blocks) \n"
+ "Set to 0 to disable noise from fading away") + "Set to 0 to disable noise from fading away \n"
+ "")
.build();
}
public static class GenericRendering
{
public static ConfigEntry<Boolean> enableRendering = new ConfigEntry.Builder<Boolean>()
.set(true)
.comment(""
+ "If true non terrain objects will be rendered in DH's terrain. \n"
+ "This includes beacon beams and clouds. \n"
+ "")
.build();
public static ConfigEntry<Boolean> enableBeaconRendering = new ConfigEntry.Builder<Boolean>()
.set(true)
.comment(""
+ "If true LOD beacon beams will be rendered. \n"
+ "")
.build();
public static ConfigEntry<Boolean> enableCloudRendering = new ConfigEntry.Builder<Boolean>()
.set(true)
.comment(""
+ "If true LOD clouds will be rendered. \n"
+ "")
.build(); .build();
} }
@@ -554,6 +602,7 @@ public class Config
+ "0 = black \n" + "0 = black \n"
+ "1 = normal \n" + "1 = normal \n"
+ "2 = near white") + "2 = near white")
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Double> saturationMultiplier = new ConfigEntry.Builder<Double>() // TODO: Make this a float (the ClassicConfigGUI doesnt support floats) public static ConfigEntry<Double> saturationMultiplier = new ConfigEntry.Builder<Double>() // TODO: Make this a float (the ClassicConfigGUI doesnt support floats)
@@ -564,6 +613,7 @@ public class Config
+ "0 = black and white \n" + "0 = black and white \n"
+ "1 = normal \n" + "1 = normal \n"
+ "2 = very saturated") + "2 = very saturated")
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Boolean> enableCaveCulling = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> enableCaveCulling = new ConfigEntry.Builder<Boolean>()
@@ -578,12 +628,15 @@ public class Config
+ "Additional Info: Currently this cull all faces \n" + "Additional Info: Currently this cull all faces \n"
+ " with skylight value of 0 in dimensions that \n" + " with skylight value of 0 in dimensions that \n"
+ " does not have a ceiling.") + " does not have a ceiling.")
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Integer> caveCullingHeight = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> caveCullingHeight = new ConfigEntry.Builder<Integer>()
.setMinDefaultMax(-4096, 40, 4096) .setMinDefaultMax(-4096, 60, 4096)
.comment("" .comment(""
+ "At what Y value should cave culling start?") + "At what Y value should cave culling start? \n"
+ "Lower this value if you get walls for areas with 0 light.")
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Integer> earthCurveRatio = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> earthCurveRatio = new ConfigEntry.Builder<Integer>()
@@ -621,6 +674,7 @@ public class Config
+ EDhApiLodShading.DISABLED + ": All LOD sides will be rendered with the same brightness. \n" + EDhApiLodShading.DISABLED + ": All LOD sides will be rendered with the same brightness. \n"
+ "") + "")
.setPerformance(EConfigEntryPerformance.NONE) .setPerformance(EConfigEntryPerformance.NONE)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Boolean> disableFrustumCulling = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> disableFrustumCulling = new ConfigEntry.Builder<Boolean>()
@@ -655,6 +709,18 @@ public class Config
+ EDhApiGrassSideRendering.AS_DIRT + ": sides render entirely as dirt. \n" + EDhApiGrassSideRendering.AS_DIRT + ": sides render entirely as dirt. \n"
+ "") + "")
.setPerformance(EConfigEntryPerformance.NONE) .setPerformance(EConfigEntryPerformance.NONE)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build();
public static ConfigEntry<Boolean> disableBeaconDistanceCulling = new ConfigEntry.Builder<Boolean>()
.set(false)
.comment(""
+ "If true all beacons near the camera won't be drawn to prevent vanilla overdraw. \n"
+ "If false all beacons will be rendered. \n"
+ "\n"
+ "Generally this should be left as false. It's main purpose is for debugging\n"
+ "beacon updating/rendering.\n"
+ "")
.build(); .build();
} }
@@ -664,16 +730,15 @@ public class Config
public static class WorldGenerator public static class WorldGenerator
{ {
public static ConfigEntry<Boolean> enableDistantGeneration = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> enableDistantGeneration = new ConfigEntry.Builder<Boolean>()
.setServersideShortName("enableDistantGeneration")
.set(true) .set(true)
.comment("" .comment(""
+ " Should Distant Horizons slowly generate LODs \n" + " Should Distant Horizons slowly generate LODs \n"
+ " outside the vanilla render distance?\n" + " outside the vanilla render distance?")
+ "\n"
+ " Note: when on a server, distant generation isn't supported \n"
+ " and will always be disabled.")
.build(); .build();
public static ConfigEntry<EDhApiDistantGeneratorMode> distantGeneratorMode = new ConfigEntry.Builder<EDhApiDistantGeneratorMode>() public static ConfigEntry<EDhApiDistantGeneratorMode> distantGeneratorMode = new ConfigEntry.Builder<EDhApiDistantGeneratorMode>()
.setServersideShortName("distantGeneratorMode")
.set(EDhApiDistantGeneratorMode.FEATURES) .set(EDhApiDistantGeneratorMode.FEATURES)
.comment("" .comment(""
+ "How detailed should LODs be generated outside the vanilla render distance? \n" + "How detailed should LODs be generated outside the vanilla render distance? \n"
@@ -715,7 +780,8 @@ public class Config
.build(); .build();
public static ConfigEntry<Integer> worldGenerationTimeoutLengthInSeconds = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> worldGenerationTimeoutLengthInSeconds = new ConfigEntry.Builder<Integer>()
.setMinDefaultMax(5, 60, 60 * 10/*10 minutes*/ ) .setServersideShortName("worldGenerationTimeout")
.setMinDefaultMax(5, 60 * 3, 60 * 10/*10 minutes*/ )
.comment("" .comment(""
+ "How long should a world generator thread run for before timing out? \n" + "How long should a world generator thread run for before timing out? \n"
+ "Note: If you are experiencing timeout errors it is better to lower your CPU usage first \n" + "Note: If you are experiencing timeout errors it is better to lower your CPU usage first \n"
@@ -728,6 +794,7 @@ public class Config
public static class LodBuilding public static class LodBuilding
{ {
public static ConfigEntry<Integer> minTimeBetweenChunkUpdatesInSeconds = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> minTimeBetweenChunkUpdatesInSeconds = new ConfigEntry.Builder<Integer>()
.setServersideShortName("minTimeBetweenChunkUpdates")
.setMinDefaultMax(0, 1, 60) .setMinDefaultMax(0, 1, 60)
.comment("" .comment(""
+ "Determines how long must pass between LOD chunk updates before another. \n" + "Determines how long must pass between LOD chunk updates before another. \n"
@@ -738,8 +805,23 @@ public class Config
+ "") + "")
.build(); .build();
public static ConfigEntry<Boolean> disableUnchangedChunkCheck = new ConfigEntry.Builder<Boolean>()
.set(false)
.comment(""
+ "Normally DH will attempt to skip creating LODs for chunks it's already seen\n"
+ "and that haven't changed.\n"
+ "\n"
+ "However sometimes that logic incorrecly prevents LODs from being updated.\n"
+ "Disabling this check may fix issues where LODs aren't updated after\n"
+ "blocks have been changed.\n"
+ "")
.build();
/** Currently we always use the DH lighting engine because there's a high likelyhood of MC returning incorrect lighting otherwise */
@Deprecated
public static ConfigEntry<Boolean> onlyUseDhLightingEngine = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> onlyUseDhLightingEngine = new ConfigEntry.Builder<Boolean>()
.set(false) .set(false)
.setAppearance(EConfigEntryAppearance.ONLY_IN_API)
.comment("" .comment(""
+ "If false LODs will be lit by Minecraft's lighting engine when possible \n" + "If false LODs will be lit by Minecraft's lighting engine when possible \n"
+ "and fall back to the DH lighting engine only when necessary. \n" + "and fall back to the DH lighting engine only when necessary. \n"
@@ -751,6 +833,20 @@ public class Config
+ "") + "")
.build(); .build();
public static ConfigEntry<Boolean> pullLightingForPregeneratedChunks = new ConfigEntry.Builder<Boolean>()
.set(false)
.comment(""
+ "If true LOD generation for pre-existing chunks will attempt to pull the lighting data \n"
+ "saved in Minecraft's Region files. \n"
+ "If false DH will pull in chunks without lighting and re-light them. \n"
+ " \n"
+ "Setting this to true will result in faster LOD generation \n"
+ "for already generated worlds, but is broken by most lighting mods. \n"
+ " \n"
+ "Set this to false if LODs are black. \n"
+ "")
.build();
public static ConfigEntry<EDhApiDataCompressionMode> dataCompression = new ConfigEntry.Builder<EDhApiDataCompressionMode>() public static ConfigEntry<EDhApiDataCompressionMode> dataCompression = new ConfigEntry.Builder<EDhApiDataCompressionMode>()
.set(EDhApiDataCompressionMode.LZMA2) .set(EDhApiDataCompressionMode.LZMA2)
.comment("" .comment(""
@@ -760,7 +856,7 @@ public class Config
+ "unaffected until it needs to be re-written to the database.\n" + "unaffected until it needs to be re-written to the database.\n"
+ "\n" + "\n"
+ EDhApiDataCompressionMode.UNCOMPRESSED + " \n" + EDhApiDataCompressionMode.UNCOMPRESSED + " \n"
+ "Should only be used for testing, is worse in every way vs ["+EDhApiDataCompressionMode.LZ4+"].\n" + "Should only be used for testing, is worse in every way vs [" + EDhApiDataCompressionMode.LZ4 + "].\n"
+ "Expected Compression Ratio: 1.0\n" + "Expected Compression Ratio: 1.0\n"
+ "Estimated average DTO read speed: 1.64 milliseconds\n" + "Estimated average DTO read speed: 1.64 milliseconds\n"
+ "Estimated average DTO write speed: 12.44 milliseconds\n" + "Estimated average DTO write speed: 12.44 milliseconds\n"
@@ -788,24 +884,58 @@ public class Config
+ "unaffected until it is modified or re-loaded.\n" + "unaffected until it is modified or re-loaded.\n"
+ "\n" + "\n"
+ EDhApiWorldCompressionMode.MERGE_SAME_BLOCKS + " \n" + EDhApiWorldCompressionMode.MERGE_SAME_BLOCKS + " \n"
+ "Every block/biome change is recorded in the database. \n" + "Every block/biome change is recorded in the database. \n"
+ "This is what DH 2.0 and 2.0.1 all used by default and will store a lot of data. \n" + "This is what DH 2.0 and 2.0.1 all used by default and will store a lot of data. \n"
+ "Expected Compression Ratio: 1.0\n" + "Expected Compression Ratio: 1.0\n"
+ "\n" + "\n"
+ EDhApiWorldCompressionMode.VISUALLY_EQUAL + " \n" + EDhApiWorldCompressionMode.VISUALLY_EQUAL + " \n"
+ "Only visible block/biome changes are recorded in the database. \n" + "Only visible block/biome changes are recorded in the database. \n"
+ "Hidden blocks (IE ores) are ignored. \n" + "Hidden blocks (IE ores) are ignored. \n"
+ "Expected Compression Ratio: 0.7\n" + "Expected Compression Ratio: 0.7\n"
+ "") + "")
.build(); .build();
public static ConfigEntry<Boolean> showMigrationChatWarning = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<String> ignoredRenderBlockCsv = new ConfigEntry.Builder<String>()
.set(true) .set("minecraft:barrier,minecraft:structure_void,minecraft:light,minecraft:tripwire")
.comment("" .comment(""
+ "Determines if a message should be displayed in the chat when LOD migration starts. \n" + "A comma separated list of block resource locations that won't be rendered by DH. \n"
+ "Note: air is always included in this list. \n"
+ "") + "")
.build(); .build();
public static ConfigEntry<String> ignoredRenderCaveBlockCsv = new ConfigEntry.Builder<String>()
.set("minecraft:glow_lichen,minecraft:rail,minecraft:water,minecraft:lava,minecraft:bubble_column")
.comment(""
+ "A comma separated list of block resource locations that shouldn't be rendered \n"
+ "if they are in a 0 sky light underground area. \n"
+ "Note: air is always included in this list. \n"
+ "")
.build();
static
{
ignoredRenderBlockCsv.addListener(new ConfigChangeListener<String>(Config.Client.Advanced.LodBuilding.ignoredRenderBlockCsv,
(blockCsv) ->
{
IWrapperFactory wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
if (wrapperFactory != null)
{
wrapperFactory.resetRendererIgnoredBlocksSet();
DhApi.Delayed.renderProxy.clearRenderDataCache();
}
}));
ignoredRenderCaveBlockCsv.addListener(new ConfigChangeListener<String>(Config.Client.Advanced.LodBuilding.ignoredRenderCaveBlockCsv,
(blockCsv) ->
{
IWrapperFactory wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
if (wrapperFactory != null)
{
wrapperFactory.resetRendererIgnoredCaveBlocks();
DhApi.Delayed.renderProxy.clearRenderDataCache();
}
}));
}
} }
public static class Multiplayer public static class Multiplayer
@@ -848,7 +978,7 @@ public class Config
.build(); .build();
// not currently implemented // not currently implemented
private static ConfigEntry<Boolean> enableMultiverseNetworking = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> enableMultiverseNetworking = new ConfigEntry.Builder<Boolean>()
.set(true) .set(true)
.comment("" .comment(""
+ "If true Distant Horizons will attempt to communicate with the connected \n" + "If true Distant Horizons will attempt to communicate with the connected \n"
@@ -856,59 +986,137 @@ public class Config
+ "") + "")
.build(); .build();
// not currently implemented public static ConfigCategory serverNetworking = new ConfigCategory.Builder().set(ServerNetworking.class).build();
private static ConfigEntry<Boolean> enableServerNetworking = new ConfigEntry.Builder<Boolean>()
.set(false) public static class ServerNetworking
.comment("" {
+ "Attention: this is only for developers and hasn't been implemented.\n" public static ConfigUIComment generalSectionNote = new ConfigUIComment();
+ "\n" public static ConfigEntry<Boolean> enableServerNetworking = new ConfigEntry.Builder<Boolean>()
+ "If true Distant Horizons will attempt to communicate with the connected \n" .setServersideShortName("enableServerNetworking")
+ "server in order to load LODs outside your vanilla render distance. \n" .set(true)
+ "\n" .comment(""
+ "Note: This requires DH to be installed on the server in order to function. \n" + "WARNING!\n"
+ "") + "Server-client networking is not yet fully implemented!\n"
.build(); + "Both the server and client must be running the server-side fork with this option enabled\n"
+ "for Distant Horizons data to be transceived.\n"
+ "\n"
+ "If true, the server and client will attempt to communicate to transceive Distant Horizons data.\n"
+ "This allows for further distant generation and LOD updates on all clients.\n"
+ "\n"
+ "This should only be used on trusted servers with trusted players!\n"
+ "")
.build();
public static ConfigEntry<Boolean> sendLevelKeys = new ConfigEntry.Builder<Boolean>()
.setServersideShortName("sendLevelKeys")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.set(true)
.comment(""
+ "Makes the server send level keys for each world.\n"
+ "Disable this if you use alternative ways to send level keys.\n"
+ "")
.build();
public static ConfigEntry<String> levelKeyPrefix = new ConfigEntry.Builder<String>()
.setServersideShortName("levelKeyPrefix")
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE)
.set(
Suppliers.compose(wrapper -> !wrapper.isDedicatedServer() || wrapper.isWorldInitialized(), () -> SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class)).get()
? ""
: "server" + ThreadLocalRandom.current().nextInt(1, 1000)
)
.comment(""
+ "Prefix of the level keys sent to the clients.\n"
+ "Should be set to a unique value for each backend server behind a proxy,\n"
+ "or empty if you don't use a proxy.\n"
+ "")
.build();
public static ConfigUIComment generationSectionNote = new ConfigUIComment();
public static ConfigEntry<Integer> generationRequestRateLimit = new ConfigEntry.Builder<Integer>()
.setServersideShortName("generationRequestRateLimit")
.setMinDefaultMax(1, 20, 100)
.comment(""
+ "How many LOD generation requests per second should a client send? \n"
+ "Also limits the amount of player's requests allowed to stay in the server's queue."
+ "")
.build();
public static ConfigUIComment realTimeUpdatesSectionNote = new ConfigUIComment();
public static ConfigEntry<Boolean> enableRealTimeUpdates = new ConfigEntry.Builder<Boolean>()
.setServersideShortName("enableRealTimeUpdates")
.set(false)
.comment(""
+ "If true, the client will receive real-time LOD updates for chunks outside the client's render distance."
+ "")
.build();
public static ConfigUIComment syncOnLoginSectionNote = new ConfigUIComment();
public static ConfigEntry<Boolean> synchronizeOnLogin = new ConfigEntry.Builder<Boolean>()
.setServersideShortName("synchronizeOnLogin")
.set(false)
.comment(""
+ "If true, clients will receive updated LODs on join if any changes occurred since last join."
+ "")
.build();
public static ConfigEntry<Integer> syncOnLoginRateLimit = new ConfigEntry.Builder<Integer>()
.setServersideShortName("syncOnLoginRateLimit")
.setMinDefaultMax(1, 50, 100)
.comment(""
+ "How many LOD sync requests per second should a client send? \n"
+ "Also limits the amount of player's requests allowed to stay in the server's queue."
+ "")
.build();
}
} }
public static class MultiThreading public static class MultiThreading
{ {
public static final String THREAD_NOTE = "" public static final String THREAD_NOTE = ""
+ "Multi-threading Note: \n" + "Multi-threading Note:\n"
+ "If the total thread count in Distant Horizon's config is more threads than your CPU has cores, \n" + "If the total thread count in Distant Horizon's config is more threads than your CPU has cores,\n"
+ "CPU performance may suffer if Distant Horizons has a lot to load or generate. \n" + "CPU performance may suffer if Distant Horizons has a lot to load or generate.\n"
+ "This can be an issue when first loading into a world, when flying, and/or when generating new terrain."; + "This can be an issue when first loading into a world, when flying, and/or when generating new terrain.";
public static final String THREAD_RUN_TIME_RATIO_NOTE = "" public static final String THREAD_RUN_TIME_RATIO_NOTE = ""
+ "If this value is less than 1.0, it will be treated as a percentage \n" + "If this value is less than 1.0, it will be treated as a percentage\n"
+ "of time each thread can run before going idle. \n" + "of time each thread can run before going idle.\n"
+ "\n" + "\n"
+ "This can be used to reduce CPU usage if the thread count \n" + "This can be used to reduce CPU usage if the thread count\n"
+ "is already set to 1 for the given option, or more finely \n" + "is already set to 1 for the given option, or more finely\n"
+ "tune CPU performance."; + "tune CPU performance.";
public static final ConfigEntry<Integer> numberOfWorldGenerationThreads = new ConfigEntry.Builder<Integer>() public static final ConfigEntry<Integer> numberOfWorldGenerationThreads = new ConfigEntry.Builder<Integer>()
.setServersideShortName("numberOfWorldGenerationThreads")
.setMinDefaultMax(1, .setMinDefaultMax(1,
ThreadPresetConfigEventHandler.getWorldGenDefaultThreadCount(), ThreadPresetConfigEventHandler.getWorldGenDefaultThreadCount(),
Runtime.getRuntime().availableProcessors()) Runtime.getRuntime().availableProcessors())
.comment("" .comment(""
+ "How many threads should be used when generating LOD \n" + "How many threads should be used when generating LOD\n"
+ "chunks outside the normal render distance? \n" + "chunks outside the normal render distance?\n"
+ "\n" + "\n"
+ "If you experience stuttering when generating distant LODs, \n" + "If you experience stuttering when generating distant LODs,\n"
+ "decrease this number. \n" + "decrease this number.\n"
+ "If you want to increase LOD \n" + "If you want to increase LOD\n"
+ "generation speed, increase this number. \n" + "generation speed, increase this number.\n"
+ "\n" + "\n"
+ THREAD_NOTE) + THREAD_NOTE)
.build(); .build();
public static final ConfigEntry<Double> runTimeRatioForWorldGenerationThreads = new ConfigEntry.Builder<Double>() public static final ConfigEntry<Double> runTimeRatioForWorldGenerationThreads = new ConfigEntry.Builder<Double>()
.setServersideShortName("runTimeRatioForWorldGenerationThreads")
.setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getWorldGenDefaultRunTimeRatio(), 1.0) .setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getWorldGenDefaultRunTimeRatio(), 1.0)
.comment(THREAD_RUN_TIME_RATIO_NOTE) .comment(THREAD_RUN_TIME_RATIO_NOTE)
.build(); .build();
public static final ConfigEntry<Integer> numberOfFileHandlerThreads = new ConfigEntry.Builder<Integer>() public static final ConfigEntry<Integer> numberOfFileHandlerThreads = new ConfigEntry.Builder<Integer>()
.setServersideShortName("numberOfFileHandlerThreads")
.setMinDefaultMax(1, .setMinDefaultMax(1,
ThreadPresetConfigEventHandler.getFileHandlerDefaultThreadCount(), ThreadPresetConfigEventHandler.getFileHandlerDefaultThreadCount(),
Runtime.getRuntime().availableProcessors()) Runtime.getRuntime().availableProcessors())
@@ -922,6 +1130,7 @@ public class Config
+ THREAD_NOTE) + THREAD_NOTE)
.build(); .build();
public static final ConfigEntry<Double> runTimeRatioForFileHandlerThreads = new ConfigEntry.Builder<Double>() public static final ConfigEntry<Double> runTimeRatioForFileHandlerThreads = new ConfigEntry.Builder<Double>()
.setServersideShortName("runTimeRatioForFileHandlerThreads")
.setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getFileHandlerDefaultRunTimeRatio(), 1.0) .setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getFileHandlerDefaultRunTimeRatio(), 1.0)
.comment(THREAD_RUN_TIME_RATIO_NOTE) .comment(THREAD_RUN_TIME_RATIO_NOTE)
.build(); .build();
@@ -952,6 +1161,7 @@ public class Config
.build(); .build();
public static final ConfigEntry<Integer> numberOfLodBuilderThreads = new ConfigEntry.Builder<Integer>() public static final ConfigEntry<Integer> numberOfLodBuilderThreads = new ConfigEntry.Builder<Integer>()
.setServersideShortName("numberOfLodBuilderThreads")
.setMinDefaultMax(1, .setMinDefaultMax(1,
ThreadPresetConfigEventHandler.getLodBuilderDefaultThreadCount(), ThreadPresetConfigEventHandler.getLodBuilderDefaultThreadCount(),
Runtime.getRuntime().availableProcessors()) Runtime.getRuntime().availableProcessors())
@@ -964,10 +1174,12 @@ public class Config
+ THREAD_NOTE) + THREAD_NOTE)
.build(); .build();
public static final ConfigEntry<Double> runTimeRatioForLodBuilderThreads = new ConfigEntry.Builder<Double>() public static final ConfigEntry<Double> runTimeRatioForLodBuilderThreads = new ConfigEntry.Builder<Double>()
.setServersideShortName("runTimeRatioForLodBuilderThreads")
.setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getLodBuilderDefaultRunTimeRatio(), 1.0) .setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getLodBuilderDefaultRunTimeRatio(), 1.0)
.comment(THREAD_RUN_TIME_RATIO_NOTE) .comment(THREAD_RUN_TIME_RATIO_NOTE)
.build(); .build();
public static final ConfigEntry<Boolean> enableLodBuilderThreadLimiting = new ConfigEntry.Builder<Boolean>() public static final ConfigEntry<Boolean> enableLodBuilderThreadLimiting = new ConfigEntry.Builder<Boolean>()
.setServersideShortName("enableLodBuilderThreadLimiting")
.set(true) .set(true)
.comment("" .comment(""
+ "Should only be disabled if deadlock occurs and LODs refuse to update. \n" + "Should only be disabled if deadlock occurs and LODs refuse to update. \n"
@@ -977,63 +1189,24 @@ public class Config
+ "") + "")
.build(); .build();
} public static final ConfigEntry<Integer> numberOfNetworkCompressionThreads = new ConfigEntry.Builder<Integer>()
.setServersideShortName("numberOfNetworkCompressionThreads")
public static class GpuBuffers .setMinDefaultMax(1,
{ ThreadPresetConfigEventHandler.getNetworkCompressionDefaultThreadCount(),
public static ConfigEntry<EDhApiGpuUploadMethod> gpuUploadMethod = new ConfigEntry.Builder<EDhApiGpuUploadMethod>() Runtime.getRuntime().availableProcessors())
.set(EDhApiGpuUploadMethod.AUTO)
.comment("" .comment(""
+ "What method should be used to upload geometry to the GPU? \n" + "How many threads should be used when building LODs? \n"
+ "\n" + "\n"
+ EDhApiGpuUploadMethod.AUTO + ": Picks the best option based on the GPU you have. \n" + "These threads run when terrain is generated, when\n"
+ "certain graphics settings are changed, and when moving around the world. \n"
+ "\n" + "\n"
+ EDhApiGpuUploadMethod.BUFFER_STORAGE + ": Default if OpenGL 4.5 is supported. \n" + THREAD_NOTE)
+ " Fast rendering, no stuttering. \n"
+ "\n"
+ EDhApiGpuUploadMethod.SUB_DATA + ": Backup option for NVIDIA. \n"
+ " Fast rendering but may stutter when uploading. \n"
+ "\n"
+ EDhApiGpuUploadMethod.BUFFER_MAPPING + ": Slow rendering but won't stutter when uploading. \n"
+ " Generally the best option for integrated GPUs. \n"
+ " Default option for AMD/Intel if OpenGL 4.5 isn't supported. \n"
+ " May end up storing buffers in System memory. \n"
+ " Fast rendering if in GPU memory, slow if in system memory, \n"
+ " but won't stutter when uploading. \n"
+ "\n"
+ EDhApiGpuUploadMethod.DATA + ": Fast rendering but will stutter when uploading. \n"
+ " Backup option for AMD/Intel. \n"
+ " Fast rendering but may stutter when uploading. \n"
+ "\n"
+ "If you don't see any difference when changing these settings, \n"
+ "or the world looks corrupted: restart your game."
+ "")
.build(); .build();
public static final ConfigEntry<Double> runTimeRatioForNetworkCompressionThreads = new ConfigEntry.Builder<Double>()
public static ConfigEntry<Integer> gpuUploadPerMegabyteInMilliseconds = new ConfigEntry.Builder<Integer>() .setServersideShortName("runTimeRatioForNetworkCompressionThreads")
.setMinDefaultMax(0, 0, 50) .setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getNetworkCompressionDefaultRunTimeRatio(), 1.0)
.comment("" .comment(THREAD_RUN_TIME_RATIO_NOTE)
+ "How long should a buffer wait per Megabyte of data uploaded? \n"
+ "Helpful resource for frame times: https://fpstoms.com \n"
+ "\n"
+ "Longer times may reduce stuttering but will make LODs \n"
+ "transition and load slower. Change this to [0] for no timeout. \n"
+ "\n"
+ "NOTE:\n"
+ "Before changing this config, try changing the \"GPU Upload method\" first. \n"
+ "")
.build(); .build();
public static ConfigEntry<Boolean> gpuUploadAsync = new ConfigEntry.Builder<Boolean>()
.set(true)
.comment(""
+ "If true geometry data will be uploaded on a DH controlled thread, reducing FPS stuttering. \n"
+ "If false uploading will be done on Minecraft's main rendering thread. \n"
+ "\n"
+ "Setting this to false may reduce crashes or corrupted geometry on systems with an AMD GPU when Sodium is installed.\n"
+ "")
.build();
} }
public static class AutoUpdater public static class AutoUpdater
@@ -1053,11 +1226,12 @@ public class Config
.build(); .build();
public static ConfigEntry<EDhApiUpdateBranch> updateBranch = new ConfigEntry.Builder<EDhApiUpdateBranch>() public static ConfigEntry<EDhApiUpdateBranch> updateBranch = new ConfigEntry.Builder<EDhApiUpdateBranch>()
.set( .set(EDhApiUpdateBranch.AUTO)
ModInfo.IS_DEV_BUILD? EDhApiUpdateBranch.NIGHTLY: EDhApiUpdateBranch.STABLE // If it's already a nightly build, then download the nightly build ofc
)
.comment("" .comment(""
+ " If DH should use the nightly (provided by Gitlab), or stable (provided by Modrinth) build") + "If DH should use the nightly (provided by Gitlab), or stable (provided by Modrinth) build. \n"
+ "If ["+EDhApiUpdateBranch.AUTO+"] is selected DH will update to new stable releases if the current jar is a stable jar \n"
+ "and will update to new nightly builds if the current jar is a nightly jar (IE the version number ends in '-dev')."
+ "")
.build(); .build();
} }
@@ -1066,68 +1240,97 @@ public class Config
// TODO add change all option // TODO add change all option
// TODO default to error chat and info file // TODO default to error chat and info file
public static ConfigEntry<EDhApiLoggerMode> logWorldGenEvent = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logWorldGenEvent = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_INFO_TO_FILE) .setServersideShortName("logWorldGenEvent")
.set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log information about the world generation process. \n" + "If enabled, the mod will log information about the world generation process. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<EDhApiLoggerMode> logWorldGenPerformance = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logWorldGenPerformance = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_FILE) .setServersideShortName("logWorldGenPerformance")
.set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log performance about the world generation process. \n" + "If enabled, the mod will log performance about the world generation process. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<EDhApiLoggerMode> logWorldGenLoadEvent = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logWorldGenLoadEvent = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_FILE) .setServersideShortName("logWorldGenPerformance")
.set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log information about the world generation process. \n" + "If enabled, the mod will log information about the world generation process. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<EDhApiLoggerMode> logLodBuilderEvent = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logLodBuilderEvent = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_INFO_TO_FILE) .setServersideShortName("logLodBuilderEvent")
.set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log information about the LOD generation process. \n" + "If enabled, the mod will log information about the LOD generation process. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<EDhApiLoggerMode> logRendererBufferEvent = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logRendererBufferEvent = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_INFO_TO_FILE) .set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log information about the renderer buffer process. \n" + "If enabled, the mod will log information about the renderer buffer process. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<EDhApiLoggerMode> logRendererGLEvent = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logRendererGLEvent = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_INFO_TO_FILE) .set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log information about the renderer OpenGL process. \n" + "If enabled, the mod will log information about the renderer OpenGL process. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<EDhApiLoggerMode> logFileReadWriteEvent = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logFileReadWriteEvent = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_INFO_TO_FILE) .setServersideShortName("logFileReadWriteEvent")
.set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log information about file read/write operations. \n" + "If enabled, the mod will log information about file read/write operations. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<EDhApiLoggerMode> logFileSubDimEvent = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logFileSubDimEvent = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_INFO_TO_FILE) .setServersideShortName("logFileSubDimEvent")
.set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log information about file sub-dimension operations. \n" + "If enabled, the mod will log information about file sub-dimension operations. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<EDhApiLoggerMode> logNetworkEvent = new ConfigEntry.Builder<EDhApiLoggerMode>() public static ConfigEntry<EDhApiLoggerMode> logNetworkEvent = new ConfigEntry.Builder<EDhApiLoggerMode>()
.set(EDhApiLoggerMode.LOG_WARNING_TO_CHAT_AND_INFO_TO_FILE) .setServersideShortName("logNetworkEvent")
.set(EDhApiLoggerMode.LOG_ERROR_TO_CHAT_AND_INFO_TO_FILE)
.comment("" .comment(""
+ "If enabled, the mod will log information about network operations. \n" + "If enabled, the mod will log information about network operations. \n"
+ "This can be useful for debugging.") + "This can be useful for debugging.")
.build(); .build();
public static ConfigEntry<Boolean> showLowMemoryWarningOnStartup = new ConfigEntry.Builder<Boolean>()
.set(true)
.comment(""
+ "If enabled, a chat message will be displayed if Java doesn't have enough \n"
+ "memory allocated to run DH well.")
.build();
public static ConfigEntry<Boolean> showReplayWarningOnStartup = new ConfigEntry.Builder<Boolean>()
.set(true)
.comment(""
+ "If enabled, a chat message will be displayed when a replay is started \n"
+ "giving some basic information about how DH will function.")
.build();
public static ConfigEntry<Boolean> showModCompatibilityWarningsOnStartup = new ConfigEntry.Builder<Boolean>()
.set(true)
.comment(""
+ "If enabled, a chat message will be displayed when a potentially problematic \n"
+ "mod is installed alongside DH.")
.build();
} }
public static class Debugging public static class Debugging
@@ -1195,6 +1398,15 @@ public class Config
+ "") + "")
.build(); .build();
public static ConfigEntry<Boolean> logBufferGarbageCollection = new ConfigEntry.Builder<Boolean>()
.set(false)
.comment(""
+ "If true OpenGL Buffer garbage collection will be logged \n"
+ "this also includes the number of live buffers. \n"
+ "")
.build();
// Note: This will reset on game restart, and should have a warning on the tooltip // Note: This will reset on game restart, and should have a warning on the tooltip
public static ConfigEntry<Boolean> allowUnsafeValues = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> allowUnsafeValues = new ConfigEntry.Builder<Boolean>()
.set(false) .set(false)
@@ -1205,22 +1417,38 @@ public class Config
public static ConfigEntry<Boolean> columnBuilderDebugEnable = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> columnBuilderDebugEnable = new ConfigEntry.Builder<Boolean>()
.set(false) .set(false)
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
.addListener(DebugColumnConfigEventHandler.INSTANCE) .addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Integer> columnBuilderDebugDetailLevel = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> columnBuilderDebugDetailLevel = new ConfigEntry.Builder<Integer>()
.set((int) DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) .set((int) DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
.addListener(DebugColumnConfigEventHandler.INSTANCE) .addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Integer> columnBuilderDebugXPos = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> columnBuilderDebugXPos = new ConfigEntry.Builder<Integer>()
.set(0) .set(0)
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
.addListener(DebugColumnConfigEventHandler.INSTANCE) .addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
public static ConfigEntry<Integer> columnBuilderDebugZPos = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> columnBuilderDebugZPos = new ConfigEntry.Builder<Integer>()
.set(0) .set(0)
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
.addListener(DebugColumnConfigEventHandler.INSTANCE) .addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build();
public static ConfigEntry<Integer> columnBuilderDebugXRow = new ConfigEntry.Builder<Integer>()
.set(-1)
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build();
public static ConfigEntry<Integer> columnBuilderDebugZRow = new ConfigEntry.Builder<Integer>()
.set(-1)
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build();
public static ConfigEntry<Integer> columnBuilderDebugColumnIndex = new ConfigEntry.Builder<Integer>()
.set(-1)
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
.addListener(ReloadLodsConfigEventHandler.INSTANCE)
.build(); .build();
@@ -1326,8 +1554,8 @@ public class Config
"Can be changed if you experience crashing when loading into a world.\n" + "Can be changed if you experience crashing when loading into a world.\n" +
"\n" + "\n" +
"Defines the OpenGL context type Distant Horizon's will create. \n" + "Defines the OpenGL context type Distant Horizon's will create. \n" +
"Generally this should be left as ["+ EDhApiGlProfileMode.CORE+"] unless there is an issue with your GPU driver. \n" + "Generally this should be left as [" + EDhApiGlProfileMode.CORE + "] unless there is an issue with your GPU driver. \n" +
"Possible values: ["+ StringUtil.join("],[", EDhApiGlProfileMode.values())+"] \n" + "Possible values: [" + StringUtil.join("],[", EDhApiGlProfileMode.values()) + "] \n" +
"") "")
.build(); .build();
public static ConfigEntry<Boolean> enableGlForwardCompatibilityMode = new ConfigEntry.Builder<Boolean>() public static ConfigEntry<Boolean> enableGlForwardCompatibilityMode = new ConfigEntry.Builder<Boolean>()
@@ -1406,9 +1634,9 @@ public class Config
.set(new HashMap<String, String>()) .set(new HashMap<String, String>())
.build(); .build();
public static ConfigUIButton uiButtonTest = new ConfigUIButton(() -> public static ConfigUIButton uiButtonTest = new ConfigUIButton(() ->
{ {
new Thread(() -> new Thread(() ->
{ {
if (!GraphicsEnvironment.isHeadless()) if (!GraphicsEnvironment.isHeadless())
{ {
@@ -1490,4 +1718,4 @@ public class Config
} }
} }
} }
@@ -23,9 +23,9 @@ import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy; import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy;
import com.seibel.distanthorizons.core.config.listeners.IConfigListener; import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
public class DebugColumnConfigEventHandler implements IConfigListener public class ReloadLodsConfigEventHandler implements IConfigListener
{ {
public static DebugColumnConfigEventHandler INSTANCE = new DebugColumnConfigEventHandler(); public static ReloadLodsConfigEventHandler INSTANCE = new ReloadLodsConfigEventHandler();
@Override @Override
public void onConfigValueSet() public void onConfigValueSet()
@@ -57,7 +57,9 @@ public abstract class AbstractPresetConfigEventHandler<TPresetEnum extends Enum<
public AbstractPresetConfigEventHandler() public AbstractPresetConfigEventHandler()
{ {
configGui.addOnScreenChangeListener(() -> this.onConfigUiClosed()); if (configGui != null) {
configGui.addOnScreenChangeListener(this::onConfigUiClosed);
}
} }
@@ -168,7 +170,7 @@ public abstract class AbstractPresetConfigEventHandler<TPresetEnum extends Enum<
if (newPreset != currentPreset) if (newPreset != currentPreset)
{ {
this.getPresetConfigEntry().set(this.getCustomPresetEnum()); this.getPresetConfigEntry().set(newPreset);
} }
} }
@@ -32,33 +32,33 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@SuppressWarnings("FieldCanBeLocal")
public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHandler<EDhApiThreadPreset> public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHandler<EDhApiThreadPreset>
{ {
public static final ThreadPresetConfigEventHandler INSTANCE = new ThreadPresetConfigEventHandler(); public static final ThreadPresetConfigEventHandler INSTANCE = new ThreadPresetConfigEventHandler();
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
private static final boolean LOW_THREAD_COUNT_CPU = (Runtime.getRuntime().availableProcessors() <= 4);
public static int getWorldGenDefaultThreadCount() { return getThreadCountByPercent(0.15); } public static int getWorldGenDefaultThreadCount() { return getThreadCountByPercent(0.1); }
private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Integer> worldGenThreadCount = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfWorldGenerationThreads, private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Integer> worldGenThreadCount = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfWorldGenerationThreads,
new HashMap<EDhApiThreadPreset, Integer>() new HashMap<EDhApiThreadPreset, Integer>()
{{ {{
this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 1); this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 1);
this.put(EDhApiThreadPreset.LOW_IMPACT, getWorldGenDefaultThreadCount()); this.put(EDhApiThreadPreset.LOW_IMPACT, getWorldGenDefaultThreadCount());
this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.25)); this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.15));
this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.5)); this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.25));
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0)); this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(0.5));
}}); }});
public static double getWorldGenDefaultRunTimeRatio() { return LOW_THREAD_COUNT_CPU ? 0.5 : 0.75; } public static double getWorldGenDefaultRunTimeRatio() { return 0.5; }
private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> worldGenRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForWorldGenerationThreads, private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> worldGenRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForWorldGenerationThreads,
new HashMap<EDhApiThreadPreset, Double>() new HashMap<EDhApiThreadPreset, Double>()
{{ {{
this.put(EDhApiThreadPreset.MINIMAL_IMPACT, LOW_THREAD_COUNT_CPU ? 0.1 : 0.25); this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 0.1);
this.put(EDhApiThreadPreset.LOW_IMPACT, getWorldGenDefaultRunTimeRatio()); this.put(EDhApiThreadPreset.LOW_IMPACT, getWorldGenDefaultRunTimeRatio());
this.put(EDhApiThreadPreset.BALANCED, LOW_THREAD_COUNT_CPU ? 0.5 : 0.75); this.put(EDhApiThreadPreset.BALANCED, 0.75);
this.put(EDhApiThreadPreset.AGGRESSIVE, LOW_THREAD_COUNT_CPU ? 0.75 : 1.0); this.put(EDhApiThreadPreset.AGGRESSIVE, 1.0);
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0); this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
}}); }});
@@ -71,13 +71,13 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.put(EDhApiThreadPreset.LOW_IMPACT, getFileHandlerDefaultThreadCount()); this.put(EDhApiThreadPreset.LOW_IMPACT, getFileHandlerDefaultThreadCount());
this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.2)); this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.2));
this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.2)); this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.2));
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0)); this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(0.5));
}}); }});
public static double getFileHandlerDefaultRunTimeRatio() { return 0.75; } public static double getFileHandlerDefaultRunTimeRatio() { return 0.5; }
private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> fileHandlerRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForFileHandlerThreads, private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> fileHandlerRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForFileHandlerThreads,
new HashMap<EDhApiThreadPreset, Double>() new HashMap<EDhApiThreadPreset, Double>()
{{ {{
this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 0.50); this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 0.25);
this.put(EDhApiThreadPreset.LOW_IMPACT, getFileHandlerDefaultRunTimeRatio()); this.put(EDhApiThreadPreset.LOW_IMPACT, getFileHandlerDefaultRunTimeRatio());
this.put(EDhApiThreadPreset.BALANCED, 1.0); this.put(EDhApiThreadPreset.BALANCED, 1.0);
this.put(EDhApiThreadPreset.AGGRESSIVE, 1.0); this.put(EDhApiThreadPreset.AGGRESSIVE, 1.0);
@@ -85,24 +85,24 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
}}); }});
public static int getUpdatePropagatorDefaultThreadCount() { return getThreadCountByPercent(0.25); } public static int getUpdatePropagatorDefaultThreadCount() { return getThreadCountByPercent(0.10); }
private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Integer> UpdatePropagatorThreadCount = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfUpdatePropagatorThreads, private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Integer> UpdatePropagatorThreadCount = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfUpdatePropagatorThreads,
new HashMap<EDhApiThreadPreset, Integer>() new HashMap<EDhApiThreadPreset, Integer>()
{{ {{
this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 1); this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 1);
this.put(EDhApiThreadPreset.LOW_IMPACT, getUpdatePropagatorDefaultThreadCount()); this.put(EDhApiThreadPreset.LOW_IMPACT, getUpdatePropagatorDefaultThreadCount());
this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.5)); this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.25));
this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.75)); this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.50));
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0)); this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(0.75));
}}); }});
public static double getUpdatePropagatorDefaultRunTimeRatio() { return 0.5; } public static double getUpdatePropagatorDefaultRunTimeRatio() { return 0.25; }
private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> UpdatePropagatorRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForUpdatePropagatorThreads, private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> UpdatePropagatorRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForUpdatePropagatorThreads,
new HashMap<EDhApiThreadPreset, Double>() new HashMap<EDhApiThreadPreset, Double>()
{{ {{
this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 0.25); this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 0.1);
this.put(EDhApiThreadPreset.LOW_IMPACT, getUpdatePropagatorDefaultRunTimeRatio()); this.put(EDhApiThreadPreset.LOW_IMPACT, getUpdatePropagatorDefaultRunTimeRatio());
this.put(EDhApiThreadPreset.BALANCED, 0.75); this.put(EDhApiThreadPreset.BALANCED, 0.50);
this.put(EDhApiThreadPreset.AGGRESSIVE, 1.0); this.put(EDhApiThreadPreset.AGGRESSIVE, 0.75);
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0); this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
}}); }});
@@ -115,15 +115,37 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.put(EDhApiThreadPreset.LOW_IMPACT, getLodBuilderDefaultThreadCount()); this.put(EDhApiThreadPreset.LOW_IMPACT, getLodBuilderDefaultThreadCount());
this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.2)); this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.2));
this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.4)); this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.4));
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0)); this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(0.6));
}}); }});
public static double getLodBuilderDefaultRunTimeRatio() { return LOW_THREAD_COUNT_CPU ? 0.25 : 0.5; } public static double getLodBuilderDefaultRunTimeRatio() { return 0.25; }
private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> lodBuilderRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForLodBuilderThreads, private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> lodBuilderRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForLodBuilderThreads,
new HashMap<EDhApiThreadPreset, Double>() new HashMap<EDhApiThreadPreset, Double>()
{{ {{
this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 0.1); this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 0.1);
this.put(EDhApiThreadPreset.LOW_IMPACT, getLodBuilderDefaultRunTimeRatio()); this.put(EDhApiThreadPreset.LOW_IMPACT, getLodBuilderDefaultRunTimeRatio());
this.put(EDhApiThreadPreset.BALANCED, LOW_THREAD_COUNT_CPU ? 0.5 : 0.75); this.put(EDhApiThreadPreset.BALANCED, 0.5);
this.put(EDhApiThreadPreset.AGGRESSIVE, 0.75);
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
}});
public static int getNetworkCompressionDefaultThreadCount() { return getThreadCountByPercent(0.3); }
private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Integer> networkCompressionThreadCount = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfNetworkCompressionThreads,
new HashMap<EDhApiThreadPreset, Integer>()
{{
this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 1);
this.put(EDhApiThreadPreset.LOW_IMPACT, getNetworkCompressionDefaultThreadCount());
this.put(EDhApiThreadPreset.BALANCED, getThreadCountByPercent(0.4));
this.put(EDhApiThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.6));
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(0.8));
}});
public static double getNetworkCompressionDefaultRunTimeRatio() { return 0.5; }
private final ConfigEntryWithPresetOptions<EDhApiThreadPreset, Double> networkCompressionRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForNetworkCompressionThreads,
new HashMap<EDhApiThreadPreset, Double>()
{{
this.put(EDhApiThreadPreset.MINIMAL_IMPACT, 0.25);
this.put(EDhApiThreadPreset.LOW_IMPACT, getNetworkCompressionDefaultRunTimeRatio());
this.put(EDhApiThreadPreset.BALANCED, 0.75);
this.put(EDhApiThreadPreset.AGGRESSIVE, 1.0); this.put(EDhApiThreadPreset.AGGRESSIVE, 1.0);
this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0); this.put(EDhApiThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
}}); }});
@@ -150,6 +172,9 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.configList.add(this.lodBuilderThreadCount); this.configList.add(this.lodBuilderThreadCount);
this.configList.add(this.lodBuilderRunTime); this.configList.add(this.lodBuilderRunTime);
this.configList.add(this.networkCompressionThreadCount);
this.configList.add(this.networkCompressionRunTime);
for (ConfigEntryWithPresetOptions<EDhApiThreadPreset, ?> config : this.configList) for (ConfigEntryWithPresetOptions<EDhApiThreadPreset, ?> config : this.configList)
{ {

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