Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b802ca362 | |||
| ea4375b215 | |||
| a6e94c39a7 | |||
| 8bd6b4837c | |||
| 679f871788 | |||
| b46f10755e | |||
| 3cf799a10f | |||
| 4e99594a3f | |||
| 8a4f991906 | |||
| ab634b3204 | |||
| b836f675e1 | |||
| a4e2003e0e | |||
| 28a8bc39f2 | |||
| 4f0a3afd93 | |||
| 4ac56774fb | |||
| 18b0582152 | |||
| b85c504995 | |||
| cbff0cd9e9 | |||
| c28cf643b3 | |||
| 44aed79e78 | |||
| e192abe666 | |||
| 9754943752 | |||
| 299ab0f856 | |||
| b97c35387c | |||
| f69ad051d1 | |||
| 9231a48998 | |||
| e8f27f7da8 | |||
| db47a9e99f | |||
| 16f72066a8 | |||
| ca4d6f158a | |||
| ad9092c45c | |||
| 95e4db2998 | |||
| 9fe5dcc16e | |||
| 8cd926f4ac | |||
| 7239b51073 | |||
| 262dcae36b | |||
| 062f86c036 | |||
| 5b4029f0ad | |||
| faa4fa3782 | |||
| 9db045d614 | |||
| c81dc83bb1 | |||
| b14701ef6b | |||
| 78f84f17cd | |||
| 7739e1cafd | |||
| d39c04d9cf | |||
| 492afa7328 | |||
| 9465512491 | |||
| 51b52a7d2a | |||
| f106867091 | |||
| 1c4908bbc5 | |||
| baa9b94a5d | |||
| 21136ba1ef | |||
| ec6f8255b5 | |||
| 2f9504b167 | |||
| f67d9e4e04 | |||
| c1644ad419 | |||
| e07557e6e3 | |||
| 52b8a91dc5 | |||
| 64fe804c40 | |||
| 2dd5b82be3 | |||
| d1f0325f87 | |||
| b10a367ce6 | |||
| 4dec387ca1 | |||
| fd3a8f7ddf | |||
| e3f586da56 | |||
| 775984f651 | |||
| 269f2c30fd | |||
| b674f49600 |
@@ -0,0 +1,17 @@
|
||||
package com.seibel.distanthorizons.api.enums.config;
|
||||
|
||||
/**
|
||||
* VULKAN, <br>
|
||||
* OPEN_GL, <br>
|
||||
*
|
||||
* @see EDhApiRenderingEngine
|
||||
*
|
||||
* @since API 7.0.0
|
||||
* @version 2026-3-10
|
||||
*/
|
||||
public enum EDhApiRenderingApi
|
||||
{
|
||||
VULKAN,
|
||||
OPEN_GL;
|
||||
|
||||
}
|
||||
+4
-4
@@ -1,16 +1,16 @@
|
||||
package com.seibel.distanthorizons.api.enums.config;
|
||||
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
|
||||
/**
|
||||
* AUTO, <br>
|
||||
* OPEN_GL, <br>
|
||||
* BLAZE_3D, <br><br>
|
||||
*
|
||||
* @since API 6.0.0
|
||||
* @see EDhApiRenderingApi
|
||||
*
|
||||
* @since API 7.0.0
|
||||
* @version 2026-3-10
|
||||
*/
|
||||
public enum EDhApiRenderApi
|
||||
public enum EDhApiRenderingEngine
|
||||
{
|
||||
AUTO,
|
||||
OPEN_GL,
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.api.enums.config;
|
||||
|
||||
/**
|
||||
* NEVER, <br>
|
||||
* DYNAMIC, <br>
|
||||
* ALWAYS <br> <br>
|
||||
*
|
||||
* This represents how far the LODs should overlap with
|
||||
* the vanilla Minecraft terrain.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @since API 2.0.0
|
||||
* @version 2024-4-6
|
||||
*/
|
||||
@Deprecated // not currently in use, if the config this enum represents is re-implemented, the deprecated flag can be removed
|
||||
public enum EDhApiVanillaOverdraw
|
||||
{
|
||||
/**
|
||||
* Don't draw LODs where a minecraft chunk could be.
|
||||
* Use Overdraw Offset to tweak the border thickness.
|
||||
*/
|
||||
NEVER,
|
||||
|
||||
/**
|
||||
* Draw LODs over the farther minecraft chunks.
|
||||
* Dynamically decides the border thickness
|
||||
*/
|
||||
DYNAMIC,
|
||||
|
||||
/** Draw LODs over all minecraft chunks. */
|
||||
ALWAYS,
|
||||
}
|
||||
+3
-15
@@ -21,25 +21,13 @@ package com.seibel.distanthorizons.api.enums.rendering;
|
||||
|
||||
/**
|
||||
* DISABLED, <br>
|
||||
* FAKE, <br>
|
||||
* COMPLETE, <br>
|
||||
*
|
||||
* @since API 2.0.0
|
||||
* @version 2024-4-6
|
||||
* @version 2026-05-19
|
||||
*/
|
||||
public enum EDhApiTransparency
|
||||
{
|
||||
DISABLED(false, false),
|
||||
FAKE(true, true),
|
||||
COMPLETE(true, false);
|
||||
|
||||
public final boolean transparencyEnabled;
|
||||
public final boolean fakeTransparencyEnabled;
|
||||
|
||||
EDhApiTransparency(boolean transparencyEnabled, boolean fakeTransparencyEnabled)
|
||||
{
|
||||
this.transparencyEnabled = transparencyEnabled;
|
||||
this.fakeTransparencyEnabled = fakeTransparencyEnabled;
|
||||
}
|
||||
|
||||
DISABLED,
|
||||
COMPLETE;
|
||||
}
|
||||
|
||||
+12
@@ -85,6 +85,18 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
|
||||
/** Modifies the quadratic function fake chunks use for horizontal quality drop-off. */
|
||||
IDhApiConfigValue<EDhApiHorizontalQuality> horizontalQuality();
|
||||
|
||||
/**
|
||||
* If true DH will try to use the camera position when
|
||||
* determining LOD quality drop-off. <br>
|
||||
* If false DH will use the player's position.
|
||||
* <br><br>
|
||||
* Enabling helps free-cam mods render correctly. <br>
|
||||
* Disabling helps multi-camera mods render correctly (ie Immersive Portals or camera mods).
|
||||
*
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
IDhApiConfigValue<Boolean> useCameraPositionForQualityDropOff();
|
||||
|
||||
IDhApiConfigValue<EDhApiTransparency> transparency();
|
||||
|
||||
/** Defines what blocks won't be rendered as LODs. */
|
||||
|
||||
+12
@@ -19,9 +19,21 @@
|
||||
|
||||
package com.seibel.distanthorizons.api.interfaces.override.rendering;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy;
|
||||
|
||||
/**
|
||||
* <b>Note: </b><br>
|
||||
* This is only used if Distant Horizons'
|
||||
* {@link IDhApiRenderProxy#getRenderingApi()} returns {@link EDhApiRenderingEngine#OPEN_GL}
|
||||
* and {@link IDhApiRenderProxy#isNativeRenderer()} returns true.
|
||||
* ie this is only used when DH is doing native OpenGL rendering,
|
||||
* if DH is using Blaze3D this interface will be ignored.
|
||||
*
|
||||
* @see IDhApiRenderProxy#getRenderingApi()
|
||||
* @see IDhApiRenderProxy#isNativeRenderer()
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2024-1-24
|
||||
* @since API 2.0.0
|
||||
|
||||
+11
@@ -19,7 +19,9 @@
|
||||
|
||||
package com.seibel.distanthorizons.api.interfaces.override.rendering;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy;
|
||||
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;
|
||||
@@ -27,7 +29,16 @@ import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
|
||||
/**
|
||||
* <b>Note: </b><br>
|
||||
* This is only used if Distant Horizons'
|
||||
* {@link IDhApiRenderProxy#getRenderingApi()} returns {@link EDhApiRenderingEngine#OPEN_GL}
|
||||
* and {@link IDhApiRenderProxy#isNativeRenderer()} returns true.
|
||||
* ie this is only used when DH is doing native OpenGL rendering,
|
||||
* if DH is using Blaze3D this interface will be ignored.
|
||||
*
|
||||
* @see IDhApiShaderProgram
|
||||
* @see IDhApiRenderProxy#getRenderingApi()
|
||||
* @see IDhApiRenderProxy#isNativeRenderer()
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2024-7-11
|
||||
|
||||
+11
@@ -19,12 +19,23 @@
|
||||
|
||||
package com.seibel.distanthorizons.api.interfaces.override.rendering;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
|
||||
|
||||
/**
|
||||
* <b>Note: </b><br>
|
||||
* This is only used if Distant Horizons'
|
||||
* {@link IDhApiRenderProxy#getRenderingApi()} returns {@link EDhApiRenderingEngine#OPEN_GL}
|
||||
* and {@link IDhApiRenderProxy#isNativeRenderer()} returns true.
|
||||
* ie this is only used when DH is doing native OpenGL rendering,
|
||||
* if DH is using Blaze3D this interface will be ignored.
|
||||
*
|
||||
* @see IDhApiGenericObjectShaderProgram
|
||||
* @see IDhApiRenderProxy#getRenderingApi()
|
||||
* @see IDhApiRenderProxy#isNativeRenderer()
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2024-1-24
|
||||
|
||||
+30
@@ -19,6 +19,9 @@
|
||||
|
||||
package com.seibel.distanthorizons.api.interfaces.render;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
|
||||
import com.seibel.distanthorizons.api.objects.DhApiResult;
|
||||
|
||||
|
||||
@@ -44,6 +47,33 @@ public interface IDhApiRenderProxy
|
||||
*/
|
||||
DhApiResult<Boolean> clearRenderDataCache();
|
||||
|
||||
/**
|
||||
* Returns which specific {@link EDhApiRenderingApi}
|
||||
* Distant Horizons will use for rendering. <br><br>
|
||||
*
|
||||
* @throws IllegalStateException if no renderer has been bound yet,
|
||||
* wait till after {@link DhApiAfterDhInitEvent} has been fired
|
||||
*
|
||||
* @see DhApiAfterDhInitEvent
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
EDhApiRenderingApi getRenderingApi() throws IllegalStateException;
|
||||
/**
|
||||
* Returns true if the current renderer
|
||||
* is calling the base rendering API's method calls. <br>
|
||||
* ie GL.drawArrays() for OpenGL. <Br><br>
|
||||
*
|
||||
* If DH is using a rendering interpretation layer like Blaze3D (Mojang's rendering API)
|
||||
* this will return false.
|
||||
*
|
||||
* @throws IllegalStateException if no renderer has been bound yet,
|
||||
* wait till after {@link DhApiAfterDhInitEvent} has been fired
|
||||
*
|
||||
* @see DhApiAfterDhInitEvent
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
boolean isNativeRenderer() throws IllegalStateException;
|
||||
|
||||
|
||||
|
||||
//=======================//
|
||||
|
||||
+26
@@ -21,8 +21,14 @@ package com.seibel.distanthorizons.api.interfaces.world;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper;
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
||||
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper;
|
||||
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBlockColorOverrideEvent;
|
||||
import com.seibel.distanthorizons.api.objects.DhApiResult;
|
||||
import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
@@ -90,6 +96,26 @@ public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper
|
||||
*/
|
||||
File getDhSaveFolder();
|
||||
|
||||
/**
|
||||
* Returns the color DH would use for the given block/biome
|
||||
* pair at the given world position before any API color overrides
|
||||
* are considered. <br>
|
||||
* API color overrides are ignored to prevent infinite
|
||||
* loops if this event is triggered inside said API override.
|
||||
* <br><br>
|
||||
*
|
||||
* Returns {@link DhApiResult#success} = false if {@link IDhApiLevelWrapper#getLevelType()} returns a {@link EDhApiLevelType#SERVER_LEVEL}
|
||||
* (server levels have no concept of textures or colors).
|
||||
*
|
||||
* @see DhApiBlockColorOverrideEvent
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
DhApiResult<Color> getBlockColorPreApi(
|
||||
IDhApiBlockStateWrapper blockStateWrapper,
|
||||
IDhApiBiomeWrapper biomeWrapper,
|
||||
int blockWorldPosX, int blockWorldPosY, int blockWorldPosZ,
|
||||
IDhApiFullDataSource dataSource);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+11
-9
@@ -59,23 +59,25 @@ public abstract class DhApiBeforeBufferRenderEvent implements IDhApiEvent<DhApiB
|
||||
* Measured in blocks.
|
||||
* Should be applied to the model view matrix to move the buffer into its proper place.
|
||||
*/
|
||||
public final DhApiVec3f modelPos;
|
||||
public DhApiVec3f modelPos;
|
||||
|
||||
|
||||
public EventParam(DhApiRenderParam parent, DhApiVec3f modelPos)
|
||||
|
||||
public EventParam() { }
|
||||
|
||||
public void update(DhApiRenderParam parent, DhApiVec3f modelPos)
|
||||
{
|
||||
super(parent);
|
||||
super.update(parent);
|
||||
this.modelPos = modelPos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getCopyBeforeFire() { return false; }
|
||||
|
||||
@Override
|
||||
public EventParam copy()
|
||||
{
|
||||
return new EventParam(
|
||||
this, this.modelPos.copy()
|
||||
);
|
||||
}
|
||||
public EventParam copy() { return this; }
|
||||
}
|
||||
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.api.methods.events.abstractEvents;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper;
|
||||
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
|
||||
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.DhApiFogRenderParam;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiMutableFogRenderParam;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource;
|
||||
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||
|
||||
/**
|
||||
* Fired before DH renders its fog.
|
||||
* Canceling this event disables fog for that frame.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2026-05-20
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
public abstract class DhApiBeforeFogRenderEvent implements IDhApiCancelableEvent<DhApiBeforeFogRenderEvent.EventParam>
|
||||
{
|
||||
/** Fired before fog is generated. */
|
||||
public abstract void beforeRender(DhApiCancelableEventParam<DhApiBeforeFogRenderEvent.EventParam> event);
|
||||
|
||||
|
||||
//=========================//
|
||||
// internal DH API methods //
|
||||
//=========================//
|
||||
|
||||
@Override
|
||||
public final void fireEvent(DhApiCancelableEventParam<DhApiBeforeFogRenderEvent.EventParam> event) { this.beforeRender(event); }
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// parameter object //
|
||||
//==================//
|
||||
|
||||
public static class EventParam implements IDhApiEventParam
|
||||
{
|
||||
private DhApiRenderParam renderParam;
|
||||
private DhApiFogRenderParam originalFogRenderParam;
|
||||
private DhApiMutableFogRenderParam fogRenderParam;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public EventParam() {}
|
||||
|
||||
public void update(DhApiRenderParam renderParam, DhApiFogRenderParam fogRenderParam)
|
||||
{
|
||||
this.renderParam = renderParam;
|
||||
this.originalFogRenderParam = fogRenderParam;
|
||||
this.fogRenderParam = new DhApiMutableFogRenderParam(fogRenderParam);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// getters/setters //
|
||||
//=================//
|
||||
//region
|
||||
|
||||
public DhApiRenderParam getRenderParam() { return this.renderParam; }
|
||||
|
||||
/** immutable, stores what DH would do without API intervention so API users have a reference point */
|
||||
public DhApiFogRenderParam getOriginalFogRenderParam() { return this.originalFogRenderParam; }
|
||||
/** mutable, can be modified by API users */
|
||||
public DhApiMutableFogRenderParam getFogRenderParam() { return this.fogRenderParam; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// base api event overrides //
|
||||
//==========================//
|
||||
//region
|
||||
|
||||
/**
|
||||
* Returns the same instance of this event.
|
||||
* Copying this event isn't supported
|
||||
* since the internal parameters must be mutated
|
||||
* by API users in order to be tracked by DH's internal
|
||||
* logic.
|
||||
*/
|
||||
@Override
|
||||
public DhApiBeforeFogRenderEvent.EventParam copy() { return this; }
|
||||
|
||||
@Override
|
||||
public boolean getCopyBeforeFire() { return false; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+27
-26
@@ -54,44 +54,45 @@ public abstract class DhApiBeforeGenericObjectRenderEvent implements IDhApiCance
|
||||
|
||||
public static class EventParam extends DhApiRenderParam implements IDhApiEventParam
|
||||
{
|
||||
public final long boxGroupId;
|
||||
public final String resourceLocationNamespace;
|
||||
public final String resourceLocationPath;
|
||||
public long boxGroupId;
|
||||
public String resourceLocationNamespace;
|
||||
public String resourceLocationPath;
|
||||
|
||||
|
||||
public EventParam(
|
||||
DhApiRenderParam renderParam,
|
||||
IDhApiRenderableBoxGroup boxGroup
|
||||
)
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
public EventParam() { }
|
||||
|
||||
/** internal DH method */
|
||||
public void update(DhApiRenderParam renderParam, IDhApiRenderableBoxGroup boxGroup)
|
||||
{
|
||||
super(renderParam);
|
||||
super.update(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;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public EventParam copy()
|
||||
{
|
||||
return new EventParam(
|
||||
this,
|
||||
this.boxGroupId, this.resourceLocationNamespace, this.resourceLocationPath
|
||||
);
|
||||
}
|
||||
public EventParam copy() { return this; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+42
-11
@@ -19,20 +19,21 @@
|
||||
|
||||
package com.seibel.distanthorizons.api.methods.events.abstractEvents;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
|
||||
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper;
|
||||
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
|
||||
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.IDhApiEventParam;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
|
||||
import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource;
|
||||
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Performance note: this event will be fired thousands of times on concurrent threads,
|
||||
* make it thread safe and as fast as possible. <Br><Br>
|
||||
* Performance note: this event will be fired millions of times on concurrent threads,
|
||||
* make it thread safe and as fast as possible. <br>
|
||||
* (If every LOD block goes through this event, On a 512 render distance world,
|
||||
* at the medium quality preset, it will be triggered around 40,000,000 times.)
|
||||
* <Br><Br>
|
||||
*
|
||||
* This event is fired when DH needs to convert a {@link IDhApiBlockStateWrapper}
|
||||
* into a color for rendering. This event is fired after DH attempts to determine
|
||||
@@ -45,13 +46,14 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* via {@link DhApiBlockStateWrapperCreatedEvent.EventParam#setAllowApiColorOverride(boolean)}.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2026-04-14
|
||||
* @version 2026-05-18
|
||||
* @since API 6.0.0
|
||||
* @see IDhApiBlockStateWrapper
|
||||
*/
|
||||
public abstract class DhApiBlockColorOverrideEvent implements IDhApiEvent<DhApiBlockColorOverrideEvent.EventParam>
|
||||
{
|
||||
public abstract void blockStateWrapperCreated(DhApiEventParam<EventParam> event);
|
||||
public abstract void onBlockColorOverridden(DhApiEventParam<EventParam> event);
|
||||
|
||||
|
||||
|
||||
//=========================//
|
||||
@@ -59,7 +61,8 @@ public abstract class DhApiBlockColorOverrideEvent implements IDhApiEvent<DhApiB
|
||||
//=========================//
|
||||
|
||||
@Override
|
||||
public final void fireEvent(DhApiEventParam<EventParam> event) { this.blockStateWrapperCreated(event); }
|
||||
public final void fireEvent(DhApiEventParam<EventParam> event) { this.onBlockColorOverridden(event); }
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
@@ -69,7 +72,9 @@ public abstract class DhApiBlockColorOverrideEvent implements IDhApiEvent<DhApiB
|
||||
public static class EventParam implements IDhApiEventParam
|
||||
{
|
||||
private IDhApiLevelWrapper levelWrapper;
|
||||
private IDhApiFullDataSource dataSource;
|
||||
private IDhApiBlockStateWrapper blockStateWrapper = null;
|
||||
private IDhApiBiomeWrapper biomeWrapper = null;
|
||||
private int colorAsInt = -1;
|
||||
private int blockPosX = 0, blockPosY = 0, blockPosZ = 0;
|
||||
|
||||
@@ -78,17 +83,22 @@ public abstract class DhApiBlockColorOverrideEvent implements IDhApiEvent<DhApiB
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public EventParam() {}
|
||||
|
||||
public void update(
|
||||
IDhApiLevelWrapper levelWrapper,
|
||||
IDhApiBlockStateWrapper blockStateWrapper,
|
||||
IDhApiFullDataSource dataSource,
|
||||
IDhApiBlockStateWrapper blockStateWrapper,
|
||||
IDhApiBiomeWrapper biomeWrapper,
|
||||
int colorAsInt,
|
||||
int blockPosX, int blockPosY, int blockPosZ)
|
||||
{
|
||||
this.levelWrapper = levelWrapper;
|
||||
this.dataSource = dataSource;
|
||||
this.blockStateWrapper = blockStateWrapper;
|
||||
this.biomeWrapper = biomeWrapper;
|
||||
this.colorAsInt = colorAsInt;
|
||||
|
||||
this.blockPosX = blockPosX;
|
||||
@@ -96,15 +106,27 @@ public abstract class DhApiBlockColorOverrideEvent implements IDhApiEvent<DhApiB
|
||||
this.blockPosZ = blockPosZ;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// getters/setters //
|
||||
//=================//
|
||||
//region
|
||||
|
||||
public IDhApiBlockStateWrapper getBlockStateWrapper() { return this.blockStateWrapper; }
|
||||
/** @since API 7.0.0 */
|
||||
public IDhApiBiomeWrapper getBiomeWrapper() { return this.biomeWrapper; }
|
||||
|
||||
public IDhApiLevelWrapper getLevelWrapper() { return levelWrapper; }
|
||||
/** the level DH is resolving this block's color in. */
|
||||
public IDhApiLevelWrapper getLevelWrapper() { return this.levelWrapper; }
|
||||
/**
|
||||
* The DH datasource that contains this block's position. Can be used to access adjacent
|
||||
* {@link IDhApiBlockStateWrapper}'s and {@link IDhApiBiomeWrapper}'s for adjacent aware tinting.
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
public IDhApiFullDataSource getDataSource() { return this.dataSource; }
|
||||
|
||||
public int getColorAsInt() { return this.colorAsInt; }
|
||||
public int getAlpha() { return ColorUtil.getAlpha(this.colorAsInt); }
|
||||
@@ -134,8 +156,15 @@ public abstract class DhApiBlockColorOverrideEvent implements IDhApiEvent<DhApiB
|
||||
/** @return the block's Z value in the world */
|
||||
public int getBlockPosZ() { return blockPosZ; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// base api event overrides //
|
||||
//==========================//
|
||||
//region
|
||||
|
||||
/**
|
||||
* Returns the same instance of this event.
|
||||
* Copying this event isn't supported
|
||||
@@ -149,6 +178,8 @@ public abstract class DhApiBlockColorOverrideEvent implements IDhApiEvent<DhApiB
|
||||
@Override
|
||||
public boolean getCopyBeforeFire() { return false; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -34,6 +34,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
|
||||
* @author James Seibel
|
||||
* @version 2023-6-23
|
||||
* @see IDhApiTerrainDataRepo
|
||||
* @see DhApiChunkProcessingEvent
|
||||
* @since API 1.0.0
|
||||
*/
|
||||
public abstract class DhApiChunkModifiedEvent implements IDhApiEvent<DhApiChunkModifiedEvent.EventParam>
|
||||
|
||||
+1
@@ -51,6 +51,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2025-09-29
|
||||
* @see DhApiChunkModifiedEvent
|
||||
* @since API 4.1.0
|
||||
*/
|
||||
public abstract class DhApiChunkProcessingEvent implements IDhApiEvent<DhApiChunkProcessingEvent.EventParam>
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.api.methods.events.sharedParameterObjects;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogFalloff;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
|
||||
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiFarFogConfig;
|
||||
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiFogConfig;
|
||||
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiHeightFogConfig;
|
||||
import com.seibel.distanthorizons.api.methods.events.interfaces.IDhApiEventParam;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Contains all the information needed to render Distant Horizons' fog.
|
||||
*
|
||||
* @see IDhApiFogConfig
|
||||
* @see IDhApiFarFogConfig
|
||||
* @see IDhApiHeightFogConfig
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2026-05-20
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
public class DhApiFogRenderParam implements IDhApiEventParam
|
||||
{
|
||||
protected Color fogColor;
|
||||
public Color getFogColor() { return this.fogColor; }
|
||||
|
||||
// far fog //
|
||||
//region
|
||||
|
||||
protected EDhApiFogFalloff farFogFalloff;
|
||||
/** @see IDhApiFarFogConfig#farFogFalloff() */
|
||||
public EDhApiFogFalloff getFarFogFalloff() { return this.farFogFalloff; }
|
||||
|
||||
protected float farFogStartPercent;
|
||||
/** @see IDhApiFarFogConfig#farFogStartDistance() */
|
||||
public float getFarFogStartPercent() { return this.farFogStartPercent; }
|
||||
|
||||
protected float farFogEndPercent;
|
||||
/** @see IDhApiFarFogConfig#farFogEndDistance() */
|
||||
public float getFarFogEndPercent() { return this.farFogEndPercent; }
|
||||
|
||||
protected float farFogMinThickness;
|
||||
/** @see IDhApiFarFogConfig#farFogMinThickness() */
|
||||
public float getFarFogMinThickness() { return this.farFogMinThickness; }
|
||||
|
||||
protected float farFogMaxThickness;
|
||||
/** @see IDhApiFarFogConfig#farFogMaxThickness() */
|
||||
public float getFarFogMaxThickness() { return this.farFogMaxThickness; }
|
||||
|
||||
protected float farFogDensity;
|
||||
/** @see IDhApiFarFogConfig#farFogDensity() */
|
||||
public float getFarFogDensity() { return this.farFogDensity; }
|
||||
|
||||
//endregion
|
||||
|
||||
// height fog //
|
||||
//region
|
||||
|
||||
protected EDhApiFogFalloff heightFogFalloff;
|
||||
/** @see IDhApiHeightFogConfig#heightFogFalloff() */
|
||||
public EDhApiFogFalloff getHeightFogFalloff() { return this.heightFogFalloff; }
|
||||
|
||||
protected EDhApiHeightFogMixMode heightFogMixingMode;
|
||||
/** @see IDhApiHeightFogConfig#heightFogMixMode() */
|
||||
public EDhApiHeightFogMixMode getHeightFogMixingMode() { return this.heightFogMixingMode; }
|
||||
|
||||
protected EDhApiHeightFogDirection heightFogDirection;
|
||||
/** @see IDhApiHeightFogConfig#heightFogDirection() */
|
||||
public EDhApiHeightFogDirection getHeightFogDirection() { return this.heightFogDirection; }
|
||||
|
||||
protected float heightFogBaseHeight;
|
||||
/** @see IDhApiHeightFogConfig#heightFogBaseHeight() */
|
||||
public float getHeightFogBaseHeight() { return this.heightFogBaseHeight; }
|
||||
|
||||
protected float heightFogStartPercent;
|
||||
/** @see IDhApiHeightFogConfig#heightFogStartingHeightPercent() */
|
||||
public float getHeightFogStartPercent() { return this.heightFogStartPercent; }
|
||||
|
||||
protected float heightFogEndPercent;
|
||||
/** @see IDhApiHeightFogConfig#heightFogEndingHeightPercent() */
|
||||
public float getHeightFogEndPercent() { return this.heightFogEndPercent; }
|
||||
|
||||
protected float heightFogMinThickness;
|
||||
/** @see IDhApiHeightFogConfig#heightFogMinThickness() */
|
||||
public float getHeightFogMinThickness() { return this.heightFogMinThickness; }
|
||||
|
||||
protected float heightFogMaxThickness;
|
||||
/** @see IDhApiHeightFogConfig#heightFogMaxThickness() */
|
||||
public float getHeightFogMaxThickness() { return this.heightFogMaxThickness; }
|
||||
|
||||
protected float heightFogDensity;
|
||||
/** @see IDhApiHeightFogConfig#heightFogDensity() */
|
||||
public float getHeightFogDensity() { return this.heightFogDensity; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
public DhApiFogRenderParam(DhApiFogRenderParam parent)
|
||||
{
|
||||
this(
|
||||
parent.fogColor,
|
||||
|
||||
// far fog
|
||||
parent.farFogFalloff,
|
||||
parent.farFogStartPercent, parent.farFogEndPercent,
|
||||
parent.farFogMinThickness, parent.farFogEndPercent,
|
||||
parent.farFogDensity,
|
||||
|
||||
// height fog
|
||||
parent.heightFogFalloff,
|
||||
parent.heightFogMixingMode, parent.heightFogDirection,
|
||||
parent.heightFogBaseHeight,
|
||||
parent.heightFogStartPercent, parent.heightFogEndPercent,
|
||||
parent.heightFogMinThickness, parent.heightFogMaxThickness,
|
||||
parent.heightFogDensity
|
||||
);
|
||||
}
|
||||
public DhApiFogRenderParam(
|
||||
Color fogColor,
|
||||
|
||||
// far fog
|
||||
EDhApiFogFalloff farFogFalloff,
|
||||
float farFogStartPercent, float farFogEndPercent,
|
||||
float farFogMinThickness, float farFogMaxThickness,
|
||||
float farFogDensity,
|
||||
|
||||
// height fog
|
||||
EDhApiFogFalloff heightFogFalloff,
|
||||
EDhApiHeightFogMixMode heightFogMixingMode, EDhApiHeightFogDirection heightFogDirection,
|
||||
float heightFogBaseHeight,
|
||||
float heightFogStartPercent, float heightFogEndPercent,
|
||||
float heightFogMinThickness, float heightFogMaxThickness,
|
||||
float heightFogDensity
|
||||
)
|
||||
{
|
||||
this.fogColor = fogColor;
|
||||
|
||||
// far fog
|
||||
this.farFogFalloff = farFogFalloff;
|
||||
this.farFogStartPercent = farFogStartPercent;
|
||||
this.farFogEndPercent = farFogEndPercent;
|
||||
this.farFogMinThickness = farFogMinThickness;
|
||||
this.farFogMaxThickness = farFogMaxThickness;
|
||||
this.farFogDensity = farFogDensity;
|
||||
|
||||
// height fog
|
||||
this.heightFogFalloff = heightFogFalloff;
|
||||
this.heightFogMixingMode = heightFogMixingMode;
|
||||
this.heightFogDirection = heightFogDirection;
|
||||
this.heightFogBaseHeight = heightFogBaseHeight;
|
||||
this.heightFogStartPercent = heightFogStartPercent;
|
||||
this.heightFogEndPercent = heightFogEndPercent;
|
||||
this.heightFogMinThickness = heightFogMinThickness;
|
||||
this.heightFogMaxThickness = heightFogMaxThickness;
|
||||
this.heightFogDensity = heightFogDensity;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public DhApiFogRenderParam copy() { return new DhApiFogRenderParam(this); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.api.methods.events.sharedParameterObjects;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogFalloff;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
|
||||
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiFarFogConfig;
|
||||
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiFogConfig;
|
||||
import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiHeightFogConfig;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* A mutable version of {@link DhApiFogRenderParam} to allow
|
||||
* API modification of DH's fog rendering.
|
||||
*
|
||||
* @see IDhApiFogConfig
|
||||
* @see IDhApiFarFogConfig
|
||||
* @see IDhApiHeightFogConfig
|
||||
* @see DhApiFogRenderParam
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2026-05-20
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
public class DhApiMutableFogRenderParam extends DhApiFogRenderParam
|
||||
{
|
||||
public void setFogColor(Color fogColor) { this.fogColor = fogColor; }
|
||||
|
||||
// far fog //
|
||||
//region
|
||||
|
||||
/** @see IDhApiFarFogConfig#farFogFalloff() */
|
||||
public void setFarFogFalloff(EDhApiFogFalloff farFogFalloff) { this.farFogFalloff = farFogFalloff; }
|
||||
/** @see IDhApiFarFogConfig#farFogStartDistance() */
|
||||
public void setFarFogStartPercent(float farFogStartPercent) { this.farFogStartPercent = farFogStartPercent; }
|
||||
/** @see IDhApiFarFogConfig#farFogEndDistance() */
|
||||
public void setFarFogEndPercent(float farFogEndPercent) { this.farFogEndPercent = farFogEndPercent; }
|
||||
/** @see IDhApiFarFogConfig#farFogMinThickness() */
|
||||
public void setFarFogMinThickness(float farFogMinThickness) { this.farFogMinThickness = farFogMinThickness; }
|
||||
/** @see IDhApiFarFogConfig#farFogMaxThickness() */
|
||||
public void setFarFogMaxThickness(float farFogMaxThickness) { this.farFogMaxThickness = farFogMaxThickness; }
|
||||
/** @see IDhApiFarFogConfig#farFogDensity() */
|
||||
public void setFarFogDensity(float farFogDensity) { this.farFogDensity = farFogDensity; }
|
||||
|
||||
//endregion
|
||||
|
||||
// height fog //
|
||||
//region
|
||||
|
||||
/** @see IDhApiHeightFogConfig#heightFogFalloff() */
|
||||
public void setHeightFogFalloff(EDhApiFogFalloff heightFogFalloff) { this.heightFogFalloff = heightFogFalloff; }
|
||||
/** @see IDhApiHeightFogConfig#heightFogMixMode() */
|
||||
public void setHeightFogMixingMode(EDhApiHeightFogMixMode heightFogMixingMode) { this.heightFogMixingMode = heightFogMixingMode; }
|
||||
/** @see IDhApiHeightFogConfig#heightFogDirection() */
|
||||
public void setHeightFogDirection(EDhApiHeightFogDirection heightFogDirection) { this.heightFogDirection = heightFogDirection; }
|
||||
/** @see IDhApiHeightFogConfig#heightFogBaseHeight() */
|
||||
public void setHeightFogBaseHeight(float heightFogBaseHeight) { this.heightFogBaseHeight = heightFogBaseHeight; }
|
||||
/** @see IDhApiHeightFogConfig#heightFogStartingHeightPercent() */
|
||||
public void setHeightFogStartPercent(float heightFogStartPercent) { this.heightFogStartPercent = heightFogStartPercent; }
|
||||
/** @see IDhApiHeightFogConfig#heightFogEndingHeightPercent() */
|
||||
public void setHeightFogEndPercent(float heightFogEnd) { this.heightFogEndPercent = heightFogEnd; }
|
||||
/** @see IDhApiHeightFogConfig#heightFogMinThickness() */
|
||||
public void setHeightFogMinThickness(float heightFogMinThickness) { this.heightFogMinThickness = heightFogMinThickness; }
|
||||
/** @see IDhApiHeightFogConfig#heightFogMaxThickness() */
|
||||
public void setHeightFogMaxThickness(float heightFogMaxThickness) { this.heightFogMaxThickness = heightFogMaxThickness; }
|
||||
/** @see IDhApiHeightFogConfig#heightFogDensity() */
|
||||
public void setHeightFogDensity(float heightFogDensity) { this.heightFogDensity = heightFogDensity; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
public DhApiMutableFogRenderParam(DhApiFogRenderParam parent)
|
||||
{ super(parent); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public DhApiMutableFogRenderParam copy() { return new DhApiMutableFogRenderParam(this); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+59
-30
@@ -35,62 +35,69 @@ import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||
public class DhApiRenderParam implements IDhApiEventParam
|
||||
{
|
||||
/** Indicates what render pass DH is currently rendering */
|
||||
public final EDhApiRenderPass renderPass;
|
||||
public EDhApiRenderPass renderPass;
|
||||
|
||||
/** Indicates how far into this tick the frame is. */
|
||||
public final float partialTicks;
|
||||
public float partialTicks;
|
||||
|
||||
/**
|
||||
* Indicates DH's near clip plane, measured in blocks.
|
||||
* Note: this may change based on time, player speed, and other factors.
|
||||
*/
|
||||
public final float nearClipPlane;
|
||||
public float nearClipPlane;
|
||||
/**
|
||||
* Indicates DH's far clip plane, measured in blocks.
|
||||
* Note: this may change based on time, player speed, and other factors.
|
||||
*/
|
||||
public final float farClipPlane;
|
||||
public float farClipPlane;
|
||||
|
||||
/** The projection matrix Minecraft is using to render this frame. */
|
||||
public final DhApiMat4f mcProjectionMatrix;
|
||||
public final DhApiMat4f mcProjectionMatrix = new DhApiMat4f();
|
||||
/** The model view matrix Minecraft is using to render this frame. */
|
||||
public final DhApiMat4f mcModelViewMatrix;
|
||||
public final DhApiMat4f mcModelViewMatrix = new DhApiMat4f();
|
||||
public final DhApiMat4f mcInverseMvmProjectionMatrix = new DhApiMat4f();
|
||||
|
||||
/** The projection matrix Distant Horizons is using to render this frame. */
|
||||
public final DhApiMat4f dhProjectionMatrix;
|
||||
public final DhApiMat4f dhProjectionMatrix = new DhApiMat4f();
|
||||
/** The model view matrix Distant Horizons is using to render this frame. */
|
||||
public final DhApiMat4f dhModelViewMatrix;
|
||||
public final DhApiMat4f dhModelViewMatrix = new DhApiMat4f();
|
||||
/** combination of the MVM and projection matrices */
|
||||
public final DhApiMat4f dhMvmProjMatrix;
|
||||
public final DhApiMat4f dhMvmProjMatrix = new DhApiMat4f();
|
||||
public final DhApiMat4f dhInverseMvmProjectionMatrix = new DhApiMat4f();
|
||||
|
||||
public final int worldYOffset;
|
||||
public int worldYOffset;
|
||||
|
||||
/**
|
||||
* The level currently being rendered.
|
||||
*
|
||||
* @since API 5.1.0
|
||||
*/
|
||||
public final IDhApiLevelWrapper clientLevelWrapper;
|
||||
public IDhApiLevelWrapper clientLevelWrapper;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
public DhApiRenderParam(DhApiRenderParam parent)
|
||||
public DhApiRenderParam() {}
|
||||
|
||||
/** Internal DH method */
|
||||
public void update(DhApiRenderParam param)
|
||||
{
|
||||
this(
|
||||
parent.renderPass,
|
||||
parent.partialTicks,
|
||||
parent.nearClipPlane, parent.farClipPlane,
|
||||
parent.mcProjectionMatrix.copy(), parent.mcModelViewMatrix.copy(),
|
||||
parent.dhProjectionMatrix.copy(), parent.dhModelViewMatrix.copy(),
|
||||
parent.worldYOffset,
|
||||
parent.clientLevelWrapper
|
||||
this.update(
|
||||
param.renderPass,
|
||||
param.partialTicks,
|
||||
param.nearClipPlane, param.farClipPlane,
|
||||
param.mcProjectionMatrix, param.mcModelViewMatrix,
|
||||
param.dhProjectionMatrix, param.mcModelViewMatrix,
|
||||
param.worldYOffset,
|
||||
param.clientLevelWrapper
|
||||
);
|
||||
}
|
||||
public DhApiRenderParam(
|
||||
/** Internal DH method */
|
||||
public void update(
|
||||
EDhApiRenderPass renderPass,
|
||||
float newPartialTicks,
|
||||
float nearClipPlane, float farClipPlane,
|
||||
@@ -107,29 +114,51 @@ public class DhApiRenderParam implements IDhApiEventParam
|
||||
this.farClipPlane = farClipPlane;
|
||||
this.nearClipPlane = nearClipPlane;
|
||||
|
||||
this.mcProjectionMatrix = newMcProjectionMatrix;
|
||||
this.mcModelViewMatrix = newMcModelViewMatrix;
|
||||
// mc matricies
|
||||
{
|
||||
this.mcProjectionMatrix.set(newMcProjectionMatrix);
|
||||
this.mcModelViewMatrix.set(newMcModelViewMatrix);
|
||||
|
||||
// inverse mvm Proj
|
||||
this.mcInverseMvmProjectionMatrix.set(newMcProjectionMatrix);
|
||||
this.mcInverseMvmProjectionMatrix.invert();
|
||||
}
|
||||
|
||||
this.dhProjectionMatrix = newDhProjectionMatrix;
|
||||
this.dhModelViewMatrix = newDhModelViewMatrix;
|
||||
|
||||
DhApiMat4f combinedMatrix = new DhApiMat4f(this.dhProjectionMatrix);
|
||||
combinedMatrix.multiply(this.dhModelViewMatrix);
|
||||
this.dhMvmProjMatrix = combinedMatrix;
|
||||
// dh matricies
|
||||
{
|
||||
this.dhProjectionMatrix.set(newDhProjectionMatrix);
|
||||
this.dhModelViewMatrix.set(newDhModelViewMatrix);
|
||||
|
||||
// proj
|
||||
this.dhMvmProjMatrix.set(this.dhProjectionMatrix);
|
||||
this.dhMvmProjMatrix.multiply(this.dhModelViewMatrix);
|
||||
|
||||
// inverse mvm Proj
|
||||
this.dhInverseMvmProjectionMatrix.set(this.dhMvmProjMatrix);
|
||||
this.dhInverseMvmProjectionMatrix.invert();
|
||||
}
|
||||
|
||||
this.worldYOffset = worldYOffset;
|
||||
this.clientLevelWrapper = clientLevelWrapper;
|
||||
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public DhApiRenderParam copy() { return new DhApiRenderParam(this); }
|
||||
public boolean getCopyBeforeFire() { return false; }
|
||||
|
||||
@Override
|
||||
public DhApiRenderParam copy() { return this; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public class DhApiResult<T>
|
||||
|
||||
|
||||
|
||||
// these constructors are private because the create... methods below are easier to understand
|
||||
// these constructors are private because the create methods below are easier to understand
|
||||
private DhApiResult(boolean success, String message) { this(success, message, null); }
|
||||
private DhApiResult(boolean success, String message, T payload)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,8 @@ package com.seibel.distanthorizons.api.objects.math;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.util.IDhApiCopyable;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* An (almost) exact copy of Minecraft's 1.16.5
|
||||
* implementation of a 4x4 float matrix. <br><br>
|
||||
@@ -33,7 +35,7 @@ import com.seibel.distanthorizons.api.interfaces.util.IDhApiCopyable;
|
||||
* </code>
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2024-6-30
|
||||
* @version 2026-05-22
|
||||
*/
|
||||
public class DhApiMat4f implements IDhApiCopyable
|
||||
{
|
||||
@@ -62,6 +64,7 @@ public class DhApiMat4f implements IDhApiCopyable
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
public DhApiMat4f() { /* all values are 0 */ }
|
||||
|
||||
@@ -71,14 +74,17 @@ public class DhApiMat4f implements IDhApiCopyable
|
||||
this.m01 = sourceMatrix.m01;
|
||||
this.m02 = sourceMatrix.m02;
|
||||
this.m03 = sourceMatrix.m03;
|
||||
|
||||
this.m10 = sourceMatrix.m10;
|
||||
this.m11 = sourceMatrix.m11;
|
||||
this.m12 = sourceMatrix.m12;
|
||||
this.m13 = sourceMatrix.m13;
|
||||
|
||||
this.m20 = sourceMatrix.m20;
|
||||
this.m21 = sourceMatrix.m21;
|
||||
this.m22 = sourceMatrix.m22;
|
||||
this.m23 = sourceMatrix.m23;
|
||||
|
||||
this.m30 = sourceMatrix.m30;
|
||||
this.m31 = sourceMatrix.m31;
|
||||
this.m32 = sourceMatrix.m32;
|
||||
@@ -109,12 +115,74 @@ public class DhApiMat4f implements IDhApiCopyable
|
||||
this.m33 = values[15];
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
/** Returns the values of this matrix in row major order (AKA rows then columns) */
|
||||
public float[] getValuesAsArray()
|
||||
{
|
||||
float[] array = new float[16];
|
||||
this.putValuesInArray(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the values of this matrix in row major order (AKA rows then columns)
|
||||
* @since API 7.0.0
|
||||
*/
|
||||
public void putValuesInArray(float[] array)
|
||||
{
|
||||
array[0] = this.m00;
|
||||
array[1] = this.m01;
|
||||
array[2] = this.m02;
|
||||
array[3] = this.m03;
|
||||
|
||||
array[4] = this.m10;
|
||||
array[5] = this.m11;
|
||||
array[6] = this.m12;
|
||||
array[7] = this.m13;
|
||||
|
||||
array[8] = this.m20;
|
||||
array[9] = this.m21;
|
||||
array[10] = this.m22;
|
||||
array[11] = this.m23;
|
||||
|
||||
array[12] = this.m30;
|
||||
array[13] = this.m31;
|
||||
array[14] = this.m32;
|
||||
array[15] = this.m33;
|
||||
}
|
||||
|
||||
|
||||
/** @since API 7.0.0 */
|
||||
public void set(DhApiMat4f mat)
|
||||
{
|
||||
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 setIdentity()
|
||||
{
|
||||
@@ -279,47 +347,14 @@ public class DhApiMat4f implements IDhApiCopyable
|
||||
this.m33 *= scalar;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// Distant Horizons //
|
||||
// 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) */
|
||||
public float[] getValuesAsArray()
|
||||
{
|
||||
return new float[]{
|
||||
this.m00,
|
||||
this.m01,
|
||||
this.m02,
|
||||
this.m03,
|
||||
|
||||
this.m10,
|
||||
this.m11,
|
||||
this.m12,
|
||||
this.m13,
|
||||
|
||||
this.m20,
|
||||
this.m21,
|
||||
this.m22,
|
||||
this.m23,
|
||||
|
||||
this.m30,
|
||||
this.m31,
|
||||
this.m32,
|
||||
this.m33,
|
||||
};
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
@@ -388,4 +423,8 @@ public class DhApiMat4f implements IDhApiCopyable
|
||||
@Override
|
||||
public DhApiMat4f copy() { return new DhApiMat4f(this); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+13
-3
@@ -35,6 +35,18 @@ import java.util.Map;
|
||||
*/
|
||||
public class DependencyInjector<BindableType extends IBindable> implements IDependencyInjector<BindableType> // Note to self: Don't try adding a generic type to IDhApiEvent, the constructor won't accept it
|
||||
{
|
||||
/**
|
||||
* empty list is to reduce GC pressure slightly in the common path
|
||||
* that {@link DependencyInjector#getInternalLogic(Class, boolean)} is called
|
||||
* when nothing has been bound.
|
||||
*/
|
||||
private static final ArrayList<?> EMPTY_GET_ALL_LIST = new ArrayList<>();
|
||||
static
|
||||
{
|
||||
EMPTY_GET_ALL_LIST.add(null);
|
||||
}
|
||||
|
||||
|
||||
protected final HashMap<Class<? extends BindableType>, ArrayList<BindableType>> dependencies = new HashMap<>();
|
||||
|
||||
/** Internal class reference to BindableType since we can't get it any other way. */
|
||||
@@ -246,9 +258,7 @@ public class DependencyInjector<BindableType extends IBindable> implements IDepe
|
||||
|
||||
|
||||
// return an empty list to prevent null pointers
|
||||
ArrayList<T> emptyList = new ArrayList<T>();
|
||||
emptyList.add(null);
|
||||
return emptyList;
|
||||
return (ArrayList<T>)EMPTY_GET_ALL_LIST;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
@@ -31,7 +31,7 @@ public final class ModInfo
|
||||
public static final String DEDICATED_SERVER_INITIAL_PATH = "dedicated_server_initial";
|
||||
|
||||
/** Incremented every time any packets are added, changed or removed, with a few exceptions. */
|
||||
public static final int PROTOCOL_VERSION = 13;
|
||||
public static final int PROTOCOL_VERSION = 15;
|
||||
|
||||
/**
|
||||
* The full plugin channel name (RESOURCE_NAMESPACE:WRAPPER_PACKET_PATH)
|
||||
@@ -43,16 +43,16 @@ public final class ModInfo
|
||||
public static final String NAME = "DistantHorizons";
|
||||
/** Human-readable version of NAME */
|
||||
public static final String READABLE_NAME = "Distant Horizons";
|
||||
public static final String VERSION = "3.0.3-b";
|
||||
public static final String VERSION = "3.0.4-b-dev";
|
||||
/** Returns true if the current build is an unstable developer build, false otherwise. */
|
||||
public static final boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
|
||||
|
||||
/** This version should only be updated when breaking changes are introduced to the DH API */
|
||||
public static final int API_MAJOR_VERSION = 6;
|
||||
public static final int API_MAJOR_VERSION = 7;
|
||||
/** 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 */
|
||||
public static final int API_PATCH_VERSION = 1;
|
||||
public static final int API_PATCH_VERSION = 0;
|
||||
|
||||
/** If the config file has an older version it'll be re-created from scratch. */
|
||||
public static final int CONFIG_FILE_VERSION = 4;
|
||||
|
||||
+6
-2
@@ -85,17 +85,21 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
|
||||
public IDhApiConfigValue<EDhApiHorizontalQuality> horizontalQuality()
|
||||
{ return new DhApiConfigValue<EDhApiHorizontalQuality, EDhApiHorizontalQuality>(Config.Client.Advanced.Graphics.Quality.horizontalQuality); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Boolean> useCameraPositionForQualityDropOff()
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.Quality.useCameraPositionForQualityDropOff); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<EDhApiTransparency> transparency()
|
||||
{ return new DhApiConfigValue<EDhApiTransparency, EDhApiTransparency>(Config.Client.Advanced.Graphics.Quality.transparency); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<EDhApiBlocksToAvoid> blocksToAvoid()
|
||||
{ return new DhApiConfigValue<EDhApiBlocksToAvoid, EDhApiBlocksToAvoid>(Config.Client.Advanced.Graphics.Quality.blocksToIgnore); }
|
||||
{ return new DhApiConfigValue<EDhApiBlocksToAvoid, EDhApiBlocksToAvoid>(Config.Client.Advanced.Graphics.Culling.blocksToIgnore); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Boolean> tintWithAvoidedBlocks()
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks); }
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.Culling.tintWithAvoidedBlocks); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Integer> getBiomeBlending()
|
||||
|
||||
+37
-15
@@ -39,15 +39,15 @@ import com.seibel.distanthorizons.core.util.DhApiTerrainDataPointUtil;
|
||||
import com.seibel.distanthorizons.core.util.FullDataPointUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.RayCastUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3f;
|
||||
import com.seibel.distanthorizons.core.world.AbstractDhWorld;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3i;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3i;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -71,24 +71,28 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
// debugging values
|
||||
private static volatile boolean debugThreadRunning = false;
|
||||
private static DhApiTerrainDataCache debugDataCache = new DhApiTerrainDataCache();
|
||||
private static DhApiVec3i currentDebugVec3i = new Vec3i();
|
||||
private static DhApiVec3i currentDebugVec3i = new DhVec3i();
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private DhApiTerrainDataRepo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// Getter Methods //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public DhApiResult<DhApiTerrainDataPoint> getSingleDataPointAtBlockPos(IDhApiLevelWrapper levelWrapper, int blockPosX, int blockPosY, int blockPosZ, IDhApiTerrainDataCache dataCache)
|
||||
@@ -109,9 +113,12 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
public DhApiResult<DhApiTerrainDataPoint[][][]> getAllTerrainDataAtDetailLevelAndPos(IDhApiLevelWrapper levelWrapper, byte detailLevel, int posX, int posZ, IDhApiTerrainDataCache dataCache)
|
||||
{ return getTerrainDataOverAreaForPositionDetailLevel(levelWrapper, DhSectionPos.encode(detailLevel, posX, posZ), dataCache); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
// private getters //
|
||||
//region
|
||||
|
||||
/** Returns a single API terrain datapoint that contains the given Y block position */
|
||||
private static DhApiResult<DhApiTerrainDataPoint> getTerrainDataAtBlockYPos(IDhApiLevelWrapper levelWrapper, long requestedColumnPos, Integer blockYPos, IDhApiTerrainDataCache dataCache)
|
||||
@@ -340,11 +347,14 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// raycasting methods //
|
||||
//====================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public DhApiResult<DhApiRaycastResult> raycast(
|
||||
@@ -356,8 +366,8 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
IDhApiTerrainDataCache dataCache)
|
||||
{
|
||||
return this.raycastLodData(levelWrapper,
|
||||
new Vec3d(rayOriginX, rayOriginY, rayOriginZ),
|
||||
new Vec3f(rayDirectionX, rayDirectionY, rayDirectionZ),
|
||||
new DhVec3d(rayOriginX, rayOriginY, rayOriginZ),
|
||||
new DhVec3f(rayDirectionX, rayDirectionY, rayDirectionZ),
|
||||
maxRayBlockLength, dataCache);
|
||||
}
|
||||
|
||||
@@ -369,7 +379,7 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
*/
|
||||
private DhApiResult<DhApiRaycastResult> raycastLodData(
|
||||
IDhApiLevelWrapper levelWrapper,
|
||||
Vec3d rayOrigin, Vec3f rayDirection,
|
||||
DhVec3d rayOrigin, DhVec3f rayDirection,
|
||||
int maxRayBlockLength,
|
||||
@Nullable
|
||||
IDhApiTerrainDataCache dataCache)
|
||||
@@ -386,9 +396,9 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
int currentLength = 0;
|
||||
|
||||
// the exact position of this step
|
||||
Vec3d exactPos = new Vec3d(rayOrigin.x, rayOrigin.y, rayOrigin.z);
|
||||
DhVec3d exactPos = new DhVec3d(rayOrigin.x, rayOrigin.y, rayOrigin.z);
|
||||
// the block position for this step
|
||||
Vec3i blockPos = new Vec3i((int) Math.round(rayOrigin.x), (int) Math.round(rayOrigin.y), (int) Math.round(rayOrigin.z));
|
||||
DhVec3i blockPos = new DhVec3i((int) Math.round(rayOrigin.x), (int) Math.round(rayOrigin.y), (int) Math.round(rayOrigin.z));
|
||||
|
||||
DhApiRaycastResult closetFoundDataPoint = null;
|
||||
|
||||
@@ -398,8 +408,8 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
&& currentLength <= maxRayBlockLength)
|
||||
{
|
||||
// get the LOD columns around this position
|
||||
ArrayList<Vec3i> columnPositions = getIntersectingColumnsAtPosition(blockPos, rayDirection);
|
||||
for (Vec3i columnPos : columnPositions)
|
||||
ArrayList<DhVec3i> columnPositions = getIntersectingColumnsAtPosition(blockPos, rayDirection);
|
||||
for (DhVec3i columnPos : columnPositions)
|
||||
{
|
||||
// check each column
|
||||
DhApiResult<DhApiTerrainDataPoint[]> result = this.getColumnDataAtBlockPos(levelWrapper, columnPos.x, columnPos.z, dataCache);
|
||||
@@ -416,7 +426,7 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
if (dataPoint.blockStateWrapper != null && !dataPoint.blockStateWrapper.isAir())
|
||||
{
|
||||
// does this LOD contain the given Y position?
|
||||
Vec3i dataPointPos = new Vec3i(columnPos.x, dataPoint.bottomYBlockPos, columnPos.z);
|
||||
DhVec3i dataPointPos = new DhVec3i(columnPos.x, dataPoint.bottomYBlockPos, columnPos.z);
|
||||
if (exactPos.y >= dataPoint.bottomYBlockPos
|
||||
&& exactPos.y <= dataPoint.topYBlockPos)
|
||||
{
|
||||
@@ -469,15 +479,15 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
*
|
||||
* Used to make sure the raycast step doesn't accidentally walk over any adjacent data.
|
||||
*/
|
||||
private static ArrayList<Vec3i> getIntersectingColumnsAtPosition(Vec3i rayEndingPos, Vec3f rayDirection)
|
||||
private static ArrayList<DhVec3i> getIntersectingColumnsAtPosition(DhVec3i rayEndingPos, DhVec3f rayDirection)
|
||||
{
|
||||
ArrayList<Vec3i> returnList = new ArrayList<>(9);
|
||||
ArrayList<DhVec3i> returnList = new ArrayList<>(9);
|
||||
|
||||
for (int x = -1; x <= 1; x++)
|
||||
{
|
||||
for (int z = -1; z <= 1; z++)
|
||||
{
|
||||
Vec3i pos = new Vec3i(rayEndingPos.x + x, rayEndingPos.y, rayEndingPos.z + z);
|
||||
DhVec3i pos = new DhVec3i(rayEndingPos.x + x, rayEndingPos.y, rayEndingPos.z + z);
|
||||
|
||||
// check if this column is intersected by the ray
|
||||
if (RayCastUtil.rayIntersectsSquare(rayEndingPos.x, rayEndingPos.z, rayDirection.x, rayDirection.z, pos.x, pos.z, 1))
|
||||
@@ -490,11 +500,14 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
return returnList;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// setter methods //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public DhApiResult<Void> overwriteChunkDataAsync(IDhApiLevelWrapper levelWrapper, Object[] chunkObjectArray) throws ClassCastException
|
||||
@@ -524,20 +537,26 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
return DhApiResult.createSuccess();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// API helpers //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public IDhApiTerrainDataCache createSoftCache() { return new DhApiTerrainDataCache(); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// debug methods //
|
||||
//===============//
|
||||
//region
|
||||
|
||||
/**
|
||||
* This method is here for debugging the repo and isn't intended for normal use.
|
||||
@@ -618,5 +637,8 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -36,11 +36,12 @@ import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||
import com.seibel.distanthorizons.core.render.renderer.*;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.util.objects.Pair;
|
||||
import com.seibel.distanthorizons.core.util.objects.RollingAverage;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IImmersivePortalsAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhVanillaFadeRenderer;
|
||||
@@ -53,7 +54,6 @@ import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiDebugRendering;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRendererMode;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
||||
import com.seibel.distanthorizons.core.world.AbstractDhWorld;
|
||||
import com.seibel.distanthorizons.core.world.DhClientWorld;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
@@ -65,9 +65,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
@@ -87,6 +87,12 @@ public class ClientApi
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
/** Delayed accessing is necessary since this object will be created before the mod accessors are bound. */
|
||||
private static class DelayedAccessors
|
||||
{
|
||||
public static final IImmersivePortalsAccessor IMMERSIVE_PORTALS = ModAccessorInjector.INSTANCE.get(IImmersivePortalsAccessor.class);
|
||||
}
|
||||
|
||||
/** this includes the is dev build message and low allocated memory warning */
|
||||
private static final int MS_BETWEEN_STATIC_STARTUP_MESSAGES = 4_000;
|
||||
|
||||
@@ -99,6 +105,11 @@ public class ClientApi
|
||||
* Only downside is making sure each variable is populated before rendering.
|
||||
*/
|
||||
public static final DhRenderState RENDER_STATE = new DhRenderState();
|
||||
/**
|
||||
* static variable so we don't have to re-create it each frame,
|
||||
* reducing GC pressure.
|
||||
*/
|
||||
private static final RenderParams RENDER_PARAMS = new RenderParams();
|
||||
|
||||
/**
|
||||
* 50ms = 20 FPS
|
||||
@@ -119,16 +130,10 @@ public class ClientApi
|
||||
|
||||
public boolean rendererDisabledBecauseOfExceptions = false;
|
||||
|
||||
private final ClientPluginChannelApi pluginChannelApi = new ClientPluginChannelApi(this::clientLevelLoadEvent, this::clientLevelUnloadEvent);
|
||||
|
||||
/** Delay loading the first level to give the server some time to respond with level to actually load */
|
||||
private Timer firstLevelLoadTimer;
|
||||
private static final long FIRST_LEVEL_LOAD_DELAY_IN_MS = 1_000;
|
||||
|
||||
/** Holds any levels that were loaded before the {@link ClientApi#onClientOnlyConnected} was fired. */
|
||||
public final HashSet<IClientLevelWrapper> waitingClientLevels = new HashSet<>();
|
||||
/** Holds any chunks that were loaded before the {@link ClientApi#clientLevelLoadEvent(IClientLevelWrapper)} was fired. */
|
||||
public final HashMap<Pair<IClientLevelWrapper, DhChunkPos>, IChunkWrapper> waitingChunkByClientLevelAndPos = new HashMap<>();
|
||||
/** Holds any chunks that were found before the client levels are loaded. */
|
||||
public final Map<Pair<IClientLevelWrapper, DhChunkPos>, IChunkWrapper> waitingChunkByClientLevelAndPos = new ConcurrentHashMap<>();
|
||||
|
||||
/** publicly available so {@link F3Screen} can display the error */
|
||||
@Nullable
|
||||
@@ -144,11 +149,10 @@ public class ClientApi
|
||||
* tracked should also be to keep the ratio roughly the same.
|
||||
* @see ClientApi#MIN_MS_BETWEEN_SPEED_CHECKS
|
||||
*/
|
||||
public RollingAverage cameraSpeedRollingAverage = new RollingAverage(40);
|
||||
private Vec3d lastCameraPosForSpeedCheck = new Vec3d();
|
||||
private final RollingAverage cameraSpeedRollingAverage = new RollingAverage(40);
|
||||
private DhVec3d lastCameraPosForSpeedCheck = new DhVec3d();
|
||||
private long msSinceLastSpeedCheck = 0L;
|
||||
|
||||
public static long firstRenderTimeMs = 0;
|
||||
public double getAvgCameraSpeed() { return cameraSpeedRollingAverage.getAverage(); }
|
||||
|
||||
/**
|
||||
* keeping track of this is necessary to fix
|
||||
@@ -176,7 +180,7 @@ public class ClientApi
|
||||
|
||||
/**
|
||||
* May be fired slightly before or after the associated
|
||||
* {@link ClientApi#clientLevelLoadEvent(IClientLevelWrapper)} event
|
||||
* level is loaded
|
||||
* depending on how the host mod loader functions. <br><br>
|
||||
*
|
||||
* Synchronized shouldn't be necessary, but is present to match {@see onClientOnlyDisconnected} and prevent any unforeseen issues.
|
||||
@@ -210,30 +214,12 @@ public class ClientApi
|
||||
|
||||
DhClientWorld world = new DhClientWorld();
|
||||
SharedApi.setDhWorld(world);
|
||||
|
||||
this.pluginChannelApi.onJoinServer(world.networkState.getSession());
|
||||
world.networkState.sendConfigMessage();
|
||||
|
||||
LOGGER.info("Loading [" + this.waitingClientLevels.size() + "] waiting client level wrappers.");
|
||||
for (IClientLevelWrapper level : this.waitingClientLevels)
|
||||
{
|
||||
this.clientLevelLoadEvent(level);
|
||||
}
|
||||
|
||||
this.waitingClientLevels.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/** Synchronized to prevent a rare issue where multiple disconnect events are triggered on top of each other. */
|
||||
public synchronized void onClientOnlyDisconnected()
|
||||
{
|
||||
// clear the first time timer
|
||||
if (this.firstLevelLoadTimer != null)
|
||||
{
|
||||
this.firstLevelLoadTimer.cancel();
|
||||
this.firstLevelLoadTimer = null;
|
||||
}
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
{
|
||||
@@ -243,11 +229,8 @@ public class ClientApi
|
||||
SharedApi.setDhWorld(null);
|
||||
}
|
||||
|
||||
this.pluginChannelApi.reset();
|
||||
|
||||
// remove any waiting items
|
||||
this.waitingChunkByClientLevelAndPos.clear();
|
||||
this.waitingClientLevels.clear();
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -257,97 +240,9 @@ public class ClientApi
|
||||
//==============//
|
||||
// level events //
|
||||
//==============//
|
||||
//region level events
|
||||
//region
|
||||
|
||||
public void clientLevelUnloadEvent(IClientLevelWrapper level)
|
||||
{
|
||||
try
|
||||
{
|
||||
LOGGER.info("Unloading client level [" + level.getClass().getSimpleName() + "]-[" + level.getDhIdentifier() + "].");
|
||||
|
||||
if (level instanceof IServerKeyedClientLevel)
|
||||
{
|
||||
this.pluginChannelApi.onClientLevelUnload();
|
||||
}
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
{
|
||||
world.unloadLevel(level);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.waitingClientLevels.remove(level);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// handle errors here to prevent blowing up a mixin or API up stream
|
||||
LOGGER.error("Unexpected error in ClientApi.clientLevelUnloadEvent(), error: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void clientLevelLoadEvent(@Nullable IClientLevelWrapper levelWrapper)
|
||||
{
|
||||
// can happen if there was an issue during level load
|
||||
if (levelWrapper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// wait a moment before loading the level to give the server a chance to handle the client's login request
|
||||
if (MC_CLIENT.clientConnectedToDedicatedServer())
|
||||
{
|
||||
if (this.firstLevelLoadTimer == null)
|
||||
{
|
||||
this.firstLevelLoadTimer = TimerUtil.CreateTimer("FirstLevelLoadTimer");
|
||||
this.firstLevelLoadTimer.schedule(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run() { ClientApi.this.clientLevelLoadEvent(levelWrapper); }
|
||||
}, FIRST_LEVEL_LOAD_DELAY_IN_MS);
|
||||
return;
|
||||
}
|
||||
this.firstLevelLoadTimer.cancel();
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
LOGGER.info("Loading client level [" + levelWrapper + "]-[" + levelWrapper.getDhIdentifier() + "].");
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
{
|
||||
if (!this.pluginChannelApi.allowLevelLoading(levelWrapper))
|
||||
{
|
||||
LOGGER.info("Levels in this connection are managed by the server, skipping auto-load.");
|
||||
|
||||
// Instead of attempting to load themselves, send the config and wait for a server provided level key.
|
||||
((DhClientWorld) world).networkState.sendConfigMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
world.getOrLoadLevel(levelWrapper);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(levelWrapper));
|
||||
|
||||
this.loadWaitingChunksForLevel(levelWrapper);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.waitingClientLevels.add(levelWrapper);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// handle errors here to prevent blowing up a mixin or API up stream
|
||||
LOGGER.error("Unexpected error in ClientApi.clientLevelLoadEvent(), error: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
private void loadWaitingChunksForLevel(IClientLevelWrapper level)
|
||||
public void loadWaitingChunksForLevel(IClientLevelWrapper level)
|
||||
{
|
||||
HashSet<Pair<IClientLevelWrapper, DhChunkPos>> keysToRemove = new HashSet<>();
|
||||
for (Pair<IClientLevelWrapper, DhChunkPos> levelChunkPair : this.waitingChunkByClientLevelAndPos.keySet())
|
||||
@@ -396,7 +291,8 @@ public class ClientApi
|
||||
{
|
||||
executor.execute(() ->
|
||||
{
|
||||
NetworkSession networkSession = this.pluginChannelApi.networkSession;
|
||||
DhClientWorld world = (DhClientWorld) Objects.requireNonNull(SharedApi.tryGetDhClientWorld());
|
||||
NetworkSession networkSession = world.pluginChannelApi.networkSession;
|
||||
if (networkSession != null)
|
||||
{
|
||||
networkSession.tryHandleMessage(message);
|
||||
@@ -498,14 +394,17 @@ public class ClientApi
|
||||
//region
|
||||
|
||||
long nowMs = System.currentTimeMillis();
|
||||
if (this.msSinceLastSpeedCheck + MIN_MS_BETWEEN_SPEED_CHECKS < nowMs)
|
||||
if (this.msSinceLastSpeedCheck + MIN_MS_BETWEEN_SPEED_CHECKS < nowMs
|
||||
// don't track camera speed for dimensions the player isn't in
|
||||
&& (DelayedAccessors.IMMERSIVE_PORTALS == null
|
||||
|| !DelayedAccessors.IMMERSIVE_PORTALS.isRenderingPortal()))
|
||||
{
|
||||
// calc time since last check
|
||||
double secSinceLastCheck = (nowMs - this.msSinceLastSpeedCheck) / 1_000.0;
|
||||
this.msSinceLastSpeedCheck = nowMs;
|
||||
|
||||
// get the distance traveled since last frame
|
||||
Vec3d camPos = MC_RENDER.getCameraExactPosition();
|
||||
DhVec3d camPos = MC_RENDER.getCameraExactPosition();
|
||||
double distanceInBlocks = camPos.getDistance(this.lastCameraPosForSpeedCheck);
|
||||
double speed = distanceInBlocks / secSinceLastCheck;
|
||||
|
||||
@@ -570,7 +469,7 @@ public class ClientApi
|
||||
// render prep and actual rendering into different threads/methods
|
||||
// this is annoying since it's possible to start a render with only
|
||||
// partially complete info, but there isn't a better option at the moment
|
||||
RenderParams renderParams = new RenderParams(renderPass, RENDER_STATE);
|
||||
RENDER_PARAMS.update(renderPass, RENDER_STATE);
|
||||
|
||||
//endregion
|
||||
|
||||
@@ -581,12 +480,7 @@ public class ClientApi
|
||||
//============//
|
||||
//region
|
||||
|
||||
if (firstRenderTimeMs == 0)
|
||||
{
|
||||
firstRenderTimeMs = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
String validationMessage = renderParams.getValidationErrorMessage(firstRenderTimeMs);
|
||||
String validationMessage = RENDER_PARAMS.getValidationErrorMessage();
|
||||
if (validationMessage != null)
|
||||
{
|
||||
// store the error message so it can be seen on the F3 screen
|
||||
@@ -632,10 +526,10 @@ public class ClientApi
|
||||
{
|
||||
if (!renderingDeferredLayer)
|
||||
{
|
||||
boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderEvent.class, renderParams);
|
||||
boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderEvent.class, RENDER_PARAMS);
|
||||
if (!renderingCancelled)
|
||||
{
|
||||
LodRenderer.INSTANCE.render(renderParams, profiler);
|
||||
LodRenderer.INSTANCE.render(RENDER_PARAMS, profiler);
|
||||
}
|
||||
|
||||
if (!DhApi.Delayed.renderProxy.getDeferTransparentRendering())
|
||||
@@ -645,10 +539,10 @@ public class ClientApi
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDeferredRenderEvent.class, renderParams);
|
||||
boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDeferredRenderEvent.class, RENDER_PARAMS);
|
||||
if (!renderingCancelled)
|
||||
{
|
||||
LodRenderer.INSTANCE.renderDeferred(renderParams, profiler);
|
||||
LodRenderer.INSTANCE.renderDeferred(RENDER_PARAMS, profiler);
|
||||
}
|
||||
|
||||
|
||||
@@ -669,11 +563,11 @@ public class ClientApi
|
||||
{
|
||||
// meta renderer needed for render state/texture
|
||||
// for setup on some APIs (IE openGL)
|
||||
metaRenderer.runRenderPassSetup(renderParams);
|
||||
metaRenderer.runRenderPassSetup(RENDER_PARAMS);
|
||||
|
||||
testRenderer.render(renderParams);
|
||||
testRenderer.render(RENDER_PARAMS);
|
||||
|
||||
metaRenderer.runRenderPassCleanup(renderParams);
|
||||
metaRenderer.runRenderPassCleanup(RENDER_PARAMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -727,11 +621,10 @@ public class ClientApi
|
||||
// or if LOD-only mode is enabled (fading is used to remove the MC render pass)
|
||||
|| Config.Client.Advanced.Debugging.lodOnlyMode.get()
|
||||
)
|
||||
// don't fade when Iris shaders are active, otherwise the rendering can get weird
|
||||
&& !DhApiRenderProxy.INSTANCE.getDeferTransparentRendering())
|
||||
&& shouldRenderFade())
|
||||
{
|
||||
RenderParams renderParams = new RenderParams(EDhApiRenderPass.OPAQUE, RENDER_STATE);
|
||||
fadeRenderer.render(renderParams);
|
||||
RENDER_PARAMS.update(EDhApiRenderPass.OPAQUE, RENDER_STATE);
|
||||
fadeRenderer.render(RENDER_PARAMS);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -757,16 +650,34 @@ public class ClientApi
|
||||
// or if LOD-only mode is enabled (fading is used to remove the MC render pass)
|
||||
|| Config.Client.Advanced.Debugging.lodOnlyMode.get()
|
||||
)
|
||||
// don't fade when Iris shaders are active, otherwise the rendering can get weird
|
||||
&& !DhApiRenderProxy.INSTANCE.getDeferTransparentRendering();
|
||||
&& shouldRenderFade();
|
||||
if (renderFade)
|
||||
{
|
||||
RenderParams renderParams = new RenderParams(EDhApiRenderPass.TRANSPARENT, RENDER_STATE);
|
||||
fadeRenderer.render(renderParams);
|
||||
RENDER_PARAMS.update(EDhApiRenderPass.TRANSPARENT, RENDER_STATE);
|
||||
fadeRenderer.render(RENDER_PARAMS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldRenderFade()
|
||||
{
|
||||
// don't fade when Iris shaders are active, otherwise the rendering can get weird
|
||||
if (DhApiRenderProxy.INSTANCE.getDeferTransparentRendering())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't render fade through immersive portals, this causes the fade to apply incorrectly
|
||||
IImmersivePortalsAccessor immersivePortals = ModAccessorInjector.INSTANCE.get(IImmersivePortalsAccessor.class);
|
||||
if (immersivePortals != null
|
||||
&& immersivePortals.isRenderingPortal())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
+15
-31
@@ -10,13 +10,13 @@ import com.seibel.distanthorizons.core.network.event.internal.CloseInternalEvent
|
||||
import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage;
|
||||
import com.seibel.distanthorizons.core.network.session.NetworkSession;
|
||||
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||
import com.seibel.distanthorizons.core.world.AbstractDhWorld;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This class is used to manage the level keys.
|
||||
@@ -30,9 +30,6 @@ public class ClientPluginChannelApi
|
||||
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 NetworkSession networkSession;
|
||||
|
||||
@@ -42,10 +39,8 @@ public class ClientPluginChannelApi
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public ClientPluginChannelApi(Consumer<IServerKeyedClientLevel> levelLoadHandler, Consumer<IClientLevelWrapper> levelUnloadHandler)
|
||||
public ClientPluginChannelApi()
|
||||
{
|
||||
this.levelLoadHandler = levelLoadHandler;
|
||||
this.levelUnloadHandler = levelUnloadHandler;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,38 +83,27 @@ public class ClientPluginChannelApi
|
||||
throw new IllegalArgumentException("Server sent invalid level key.");
|
||||
}
|
||||
|
||||
LOGGER.info("Server level key received: [" + msg.levelKey + "].");
|
||||
LOGGER.info("Level init received for [" + msg.dimensionResourceLocation + "]: server key [" + msg.serverKey + "], level key [" + msg.levelKey + "]");
|
||||
|
||||
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("ClientPluginChannelApi onLevelInitMessage", () ->
|
||||
{
|
||||
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.getDhIdentifier() + "].");
|
||||
this.levelUnloadHandler.accept(clientLevel);
|
||||
}
|
||||
IServerKeyedClientLevel existingKeyedClientLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel(clientLevel);
|
||||
|
||||
if (existingKeyedClientLevel == null
|
||||
|| !existingKeyedClientLevel.getServerKey().equals(msg.serverKey)
|
||||
|| !existingKeyedClientLevel.getServerLevelKey().equals(msg.levelKey))
|
||||
|| !existingKeyedClientLevel.getServerKey().equals(msg.serverKey)
|
||||
|| !existingKeyedClientLevel.getServerLevelKey().equals(msg.levelKey))
|
||||
{
|
||||
LOGGER.info("Loading level with key: [" + msg.levelKey + "].");
|
||||
IServerKeyedClientLevel keyedLevel = KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(clientLevel, msg.serverKey, msg.levelKey);
|
||||
this.levelLoadHandler.accept(keyedLevel);
|
||||
|
||||
IServerKeyedClientLevel keyedLevel = KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(clientLevel, msg.dimensionResourceLocation, msg.serverKey, msg.levelKey);
|
||||
|
||||
if (keyedLevel != null) {
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null) {
|
||||
world.getOrLoadLevel(keyedLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,13 +19,10 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.api.internal;
|
||||
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
|
||||
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
|
||||
import com.seibel.distanthorizons.core.world.*;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
@@ -77,7 +74,6 @@ public class ServerApi
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// level events //
|
||||
//==============//
|
||||
@@ -90,7 +86,6 @@ public class ServerApi
|
||||
if (serverWorld != null)
|
||||
{
|
||||
serverWorld.getOrLoadLevel(levelWrapper);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(levelWrapper));
|
||||
}
|
||||
}
|
||||
public void serverLevelUnloadEvent(IServerLevelWrapper level)
|
||||
@@ -101,12 +96,10 @@ public class ServerApi
|
||||
if (serverWorld != null)
|
||||
{
|
||||
serverWorld.unloadLevel(level);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=======================//
|
||||
// chunk modified events //
|
||||
//=======================//
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
package com.seibel.distanthorizons.core.api.internal.rendering;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhMat4f;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
|
||||
@@ -12,8 +12,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp
|
||||
*/
|
||||
public class DhRenderState
|
||||
{
|
||||
public Mat4f mcModelViewMatrix = null;
|
||||
public Mat4f mcProjectionMatrix = null;
|
||||
public DhMat4f mcModelViewMatrix = null;
|
||||
public DhMat4f mcProjectionMatrix = null;
|
||||
/**
|
||||
* percentage of time into the current client tick. <br><br>
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,6 +55,16 @@ public class ConfigEntry<T> extends AbstractConfigBase<T>
|
||||
@Nullable
|
||||
private T apiValue;
|
||||
|
||||
/**
|
||||
* Will be null if un-set. <br> <br>
|
||||
*
|
||||
* Some options aren't supported on all Minecraft versions,
|
||||
* in those cases this value will be set to override the
|
||||
* config file option.
|
||||
*/
|
||||
@Nullable
|
||||
private T mcVersionOverrideValue;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
@@ -127,7 +137,14 @@ public class ConfigEntry<T> extends AbstractConfigBase<T>
|
||||
return this.allowApiOverride
|
||||
&& this.apiValue != null;
|
||||
}
|
||||
|
||||
|
||||
/** setting to null will allow the config to be used normally */
|
||||
public void setMcVersionOverrideValue(@Nullable T value)
|
||||
{ this.mcVersionOverrideValue = value; }
|
||||
|
||||
public boolean mcVersionOverridePresent()
|
||||
{ return this.mcVersionOverrideValue != null; }
|
||||
|
||||
/**
|
||||
* Should only be used when loading the config from file. <Br>
|
||||
* Sets the value without informing the rest of the code (ie, it doesn't call listeners, or saving the value to file).
|
||||
@@ -183,6 +200,12 @@ public class ConfigEntry<T> extends AbstractConfigBase<T>
|
||||
@Override
|
||||
public T get()
|
||||
{
|
||||
// always use the MC version specific option if defined
|
||||
if (this.mcVersionOverrideValue != null)
|
||||
{
|
||||
return this.mcVersionOverrideValue;
|
||||
}
|
||||
|
||||
if (this.allowApiOverride
|
||||
&& this.apiValue != null)
|
||||
{
|
||||
|
||||
+16
-14
@@ -41,28 +41,28 @@ public final class BufferQuad
|
||||
public static final int MAX_QUAD_WIDTH_FOR_EARTH_CURVATURE = LodUtil.CHUNK_WIDTH;
|
||||
|
||||
|
||||
public final short x;
|
||||
public final short y;
|
||||
public final short z;
|
||||
public short x;
|
||||
public short y;
|
||||
public short z;
|
||||
|
||||
public short widthEastWest;
|
||||
/** This is both North/South and Up/Down since the merging logic is the same either way */
|
||||
public short widthNorthSouthOrHeight;
|
||||
|
||||
public final int color;
|
||||
public int color;
|
||||
/** used by the Iris shader mod to determine how each LOD should be rendered */
|
||||
public final byte irisBlockMaterialId;
|
||||
public byte irisBlockMaterialId;
|
||||
|
||||
public final byte skyLight;
|
||||
public final byte blockLight;
|
||||
public final EDhDirection direction;
|
||||
public byte skyLight;
|
||||
public byte blockLight;
|
||||
public EDhDirection direction;
|
||||
|
||||
public boolean hasError = false;
|
||||
|
||||
// Pre-computed sort keys to avoid recomputing on every comparison
|
||||
// Slight increase in memory for reduction in cpu usage
|
||||
public final long sortKeyEastWest;
|
||||
public final long sortKeyNorthSouth;
|
||||
public long sortKeyEastWest;
|
||||
public long sortKeyNorthSouth;
|
||||
|
||||
|
||||
|
||||
@@ -71,15 +71,17 @@ public final class BufferQuad
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public BufferQuad(
|
||||
short x, short y, short z, short widthEastWest, short widthNorthSouthOrHeight,
|
||||
int color, byte irisBlockMaterialId, byte skylight, byte blockLight,
|
||||
EDhDirection direction)
|
||||
public BufferQuad() {}
|
||||
|
||||
public void set(short x, short y, short z, short widthEastWest, short widthNorthSouthOrHeight,
|
||||
int color, byte irisBlockMaterialId, byte skylight, byte blockLight,
|
||||
EDhDirection direction)
|
||||
{
|
||||
if (widthEastWest == 0 || widthNorthSouthOrHeight == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Size 0 quad!");
|
||||
}
|
||||
|
||||
if (widthEastWest < 0 || widthNorthSouthOrHeight < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Negative sized quad!");
|
||||
|
||||
+60
-54
@@ -19,11 +19,14 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiTransparency;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
||||
import com.seibel.distanthorizons.core.util.objects.pooling.PhantomArrayListCheckout;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.RenderDataPointUtil;
|
||||
@@ -51,7 +54,7 @@ public class ColumnBox
|
||||
|
||||
public static void addBoxQuadsToBuilder(
|
||||
LodQuadBuilder builder, PhantomArrayListCheckout phantomArrayCheckout, IDhClientLevel clientLevel,
|
||||
short width, short yHeight,
|
||||
short blockWidth, short yHeight,
|
||||
short minX, short minY, short minZ,
|
||||
int color, byte irisBlockMaterialId, byte skyLight, byte blockLight,
|
||||
long topData, long bottomData, ColumnRenderView[] adjData, boolean[] isAdjDataSameDetailLevel)
|
||||
@@ -60,14 +63,19 @@ public class ColumnBox
|
||||
// variable setup //
|
||||
//================//
|
||||
|
||||
short maxX = (short) (minX + width);
|
||||
IClientLevelWrapper clientLevelWrapper = clientLevel.getClientLevelWrapper();
|
||||
if (clientLevelWrapper == null)
|
||||
{
|
||||
LodUtil.assertNotReach("addBoxQuadsToBuilder getClientLevelWrapper should always succeed");
|
||||
}
|
||||
|
||||
short maxX = (short) (minX + blockWidth);
|
||||
short maxY = (short) (minY + yHeight);
|
||||
short maxZ = (short) (minZ + width);
|
||||
short maxZ = (short) (minZ + blockWidth);
|
||||
byte skyLightTop = skyLight;
|
||||
byte skyLightBot = RenderDataPointUtil.doesDataPointExist(bottomData) ? RenderDataPointUtil.getLightSky(bottomData) : 0;
|
||||
|
||||
boolean transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled;
|
||||
boolean fakeOceanFloor = Config.Client.Advanced.Graphics.Quality.transparency.get().fakeTransparencyEnabled;
|
||||
boolean transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get() == EDhApiTransparency.COMPLETE;
|
||||
|
||||
boolean isTransparent = ColorUtil.getAlpha(color) < 255 && transparencyEnabled;
|
||||
boolean overVoid = !RenderDataPointUtil.doesDataPointExist(bottomData);
|
||||
@@ -92,24 +100,6 @@ public class ColumnBox
|
||||
}
|
||||
|
||||
|
||||
// fake ocean transparency
|
||||
if (transparencyEnabled && fakeOceanFloor)
|
||||
{
|
||||
if (!isTransparent && isTopTransparent && RenderDataPointUtil.doesDataPointExist(topData))
|
||||
{
|
||||
skyLightTop = (byte) MathUtil.clamp(0, 15 - (RenderDataPointUtil.getYMax(topData) - minY), 15);
|
||||
yHeight = (short) (RenderDataPointUtil.getYMax(topData) - minY - 1);
|
||||
}
|
||||
else if (isTransparent && !isBottomTransparent && RenderDataPointUtil.doesDataPointExist(bottomData))
|
||||
{
|
||||
minY = (short) (minY + yHeight - 1);
|
||||
yHeight = 1;
|
||||
}
|
||||
|
||||
maxY = (short) (minY + yHeight);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// add top and bottom faces //
|
||||
@@ -122,7 +112,7 @@ public class ColumnBox
|
||||
&& !isTopTransparent;
|
||||
if (!skipTop)
|
||||
{
|
||||
builder.addQuadUp(minX, maxY, minZ, width, ColorUtil.applyShade(color, MC_RENDER.getShade(EDhDirection.UP)), irisBlockMaterialId, skyLightTop, blockLight);
|
||||
builder.addQuadUp(minX, maxY, minZ, blockWidth, ColorUtil.applyShade(color, clientLevelWrapper.getShade(EDhDirection.UP)), irisBlockMaterialId, skyLightTop, blockLight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +123,7 @@ public class ColumnBox
|
||||
&& !isBottomTransparent;
|
||||
if (!skipBottom)
|
||||
{
|
||||
builder.addQuadDown(minX, minY, minZ, width, ColorUtil.applyShade(color, MC_RENDER.getShade(EDhDirection.DOWN)), irisBlockMaterialId, skyLightBot, blockLight);
|
||||
builder.addQuadDown(minX, minY, minZ, blockWidth, ColorUtil.applyShade(color, clientLevelWrapper.getShade(EDhDirection.DOWN)), irisBlockMaterialId, skyLightBot, blockLight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,16 +146,16 @@ public class ColumnBox
|
||||
builder.addQuadAdj(
|
||||
EDhDirection.NORTH,
|
||||
minX, minY, minZ,
|
||||
width, yHeight,
|
||||
blockWidth, yHeight,
|
||||
color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAdjVerticalQuad(
|
||||
builder, phantomArrayCheckout,
|
||||
builder, phantomArrayCheckout, clientLevelWrapper,
|
||||
adjCol, adjSameDetailLevel, caveCullingMaxY, EDhDirection.NORTH,
|
||||
minX, minY, minZ, width, yHeight,
|
||||
minX, minY, minZ, blockWidth, yHeight,
|
||||
color, irisBlockMaterialId, blockLight);
|
||||
}
|
||||
}
|
||||
@@ -181,16 +171,16 @@ public class ColumnBox
|
||||
builder.addQuadAdj(
|
||||
EDhDirection.SOUTH,
|
||||
minX, minY, maxZ,
|
||||
width, yHeight,
|
||||
blockWidth, yHeight,
|
||||
color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAdjVerticalQuad(
|
||||
builder, phantomArrayCheckout,
|
||||
builder, phantomArrayCheckout, clientLevelWrapper,
|
||||
adjCol, adjSameDetailLevel, caveCullingMaxY, EDhDirection.SOUTH,
|
||||
minX, minY, maxZ, width, yHeight,
|
||||
minX, minY, maxZ, blockWidth, yHeight,
|
||||
color, irisBlockMaterialId, blockLight);
|
||||
}
|
||||
}
|
||||
@@ -206,16 +196,16 @@ public class ColumnBox
|
||||
builder.addQuadAdj(
|
||||
EDhDirection.WEST,
|
||||
minX, minY, minZ,
|
||||
width, yHeight,
|
||||
blockWidth, yHeight,
|
||||
color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAdjVerticalQuad(
|
||||
builder, phantomArrayCheckout,
|
||||
builder, phantomArrayCheckout, clientLevelWrapper,
|
||||
adjCol, adjSameDetailLevel, caveCullingMaxY, EDhDirection.WEST,
|
||||
minX, minY, minZ, width, yHeight,
|
||||
minX, minY, minZ, blockWidth, yHeight,
|
||||
color, irisBlockMaterialId, blockLight);
|
||||
}
|
||||
}
|
||||
@@ -231,25 +221,25 @@ public class ColumnBox
|
||||
builder.addQuadAdj(
|
||||
EDhDirection.EAST,
|
||||
maxX, minY, minZ,
|
||||
width, yHeight,
|
||||
blockWidth, yHeight,
|
||||
color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAdjVerticalQuad(
|
||||
builder, phantomArrayCheckout,
|
||||
builder, phantomArrayCheckout, clientLevelWrapper,
|
||||
adjCol, adjSameDetailLevel, caveCullingMaxY, EDhDirection.EAST,
|
||||
maxX, minY, minZ, width, yHeight,
|
||||
maxX, minY, minZ, blockWidth, yHeight,
|
||||
color, irisBlockMaterialId, blockLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void makeAdjVerticalQuad(
|
||||
LodQuadBuilder builder, PhantomArrayListCheckout phantomArrayCheckout,
|
||||
LodQuadBuilder builder, PhantomArrayListCheckout phantomArrayCheckout, IClientLevelWrapper clientLevelWrapper,
|
||||
@NotNull ColumnRenderView adjColumnView, boolean adjacentIsSameDetailLevel, int caveCullingMaxY, EDhDirection direction,
|
||||
short x, short yMin, short z, short horizontalWidth, short ySize,
|
||||
short x, short yMin, short z, short horizontalBlockWidth, short ySize,
|
||||
int color, byte irisBlockMaterialId, byte blockLight)
|
||||
{
|
||||
// pooled arrays
|
||||
@@ -263,12 +253,12 @@ public class ColumnBox
|
||||
// no adjacent data //
|
||||
//==================//
|
||||
|
||||
color = ColorUtil.applyShade(color, MC_RENDER.getShade(direction));
|
||||
color = ColorUtil.applyShade(color, clientLevelWrapper.getShade(direction));
|
||||
|
||||
if (adjColumnView.size == 0
|
||||
|| RenderDataPointUtil.hasZeroHeight(adjColumnView.get(0)))
|
||||
{
|
||||
builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight);
|
||||
builder.addQuadAdj(direction, x, yMin, z, horizontalBlockWidth, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -278,7 +268,7 @@ public class ColumnBox
|
||||
// determine face visibility/light //
|
||||
//=================================//
|
||||
|
||||
boolean transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled;
|
||||
boolean transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get() == EDhApiTransparency.COMPLETE;
|
||||
boolean inputTransparent = ColorUtil.getAlpha(color) < 255 && transparencyEnabled;
|
||||
short yMax = (short) (yMin + ySize);
|
||||
|
||||
@@ -320,18 +310,34 @@ public class ColumnBox
|
||||
if (!adjTransparent)
|
||||
{
|
||||
// Adjacent is opaque
|
||||
boolean adjacentCoversThis =
|
||||
!adjacentIsSameDetailLevel
|
||||
&& RenderDataPointUtil.getYMax(adjPoint) >= caveCullingMaxY
|
||||
&&
|
||||
(
|
||||
(x == 0 && direction == EDhDirection.WEST)
|
||||
|| (z == 0 && direction == EDhDirection.NORTH)
|
||||
|| (x == 256 && direction == EDhDirection.EAST)
|
||||
|| (z == 256 && direction == EDhDirection.SOUTH)
|
||||
);
|
||||
|
||||
lightToApply = adjacentCoversThis ? adjSkyLight : SKYLIGHT_COVERED;
|
||||
// The following logic is done to provide a little bit of overdraw to
|
||||
// prevent holes when low detail LODs are replaced by higher-detail ones
|
||||
// when moving.
|
||||
// If not done higher quality LODs can cause holes due to not
|
||||
// covering the whole face like the lower detail LODs they replaced,
|
||||
// while still culling most LODs that are covered by other blocks.
|
||||
|
||||
boolean onBorder =
|
||||
(direction == EDhDirection.WEST && x == 0)
|
||||
|| (direction == EDhDirection.NORTH && z == 0)
|
||||
|| (direction == EDhDirection.EAST && x == ((horizontalBlockWidth) * (ColumnRenderSource.WIDTH)))
|
||||
|| (direction == EDhDirection.SOUTH && z == ((horizontalBlockWidth) * (ColumnRenderSource.WIDTH)));
|
||||
|
||||
boolean isLit =
|
||||
RenderDataPointUtil.getLightSky(adjPoint) != LodUtil.MIN_MC_LIGHT
|
||||
|| RenderDataPointUtil.getLightBlock(adjPoint) != LodUtil.MIN_MC_LIGHT;
|
||||
|
||||
// render the face if...
|
||||
boolean useAdjLighting =
|
||||
// we're on the border... (holes can only happen on LOD borders since faces inside an LOD will always be the same detail level)
|
||||
onBorder
|
||||
// ...this face has some sort of lighting... (0 light generally means the face is covered by other blocks)
|
||||
&& isLit
|
||||
// ...and is above the culling height
|
||||
&& RenderDataPointUtil.getYMax(adjPoint) >= caveCullingMaxY;
|
||||
|
||||
lightToApply = useAdjLighting ? adjSkyLight : SKYLIGHT_COVERED;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -374,7 +380,7 @@ public class ColumnBox
|
||||
long segment = segments.getLong(i);
|
||||
tryAddVerticalFaceWithSkyLightToBuilder(
|
||||
builder, direction,
|
||||
x, z, horizontalWidth,
|
||||
x, z, horizontalBlockWidth,
|
||||
color, irisBlockMaterialId, blockLight,
|
||||
YSegmentUtil.getSkyLight(segment), inputTransparent, YSegmentUtil.getEndY(segment), YSegmentUtil.getStartY(segment)
|
||||
);
|
||||
|
||||
+1
-4
@@ -1,7 +1,5 @@
|
||||
package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@@ -14,11 +12,10 @@ public class IndexBufferBuilder
|
||||
//==========//
|
||||
//region
|
||||
|
||||
/** Buffer should be freed by {@link MemoryUtil#memFree} */
|
||||
public static ByteBuffer createBuffer(int quadCount)
|
||||
{
|
||||
int indexCount = quadCount * 6; // 2 triangles per quad
|
||||
ByteBuffer buffer = MemoryUtil.memAlloc(indexCount * Integer.BYTES);
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(indexCount * Integer.BYTES);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
buildBufferInt(quadCount, buffer);
|
||||
|
||||
|
||||
+4
-40
@@ -32,7 +32,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRender
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
@@ -75,8 +74,6 @@ public class LodBufferContainer implements AutoCloseable
|
||||
this.minCornerBlockPos = minCornerBlockPos;
|
||||
this.vboOpaqueWrappers = new IVertexBufferWrapper[0];
|
||||
this.vboTransparentWrappers = new IVertexBufferWrapper[0];
|
||||
|
||||
this.uniformContainer.createUniformData(this);
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -91,7 +88,9 @@ public class LodBufferContainer implements AutoCloseable
|
||||
/** Should be run on a DH thread. */
|
||||
public static CompletableFuture<LodBufferContainer> tryMakeAndUploadBuffersAsync(
|
||||
long pos, IDhClientLevel clientLevel,
|
||||
LodQuadBuilder builder)
|
||||
ArrayList<ByteBuffer> opaqueBuffers,
|
||||
ArrayList<ByteBuffer> transparentBuffers
|
||||
)
|
||||
{
|
||||
// new upload needed
|
||||
CompletableFuture<LodBufferContainer> future = new CompletableFuture<>();
|
||||
@@ -109,10 +108,6 @@ public class LodBufferContainer implements AutoCloseable
|
||||
DhSectionPos.getMinCornerBlockZ(pos));
|
||||
LodBufferContainer bufferContainer = new LodBufferContainer(pos, minCornerBlockPos);
|
||||
|
||||
// create CPU vertex buffers
|
||||
ArrayList<ByteBuffer> opaqueBuffers = builder.makeOpaqueVertexBuffers();
|
||||
ArrayList<ByteBuffer> transparentBuffers = builder.makeTransparentVertexBuffers();
|
||||
|
||||
// update arrays to contain buffers
|
||||
bufferContainer.vboOpaqueWrappers = resizeWrapperArray(bufferContainer.vboOpaqueWrappers, opaqueBuffers.size());
|
||||
bufferContainer.vboTransparentWrappers = resizeWrapperArray(bufferContainer.vboTransparentWrappers, transparentBuffers.size());
|
||||
@@ -212,39 +207,8 @@ public class LodBufferContainer implements AutoCloseable
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// CPU Buffer cleanup //
|
||||
//====================//
|
||||
//region
|
||||
|
||||
future.whenComplete((LodBufferContainer lodBufferContainer, Throwable throwable) ->
|
||||
{
|
||||
// all the buffers must be manually freed to prevent memory leaks
|
||||
|
||||
tryFreeByteBufferList(opaqueBuffers);
|
||||
tryFreeByteBufferList(transparentBuffers);
|
||||
|
||||
tryFreeByteBufferList(opaqueIndexBuffers);
|
||||
tryFreeByteBufferList(transparentIndexBuffers);
|
||||
|
||||
});
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
return future;
|
||||
}
|
||||
private static void tryFreeByteBufferList(@Nullable ArrayList<ByteBuffer> list)
|
||||
{
|
||||
if (list != null)
|
||||
{
|
||||
for (ByteBuffer buffer : list)
|
||||
{
|
||||
MemoryUtil.memFree(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ArrayList<ByteBuffer> createIndexBuffers(ArrayList<ByteBuffer> vertexBuffers)
|
||||
@@ -297,7 +261,7 @@ public class LodBufferContainer implements AutoCloseable
|
||||
|
||||
if (vboWrappers[i] == null)
|
||||
{
|
||||
vboWrappers[i] = WRAPPER_FACTORY.createVboWrapper("distantHorizons:McLodRenderer");
|
||||
vboWrappers[i] = WRAPPER_FACTORY.createVboWrapper("distantHorizons:TerrainRenderer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+117
-29
@@ -20,6 +20,7 @@
|
||||
package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.*;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiGrassSideRendering;
|
||||
@@ -33,28 +34,19 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
/**
|
||||
* Used to create the quads before they are converted to render-able buffers. <br><br>
|
||||
*
|
||||
* Note: the magic number 6 you see throughout this method represents the number of sides on a cube.
|
||||
*/
|
||||
public class LodQuadBuilder
|
||||
public class LodQuadBuilder implements AutoCloseable
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final ArrayList<BufferQuad>[] opaqueQuads = (ArrayList<BufferQuad>[]) new ArrayList[6];
|
||||
@SuppressWarnings("unchecked")
|
||||
private final ArrayList<BufferQuad>[] transparentQuads = (ArrayList<BufferQuad>[]) new ArrayList[6];
|
||||
|
||||
private final boolean doTransparency;
|
||||
private final IClientLevelWrapper clientLevelWrapper;
|
||||
|
||||
private final EDhApiDebugRendering debugRenderingMode;
|
||||
private final EDhApiGrassSideRendering grassSideRenderingMode;
|
||||
/** ThreadLocal is the simplest way to allow each LOD loading thread to have their own builder */
|
||||
private static final ThreadLocal<LodQuadBuilder> THREAD_LOCAL = ThreadLocal.withInitial(LodQuadBuilder::new);
|
||||
|
||||
/** the number of bytes for a single vertex */
|
||||
public static final int BYTES_PER_VERTEX = 16;
|
||||
@@ -111,6 +103,26 @@ public class LodQuadBuilder
|
||||
};
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final ArrayList<BufferQuad>[] opaqueQuads = (ArrayList<BufferQuad>[]) new ArrayList[6];
|
||||
@SuppressWarnings("unchecked")
|
||||
private final ArrayList<BufferQuad>[] transparentQuads = (ArrayList<BufferQuad>[]) new ArrayList[6];
|
||||
|
||||
/**
|
||||
* Caching the BufferQuad objects reduces overhead slightly. <br>
|
||||
* Caching is handled per builder (vs globally in {@link BufferQuad} itself)
|
||||
* to prevent concurrency overhead.
|
||||
*/
|
||||
private final ArrayList<BufferQuad> bufferQuadCacheList = new ArrayList<>();
|
||||
|
||||
private boolean doTransparency;
|
||||
private IClientLevelWrapper clientLevelWrapper;
|
||||
|
||||
private EDhApiDebugRendering debugRenderingMode;
|
||||
private EDhApiGrassSideRendering grassSideRenderingMode;
|
||||
|
||||
private int premergeCount = 0;
|
||||
|
||||
|
||||
@@ -120,20 +132,31 @@ public class LodQuadBuilder
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public LodQuadBuilder(boolean doTransparency, IClientLevelWrapper clientLevelWrapper)
|
||||
private LodQuadBuilder()
|
||||
{
|
||||
this.doTransparency = doTransparency;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
this.opaqueQuads[i] = new ArrayList<>();
|
||||
this.transparentQuads[i] = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public static LodQuadBuilder getBuilder(boolean doTransparency, IClientLevelWrapper clientLevelWrapper)
|
||||
{
|
||||
LodQuadBuilder builder = THREAD_LOCAL.get();
|
||||
builder.set(doTransparency, clientLevelWrapper);
|
||||
return builder;
|
||||
}
|
||||
private void set(boolean doTransparency, IClientLevelWrapper clientLevelWrapper)
|
||||
{
|
||||
this.doTransparency = doTransparency;
|
||||
|
||||
this.clientLevelWrapper = clientLevelWrapper;
|
||||
|
||||
this.debugRenderingMode = Config.Client.Advanced.Debugging.debugRenderingColors.get();
|
||||
this.grassSideRenderingMode = Config.Client.Advanced.Graphics.Quality.grassSideRendering.get();
|
||||
|
||||
this.premergeCount = 0;
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -143,7 +166,7 @@ public class LodQuadBuilder
|
||||
//===========//
|
||||
// add quads //
|
||||
//===========//
|
||||
///region
|
||||
//region
|
||||
|
||||
public void addQuadAdj(
|
||||
EDhDirection dir,
|
||||
@@ -167,7 +190,8 @@ public class LodQuadBuilder
|
||||
quadList = this.opaqueQuads[dir.ordinal()];
|
||||
}
|
||||
|
||||
BufferQuad quad = new BufferQuad(x, y, z, width, height, color, irisBlockMaterialId, skyLight, blockLight, dir);
|
||||
BufferQuad quad = this.getOrCreateBufferQuad();
|
||||
quad.set(x, y, z, width, height, color, irisBlockMaterialId, skyLight, blockLight, dir);
|
||||
if (!quadList.isEmpty()
|
||||
&& (
|
||||
quadList.get(quadList.size() - 1).tryMerge(quad, BufferMergeDirectionEnum.EastWest)
|
||||
@@ -182,35 +206,37 @@ public class LodQuadBuilder
|
||||
}
|
||||
|
||||
// XZ
|
||||
public void addQuadUp(short minX, short maxY, short minZ, short width, int color, byte irisBlockMaterialId, byte skylight, byte blocklight)
|
||||
public void addQuadUp(short minX, short maxY, short minZ, short blockWidth, int color, byte irisBlockMaterialId, byte skylight, byte blocklight)
|
||||
{
|
||||
boolean isTransparent = (this.doTransparency && ColorUtil.getAlpha(color) < 255);
|
||||
ArrayList<BufferQuad> quadList = isTransparent
|
||||
? this.transparentQuads[EDhDirection.UP.ordinal()]
|
||||
: this.opaqueQuads[EDhDirection.UP.ordinal()];
|
||||
|
||||
BufferQuad quad = new BufferQuad(minX, maxY, minZ, width, width, color, irisBlockMaterialId, skylight, blocklight, EDhDirection.UP);
|
||||
BufferQuad quad = this.getOrCreateBufferQuad();
|
||||
quad.set(minX, maxY, minZ, blockWidth, blockWidth, color, irisBlockMaterialId, skylight, blocklight, EDhDirection.UP);
|
||||
quadList.add(quad);
|
||||
}
|
||||
|
||||
public void addQuadDown(short x, short y, short z, short width, int color, byte irisBlockMaterialId, byte skylight, byte blocklight)
|
||||
public void addQuadDown(short x, short y, short z, short blockWidth, int color, byte irisBlockMaterialId, byte skylight, byte blocklight)
|
||||
{
|
||||
ArrayList<BufferQuad> quadArray = (this.doTransparency && ColorUtil.getAlpha(color) < 255)
|
||||
? this.transparentQuads[EDhDirection.DOWN.ordinal()]
|
||||
: this.opaqueQuads[EDhDirection.DOWN.ordinal()];
|
||||
|
||||
BufferQuad quad = new BufferQuad(x, y, z, width, width, color, irisBlockMaterialId, skylight, blocklight, EDhDirection.DOWN);
|
||||
BufferQuad quad = this.getOrCreateBufferQuad();
|
||||
quad.set(x, y, z, blockWidth, blockWidth, color, irisBlockMaterialId, skylight, blocklight, EDhDirection.DOWN);
|
||||
quadArray.add(quad);
|
||||
}
|
||||
|
||||
///endregion
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// data finalizing //
|
||||
//=================//
|
||||
///region
|
||||
//region
|
||||
|
||||
/** Uses Greedy meshing to merge this builder's Quads. */
|
||||
public void mergeQuads()
|
||||
@@ -279,14 +305,14 @@ public class LodQuadBuilder
|
||||
return mergeCount;
|
||||
}
|
||||
|
||||
///endregion
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// buffer setup //
|
||||
//==============//
|
||||
///region
|
||||
//region
|
||||
|
||||
public ArrayList<ByteBuffer> makeOpaqueVertexBuffers() { return this.makeVertexBuffers(this.opaqueQuads); }
|
||||
public ArrayList<ByteBuffer> makeTransparentVertexBuffers() { return this.makeVertexBuffers(this.transparentQuads); }
|
||||
@@ -311,7 +337,8 @@ public class LodQuadBuilder
|
||||
if (buffer == null
|
||||
|| buffer.remaining() < BYTES_PER_QUAD)
|
||||
{
|
||||
buffer = MemoryUtil.memAlloc(getMaxBufferByteSize());
|
||||
buffer = ByteBuffer.allocateDirect(getMaxBufferByteSize());
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
byteBufferList.add(buffer);
|
||||
}
|
||||
|
||||
@@ -394,7 +421,7 @@ public class LodQuadBuilder
|
||||
// for horizontal and bottom faces of grass blocks, use the dirt color to
|
||||
// prevent green cliff walls
|
||||
color = this.clientLevelWrapper.getDirtBlockColor();
|
||||
color = ColorUtil.applyShade(color, MC_RENDER.getShade(quad.direction));
|
||||
color = ColorUtil.applyShade(color, this.clientLevelWrapper.getShade(quad.direction));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -451,14 +478,14 @@ public class LodQuadBuilder
|
||||
bb.putShort((short) 0); // padding to make sure the vertex format as a whole is a multiple of 4
|
||||
}
|
||||
|
||||
///endregion
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// getters //
|
||||
//=========//
|
||||
///region
|
||||
//region
|
||||
|
||||
public int getCurrentOpaqueQuadsCount()
|
||||
{
|
||||
@@ -513,7 +540,68 @@ public class LodQuadBuilder
|
||||
return fullSizedBuffer;
|
||||
}
|
||||
|
||||
///endregion
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// buffer quad pooling //
|
||||
//=====================//
|
||||
//region
|
||||
|
||||
private BufferQuad getOrCreateBufferQuad()
|
||||
{
|
||||
// start from the back of the list so we don't have
|
||||
// to move the array around
|
||||
int index = bufferQuadCacheList.size() - 1;
|
||||
if (index < 0)
|
||||
{
|
||||
// cache empty, create a new object
|
||||
return new BufferQuad();
|
||||
}
|
||||
|
||||
BufferQuad quad = bufferQuadCacheList.remove(index);
|
||||
if (quad != null) // shouldn't happen, but just in case
|
||||
{
|
||||
return quad;
|
||||
}
|
||||
|
||||
return new BufferQuad();
|
||||
}
|
||||
|
||||
private static void returnQuadsToCache(ArrayList<BufferQuad> quadCache, ArrayList<BufferQuad>[] quadsToReturn)
|
||||
{
|
||||
for (int i = 0; i < quadsToReturn.length; i++)
|
||||
{
|
||||
// manual add and loop to reduce GC pressure due to addAll() doing unnecessary
|
||||
// array copies
|
||||
for (int j = 0; j < quadsToReturn[i].size(); j++)
|
||||
{
|
||||
quadCache.add(quadsToReturn[i].get(j));
|
||||
}
|
||||
|
||||
quadsToReturn[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
// can be used/closed multiple times
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
returnQuadsToCache(this.bufferQuadCacheList, this.opaqueQuads);
|
||||
returnQuadsToCache(this.bufferQuadCacheList, this.transparentQuads);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -193,8 +193,8 @@ public class FullDataToRenderDataTransformer
|
||||
// config values //
|
||||
//===============//
|
||||
|
||||
boolean ignoreNonCollidingBlocks = (Config.Client.Advanced.Graphics.Quality.blocksToIgnore.get() == EDhApiBlocksToAvoid.NON_COLLIDING);
|
||||
boolean colorBelowWithAvoidedBlocks = Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks.get();
|
||||
boolean ignoreNonCollidingBlocks = (Config.Client.Advanced.Graphics.Culling.blocksToIgnore.get() == EDhApiBlocksToAvoid.NON_COLLIDING);
|
||||
boolean colorBelowWithAvoidedBlocks = Config.Client.Advanced.Graphics.Culling.tintWithAvoidedBlocks.get();
|
||||
|
||||
final ObjectOpenHashSet<IBlockStateWrapper> blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper);
|
||||
final ObjectOpenHashSet<IBlockStateWrapper> caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.enums;
|
||||
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3i;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3i;
|
||||
|
||||
/**
|
||||
* Up <Br>
|
||||
@@ -32,17 +32,17 @@ import com.seibel.distanthorizons.core.util.math.Vec3i;
|
||||
public enum EDhDirection
|
||||
{
|
||||
/** negative Y */
|
||||
DOWN("down", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.Y, new Vec3i(0, -1, 0), -1),
|
||||
DOWN("down", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.Y, new DhVec3i(0, -1, 0), -1),
|
||||
/** positive Y */
|
||||
UP("up", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.Y, new Vec3i(0, 1, 0), -1),
|
||||
UP("up", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.Y, new DhVec3i(0, 1, 0), -1),
|
||||
/** negative Z */
|
||||
NORTH("north", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.Z, new Vec3i(0, 0, -1), 0),
|
||||
NORTH("north", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.Z, new DhVec3i(0, 0, -1), 0),
|
||||
/** positive Z */
|
||||
SOUTH("south", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.Z, new Vec3i(0, 0, 1), 1),
|
||||
SOUTH("south", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.Z, new DhVec3i(0, 0, 1), 1),
|
||||
/** negative X */
|
||||
WEST("west", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.X, new Vec3i(-1, 0, 0), 2),
|
||||
WEST("west", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.X, new DhVec3i(-1, 0, 0), 2),
|
||||
/** positive X */
|
||||
EAST("east", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.X, new Vec3i(1, 0, 0), 3);
|
||||
EAST("east", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.X, new DhVec3i(1, 0, 0), 3);
|
||||
|
||||
|
||||
/** Up, Down, West, East, North, South */
|
||||
@@ -68,7 +68,7 @@ public enum EDhDirection
|
||||
public final String name;
|
||||
public final EDhDirection.Axis axis;
|
||||
public final EDhDirection.AxisDirection axisDirection;
|
||||
public final Vec3i normal;
|
||||
public final DhVec3i normal;
|
||||
/** -1 if not a {@link EDhDirection#CARDINAL_COMPASS} direction */
|
||||
public final int compassIndex;
|
||||
|
||||
@@ -78,7 +78,7 @@ public enum EDhDirection
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
EDhDirection(String name, EDhDirection.AxisDirection axisDirection, EDhDirection.Axis axis, Vec3i normal, int compassIndex)
|
||||
EDhDirection(String name, EDhDirection.AxisDirection axisDirection, EDhDirection.Axis axis, DhVec3i normal, int compassIndex)
|
||||
{
|
||||
this.name = name;
|
||||
this.axis = axis;
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ public abstract class AbstractLodRequestState
|
||||
remainingChunkCount += this.retrievalQueue.getQueuedChunkCount();
|
||||
String remainingChunkCountStr = F3Screen.NUMBER_FORMAT.format(remainingChunkCount);
|
||||
|
||||
String message = "DH is generating chunks. ";
|
||||
String message = "DH is "+this.retrievalQueue.getRetrievalTypeName()+". ";
|
||||
if (this.dhLevel.getClass() == DhServerLevel.class)
|
||||
{
|
||||
// server levels can have multiple world generators running at once,
|
||||
|
||||
+6
@@ -65,6 +65,12 @@ public interface IFullDataSourceRetrievalQueue extends Closeable
|
||||
*/
|
||||
byte highestDataDetail();
|
||||
|
||||
/**
|
||||
* Returns a value like "downloading" or "generating" depending on how the LODs are being retrieved.
|
||||
* Used to make the progress message easier to understand.
|
||||
*/
|
||||
String getRetrievalTypeName();
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
-11
@@ -123,17 +123,6 @@ public class LodRequestModule implements Closeable
|
||||
// if the world is read only don't generate anything
|
||||
shouldDoWorldGen &= !DhApiWorldProxy.INSTANCE.tryGetReadOnly();
|
||||
|
||||
// don't generate chunks for client levels that aren't being rendered
|
||||
// (this can happen when moving between dimensions)
|
||||
if (this.level instanceof IDhClientLevel)
|
||||
{
|
||||
boolean isRendering = ((IDhClientLevel) this.level).isRendering();
|
||||
if (!isRendering)
|
||||
{
|
||||
shouldDoWorldGen = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean isWorldGenRunning = this.isWorldGenRunning();
|
||||
|
||||
+3
@@ -51,6 +51,9 @@ public class RemoteWorldRetrievalQueue extends AbstractFullDataNetworkRequestQue
|
||||
@Override
|
||||
public byte highestDataDetail() { return LodUtil.BLOCK_DETAIL_LEVEL; }
|
||||
|
||||
@Override
|
||||
public String getRetrievalTypeName() { return "downloading LODs"; }
|
||||
|
||||
@Override
|
||||
public CompletableFuture<DataSourceRetrievalResult> submitRetrievalTask(long sectionPos, byte requiredDataDetail)
|
||||
{
|
||||
|
||||
+2
@@ -593,6 +593,8 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
||||
@Override public byte lowestDataDetail() { return this.lowestDataDetail; }
|
||||
@Override public byte highestDataDetail() { return this.highestDataDetail; }
|
||||
|
||||
@Override public String getRetrievalTypeName() { return "generating chunks"; }
|
||||
|
||||
@Override public int getEstimatedRemainingTaskCount() { return this.estimatedRemainingTaskCount; }
|
||||
@Override public void setEstimatedRemainingTaskCount(int newEstimate) { this.estimatedRemainingTaskCount = newEstimate; }
|
||||
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.jar;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A fork of iris' dark mode detector (https://github.com/IrisShaders/Iris-Installer/blob/master/src/main/java/net/hypercubemc/iris_installer/DarkModeDetector.java)
|
||||
* Which is a fork of HanSolo's dark mode detector (https://gist.github.com/HanSolo/7cf10b86efff8ca2845bf5ec2dd0fe1d)
|
||||
*
|
||||
* This fork has better support for Linux
|
||||
*
|
||||
* @author HanSolo
|
||||
* @author IMS
|
||||
* @author coolGi
|
||||
*/
|
||||
public class DarkModeDetector
|
||||
{
|
||||
private static final String REGQUERY_UTIL = "reg query ";
|
||||
private static final String REGDWORD_TOKEN = "REG_DWORD";
|
||||
private static final String DARK_THEME_CMD = REGQUERY_UTIL + "\"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\"" + " /v AppsUseLightTheme";
|
||||
|
||||
public static boolean isDarkMode()
|
||||
{
|
||||
switch (EPlatform.get())
|
||||
{
|
||||
case WINDOWS:
|
||||
return isWindowsDarkMode();
|
||||
case MACOS:
|
||||
return isMacOsDarkMode();
|
||||
case LINUX:
|
||||
// Most Unix(-like) distros also use a lot of the same things as Linux (like desktop environments and window managers)
|
||||
case BSD:
|
||||
case UNIX:
|
||||
return checkLinuxDark();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Needs checking as I dont use Mac
|
||||
public static boolean isMacOsDarkMode()
|
||||
{
|
||||
boolean isDarkMode = false;
|
||||
String line = query("defaults read -g AppleInterfaceStyle");
|
||||
if (line.equals("Dark"))
|
||||
{
|
||||
isDarkMode = true;
|
||||
}
|
||||
return isDarkMode;
|
||||
}
|
||||
|
||||
// Needs checking as I don't use Windows
|
||||
public static boolean isWindowsDarkMode()
|
||||
{
|
||||
try
|
||||
{
|
||||
String result = query(DARK_THEME_CMD);
|
||||
int p = result.indexOf(REGDWORD_TOKEN);
|
||||
|
||||
if (p == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1 == Light Mode, 0 == Dark Mode
|
||||
String temp = result.substring(p + REGDWORD_TOKEN.length()).trim();
|
||||
return ((Integer.parseInt(temp.substring("0x".length()), 16))) == 0;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// On Linux there are 2 popular formats for theming
|
||||
// They are qt and gtk. We check the desktop environment and use that to pick which one to use (if none work then use GTK)
|
||||
public static boolean checkLinuxDark()
|
||||
{
|
||||
// Checks "/usr/bin" as "echo $XDG_CURRENT_DESKTOP" dosnt work in java and dosnt detect window managers
|
||||
File de_location = new File("/usr/bin");
|
||||
// System.out.println(de_location.list());
|
||||
for (String de : de_location.list())
|
||||
{
|
||||
// System.out.println(de);
|
||||
if (de.contains("gnome-session")) // Gnome uses GTK
|
||||
{
|
||||
return GTKChecker();
|
||||
}
|
||||
if (de.contains("plasma_session")) // KDE plasma uses QT
|
||||
{
|
||||
return QTChecker();
|
||||
}
|
||||
}
|
||||
return GTKChecker(); // GTK works best with non plasma desktops (desktops includes window managers)
|
||||
}
|
||||
|
||||
public static boolean GTKChecker()
|
||||
{
|
||||
// Checks if the return to "gsettings get org.gnome.desktop.interface color-scheme" in terminal is 'prefer-dark' or contains the word dark in it
|
||||
final Pattern darkThemeNamePattern = Pattern.compile(".*dark.*", Pattern.CASE_INSENSITIVE);
|
||||
return darkThemeNamePattern.matcher(query("gsettings get org.gnome.desktop.interface color-scheme")).matches();
|
||||
}
|
||||
|
||||
public static boolean QTChecker()
|
||||
{
|
||||
// Get the contents of "~/.config/Trolltech.conf" then check "KWinPalette\activeBackground"
|
||||
// With that you grayscale the rgb and check if it is over/under 128
|
||||
|
||||
// If there is a better way of doing this then please let me know
|
||||
// This seems like the best way as qt dosnt have a dark/light preference and just stores pure color values
|
||||
|
||||
try
|
||||
{
|
||||
File themeFile = new File(System.getProperty("user.home") + "/.config/Trolltech.conf");
|
||||
|
||||
BufferedReader reader = new BufferedReader(new FileReader(themeFile));
|
||||
String themeLine = reader.readLine();
|
||||
while (themeLine != null)
|
||||
{ // Go through each line till you find "KWinPalette\activeBackground"
|
||||
if (themeLine.contains("KWinPalette\\activeBackground"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
themeLine = reader.readLine();
|
||||
}
|
||||
reader.close();
|
||||
|
||||
// Get where the # is then read the hex numbers after it
|
||||
short index = (short) themeLine.indexOf("#");
|
||||
short r = (short) Integer.parseInt("" + themeLine.charAt(index + 1) + themeLine.charAt(index + 2), 16);
|
||||
short g = (short) Integer.parseInt("" + themeLine.charAt(index + 3) + themeLine.charAt(index + 4), 16);
|
||||
short b = (short) Integer.parseInt("" + themeLine.charAt(index + 5) + themeLine.charAt(index + 6), 16);
|
||||
if ((r + g + b) / 2 >= 128)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace(); return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Runs a command trough command line */
|
||||
private static String query(String cmd)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process process = Runtime.getRuntime().exec(cmd);
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())))
|
||||
{
|
||||
String actualReadLine;
|
||||
while ((actualReadLine = reader.readLine()) != null)
|
||||
{
|
||||
if (stringBuilder.length() != 0)
|
||||
{
|
||||
stringBuilder.append('\n');
|
||||
}
|
||||
stringBuilder.append(actualReadLine);
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
System.out.println("Exception caught while querying the OS:");
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,13 +57,13 @@ public class SelfUpdater
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
private static final IVersionConstants VERSION_CONSTANTS = SingletonInjector.INSTANCE.get(IVersionConstants.class);
|
||||
|
||||
private static final String MC_VERSION = VERSION_CONSTANTS.getMinecraftVersion();
|
||||
|
||||
/** As we cannot delete(or replace) the jar while the mod is running, we just have this to delete it once the game closes */
|
||||
public static boolean deleteOldJarOnJvmShutdown = false;
|
||||
|
||||
private static String currentJarSha = "";
|
||||
private static String mcVersion = SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion();
|
||||
|
||||
public static File newFileLocation;
|
||||
|
||||
|
||||
@@ -75,29 +75,33 @@ public class SelfUpdater
|
||||
*/
|
||||
public static boolean onStart()
|
||||
{
|
||||
LOGGER.info("Checking for Distant Horizons update");
|
||||
|
||||
try
|
||||
if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get())
|
||||
{
|
||||
currentJarSha = JarUtils.getFileChecksum(MessageDigest.getInstance("SHA"), JarUtils.jarFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unable to get existing jar checksum, error: ["+e.getMessage()+"].", e);
|
||||
LOGGER.info("Distant Horizons auto update disabled.");
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean returnValue = false;
|
||||
|
||||
try
|
||||
{
|
||||
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
|
||||
returnValue = (updateBranch == EDhApiUpdateBranch.STABLE) ? onStableStart() : onNightlyStart();
|
||||
|
||||
LOGGER.info("Checking for Distant Horizons ["+updateBranch+"] update for MC ["+MC_VERSION+"]...");
|
||||
|
||||
if (updateBranch == EDhApiUpdateBranch.STABLE)
|
||||
{
|
||||
return onStableStart();
|
||||
}
|
||||
else
|
||||
{
|
||||
return onNightlyStart();
|
||||
}
|
||||
}
|
||||
catch (Exception e) // Shouldn't be needed, but just in case
|
||||
{
|
||||
LOGGER.warn("Unexpected updater startup error: ["+e.getMessage()+"].", e);
|
||||
return false;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
private static boolean onStableStart()
|
||||
{
|
||||
@@ -108,15 +112,19 @@ public class SelfUpdater
|
||||
LOGGER.warn("Unable to find any nightly build pipelines, auto update will be unavailable.");
|
||||
return false;
|
||||
}
|
||||
if (!ModrinthGetter.mcVersions.contains(mcVersion))
|
||||
if (!ModrinthGetter.mcVersions.contains(MC_VERSION))
|
||||
{
|
||||
LOGGER.warn("Minecraft version ["+ mcVersion +"] is not findable on Modrinth, only findable versions are ["+ StringUtil.join(", ", ModrinthGetter.mcVersions) +"]");
|
||||
LOGGER.warn("Minecraft version ["+ MC_VERSION +"] is not findable on Modrinth, only findable versions are ["+ StringUtil.join(", ", ModrinthGetter.mcVersions) +"]");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
newFileLocation = JarUtils.jarFile.getParentFile().toPath().resolve("update").resolve(ModInfo.NAME + "-" + ModrinthGetter.getLatestNameForVersion(mcVersion) + "-" + mcVersion + ".jar").toFile();
|
||||
newFileLocation = JarUtils.jarFile
|
||||
.getParentFile().toPath()
|
||||
.resolve("update")
|
||||
.resolve(ModInfo.NAME + "-" + ModrinthGetter.getLatestNameForVersion(MC_VERSION) + "-" + MC_VERSION + ".jar")
|
||||
.toFile();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -124,8 +132,19 @@ public class SelfUpdater
|
||||
return false;
|
||||
}
|
||||
|
||||
String currentJarSha;
|
||||
try
|
||||
{
|
||||
currentJarSha = JarUtils.getFileChecksum(MessageDigest.getInstance("SHA"), JarUtils.jarFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unable to get existing jar checksum, error: ["+e.getMessage()+"].", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the sha's of both our stuff
|
||||
if (currentJarSha.equals(ModrinthGetter.getLatestShaForVersion(mcVersion)))
|
||||
if (currentJarSha.equals(ModrinthGetter.getLatestShaForVersion(MC_VERSION)))
|
||||
{
|
||||
LOGGER.info("Distant Horizons already up to date.");
|
||||
return false;
|
||||
@@ -137,21 +156,23 @@ public class SelfUpdater
|
||||
}
|
||||
|
||||
|
||||
LOGGER.info("New version (" + ModrinthGetter.getLatestNameForVersion(mcVersion) + ") of Distant Horizons is available");
|
||||
LOGGER.info("New version (" + ModrinthGetter.getLatestNameForVersion(MC_VERSION) + ") of Distant Horizons is available");
|
||||
if (Config.Client.Advanced.AutoUpdater.enableSilentUpdates.get())
|
||||
{
|
||||
// Auto-update mod
|
||||
updateMod(mcVersion, newFileLocation);
|
||||
updateMod(MC_VERSION, newFileLocation);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.info("Download link: " + ModrinthGetter.getLatestDownloadForVersion(mcVersion));
|
||||
LOGGER.info("Download link: " + ModrinthGetter.getLatestDownloadForVersion(MC_VERSION));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private static boolean onNightlyStart()
|
||||
{
|
||||
LOGGER.info("Checking for Distant Horizons Nightly update...");
|
||||
|
||||
if (GitlabGetter.INSTANCE.projectPipelines.size() == 0)
|
||||
{
|
||||
LOGGER.info("Unable to find any nightly build pipelines, auto update will be unavailable.");
|
||||
@@ -171,9 +192,9 @@ public class SelfUpdater
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GitlabGetter.INSTANCE.getDownloads(pipeline.get("id")).containsKey(mcVersion))
|
||||
if (!GitlabGetter.INSTANCE.getDownloads(pipeline.get("id")).containsKey(MC_VERSION))
|
||||
{
|
||||
LOGGER.warn("Minecraft version ["+ mcVersion +"] is not findable on Gitlab, findable versions are ["+ StringUtil.join(", ", GitlabGetter.INSTANCE.getDownloads(pipeline.get("id")).keySet().toArray()) +"].");
|
||||
LOGGER.warn("Minecraft version ["+ MC_VERSION +"] is not findable on Gitlab, findable versions are ["+ StringUtil.join(", ", GitlabGetter.INSTANCE.getDownloads(pipeline.get("id")).keySet().toArray()) +"].");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -200,12 +221,12 @@ public class SelfUpdater
|
||||
if (Config.Client.Advanced.AutoUpdater.enableSilentUpdates.get())
|
||||
{
|
||||
// Auto-update mod
|
||||
updateMod(mcVersion, newFileLocation);
|
||||
updateMod(MC_VERSION, newFileLocation);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.info("Download link: " + GitlabGetter.getLatestForVersion(mcVersion));
|
||||
LOGGER.info("Download link: " + GitlabGetter.getLatestForVersion(MC_VERSION));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+9
-28
@@ -9,7 +9,6 @@ import com.seibel.distanthorizons.core.multiplayer.server.FullDataSourceRequestH
|
||||
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerStateManager;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.RequestOutOfRangeException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.RequestRejectedException;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.SectionRequiresSplittingException;
|
||||
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.AbstractTrackableMessage;
|
||||
@@ -22,14 +21,14 @@ import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.WorldGenUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
@@ -72,9 +71,11 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
||||
boolean runRepoReliantSetup
|
||||
) throws SQLException, IOException
|
||||
{
|
||||
if (saveStructure.getSaveFolder(serverLevelWrapper).mkdirs())
|
||||
File saveFolder = saveStructure.getSaveFolder(serverLevelWrapper);
|
||||
saveFolder.mkdirs();
|
||||
if (!saveFolder.exists())
|
||||
{
|
||||
LOGGER.warn("unable to create data folder.");
|
||||
throw new IOException("unable to create save folder at ["+saveFolder.getPath()+"]. If you're on Windows you may need to enable long file paths.");
|
||||
}
|
||||
this.serverLevelWrapper = serverLevelWrapper;
|
||||
this.serverside = new ServerLevelModule(this, saveStructure);
|
||||
@@ -114,7 +115,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
||||
this.worldGenPlayerCenteringQueue.add(firstPlayer);
|
||||
this.worldGenPlayerCenteringQueue.remove(firstPlayer);
|
||||
|
||||
Vec3d position = firstPlayer.getPosition();
|
||||
DhVec3d position = firstPlayer.getPosition();
|
||||
return new DhBlockPos2D((int) position.x, (int) position.z);
|
||||
}
|
||||
|
||||
@@ -133,7 +134,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3d playerPosition = serverPlayerState.getServerPlayer().getPosition();
|
||||
DhVec3d playerPosition = serverPlayerState.getServerPlayer().getPosition();
|
||||
int distanceFromPlayer = DhSectionPos.getChebyshevSignedBlockDistance(message.sectionPos, new DhBlockPos2D((int) playerPosition.x, (int) playerPosition.z)) / 16;
|
||||
|
||||
ServerPlayerState.RateLimiterSet rateLimiterSet = serverPlayerState.getRateLimiterSet(this);
|
||||
@@ -200,26 +201,6 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
||||
|
||||
LodUtil.assertTrue(message.getSession().serverPlayer != null);
|
||||
|
||||
// Check if the player is in this dimension,
|
||||
// since handling multiple dimensions isn't allowed
|
||||
if (message.getSession().serverPlayer.getLevel() != this.getLevelWrapper())
|
||||
{
|
||||
// If the message can be replied to - reply with an error, otherwise just ignore
|
||||
if (message instanceof AbstractTrackableMessage)
|
||||
{
|
||||
((AbstractTrackableMessage) message).sendResponse(
|
||||
new RequestRejectedException(
|
||||
"Generation not allowed. " +
|
||||
"Requested dimension: ["+((ILevelRelatedMessage) message).getLevelName()+"], " +
|
||||
"player dimension: [" + message.getSession().serverPlayer.getLevel().getDhIdentifier() + "], " +
|
||||
"handler dimension: [" + this.getLevelWrapper().getDhIdentifier() + "]"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -270,7 +251,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
||||
continue;
|
||||
}
|
||||
|
||||
Vec3d playerPosition = serverPlayerState.getServerPlayer().getPosition();
|
||||
DhVec3d playerPosition = serverPlayerState.getServerPlayer().getPosition();
|
||||
int distanceFromPlayer = DhSectionPos.getChebyshevSignedBlockDistance(data.getPos(), new DhBlockPos2D((int) playerPosition.x, (int) playerPosition.z)) / 16;
|
||||
if (distanceFromPlayer <= serverPlayerState.sessionConfig.getMaxUpdateDistanceRadius())
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.render.QuadTree.LodQuadTree;
|
||||
import com.seibel.distanthorizons.core.render.RenderBufferHandler;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
@@ -109,10 +109,21 @@ public class ClientLevelModule implements Closeable, IDataSourceUpdateListenerFu
|
||||
this.ClientRenderStateRef.set(clientRenderState);
|
||||
}
|
||||
|
||||
// use camera position instead of player pos so free cam mods work better
|
||||
Vec3d cameraDoublePos = MC_RENDER.getCameraExactPosition();
|
||||
DhBlockPos2D cameraBlockPos = new DhBlockPos2D((int)cameraDoublePos.x, (int)cameraDoublePos.z);
|
||||
clientRenderState.quadtree.tryTick(cameraBlockPos);
|
||||
|
||||
DhBlockPos2D quadTreeTickBlockPos;
|
||||
if (Config.Client.Advanced.Graphics.Quality.useCameraPositionForQualityDropOff.get())
|
||||
{
|
||||
// use camera position allow free cam mods work better
|
||||
DhVec3d cameraDoublePos = MC_RENDER.getCameraExactPosition();
|
||||
quadTreeTickBlockPos = new DhBlockPos2D((int)cameraDoublePos.x, (int)cameraDoublePos.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
// player position allows multi-cam mods to work better
|
||||
quadTreeTickBlockPos = new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos());
|
||||
}
|
||||
|
||||
clientRenderState.quadtree.tryTick(quadTreeTickBlockPos);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +137,7 @@ public class ClientLevelModule implements Closeable, IDataSourceUpdateListenerFu
|
||||
ClientRenderState clientRenderState = new ClientRenderState(this.clientLevel, this.clientLevel.getFullDataProvider());
|
||||
if (!this.ClientRenderStateRef.compareAndSet(null, clientRenderState))
|
||||
{
|
||||
LOGGER.warn("Renderer already started for ["+this+"].");
|
||||
LOGGER.warn("Renderer already started for ["+this.clientLevel.getClientLevelWrapper()+"].");
|
||||
clientRenderState.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package com.seibel.distanthorizons.core.level;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.eventHandlers.IgnoredDimensionCsvHandler;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
@@ -114,16 +115,19 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||
File saveFolder = saveStructure.getSaveFolder(clientLevelWrapper);
|
||||
File pre23Folder = saveStructure.getPre23SaveFolder(clientLevelWrapper);
|
||||
|
||||
saveFolder.mkdirs();
|
||||
|
||||
if (pre23Folder.exists())
|
||||
{
|
||||
if (!pre23Folder.renameTo(saveFolder))
|
||||
{
|
||||
throw new RuntimeException("Could not move old save data folder: " + pre23Folder.getAbsolutePath() + " to " + saveFolder.getAbsolutePath());
|
||||
throw new RuntimeException("Could not move old save data folder: [" + pre23Folder.getAbsolutePath() + "] to [" + saveFolder.getAbsolutePath() + "].");
|
||||
}
|
||||
}
|
||||
else if (saveStructure.getSaveFolder(clientLevelWrapper).mkdirs())
|
||||
|
||||
if (!saveFolder.exists())
|
||||
{
|
||||
LOGGER.warn("unable to create data folder.");
|
||||
throw new IOException("unable to create save folder at ["+saveFolder.getPath()+"]. If you're on Windows you may need to enable long file paths.");
|
||||
}
|
||||
|
||||
this.levelWrapper = clientLevelWrapper;
|
||||
@@ -167,15 +171,17 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||
}
|
||||
|
||||
|
||||
// Check this before decoding data to prevent errors if multiple client levels
|
||||
// are receiving data at once (Immersive Portals compatibility).
|
||||
boolean isSameLevel = message.isSameLevelAs(this.levelWrapper);
|
||||
//NETWORK_LOGGER.debug("Buffer ["+message.payload.dtoBufferId+"] isSameLevel: ["+isSameLevel+"]");
|
||||
if (!isSameLevel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try (FullDataSourceV2DTO dataSourceDto = this.networkState.fullDataPayloadReceiver.decodeDataSource(message.payload))
|
||||
{
|
||||
boolean isSameLevel = message.isSameLevelAs(this.levelWrapper);
|
||||
NETWORK_LOGGER.debug("Buffer ["+message.payload.dtoBufferId+"] isSameLevel: ["+isSameLevel+"]");
|
||||
if (!isSameLevel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Executor executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||
if (executor != null)
|
||||
@@ -219,6 +225,15 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||
{
|
||||
try
|
||||
{
|
||||
// only tick the level the player is currently in
|
||||
// (done to prevent ticking LodQuadTree's for levels that aren't rendering)
|
||||
IClientLevelWrapper clientLevelWrapper = MC_CLIENT.getWrappedClientLevel();
|
||||
if (clientLevelWrapper == null
|
||||
|| clientLevelWrapper.getDhLevel() != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientside.clientTick();
|
||||
|
||||
if (this.syncOnLoadRequestQueue != null)
|
||||
@@ -333,12 +348,15 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||
String o = MinecraftTextFormat.ORANGE;
|
||||
String y = MinecraftTextFormat.YELLOW;
|
||||
String g = MinecraftTextFormat.GREEN;
|
||||
String r = MinecraftTextFormat.RED;
|
||||
String cf = MinecraftTextFormat.CLEAR_FORMATTING;
|
||||
|
||||
|
||||
String dimName = this.levelWrapper.getDhIdentifier();
|
||||
boolean rendering = this.clientside.isRendering();
|
||||
String renderingString = rendering ? (g+"yes"+cf) : (o+"no"+cf);
|
||||
boolean rendering =
|
||||
this.clientside.isRendering()
|
||||
&& !IgnoredDimensionCsvHandler.INSTANCE.dimensionNameShouldBeIgnored(dimName);
|
||||
String renderingString = rendering ? (g+"yes"+cf) : (r+"no"+cf);
|
||||
messageList.add("["+y+dimName+cf+"] rendering: "+renderingString);
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.level;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.eventHandlers.IgnoredDimensionCsvHandler;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
||||
@@ -71,7 +72,19 @@ public class DhClientServerLevel extends AbstractDhServerLevel implements IDhCli
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void clientTick() { this.clientside.clientTick(); }
|
||||
public void clientTick()
|
||||
{
|
||||
// only tick the level the player is currently in
|
||||
// (done to prevent ticking LodQuadTree's for levels that aren't rendering)
|
||||
IClientLevelWrapper clientLevelWrapper = MC_CLIENT.getWrappedClientLevel();
|
||||
if (clientLevelWrapper == null
|
||||
|| clientLevelWrapper.getDhLevel() != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientside.clientTick();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
@@ -121,12 +134,15 @@ public class DhClientServerLevel extends AbstractDhServerLevel implements IDhCli
|
||||
String o = MinecraftTextFormat.ORANGE;
|
||||
String y = MinecraftTextFormat.YELLOW;
|
||||
String g = MinecraftTextFormat.GREEN;
|
||||
String r = MinecraftTextFormat.RED;
|
||||
String cf = MinecraftTextFormat.CLEAR_FORMATTING;
|
||||
|
||||
|
||||
String dimName = this.serverLevelWrapper.getDhIdentifier();
|
||||
boolean rendering = this.clientside.isRendering();
|
||||
String renderingString = rendering ? (g+"yes"+cf) : (o+"no"+cf);
|
||||
boolean rendering =
|
||||
this.clientside.isRendering()
|
||||
&& !IgnoredDimensionCsvHandler.INSTANCE.dimensionNameShouldBeIgnored(dimName);
|
||||
String renderingString = rendering ? (g+"yes"+cf) : (r+"no"+cf);
|
||||
messageList.add("["+y+dimName+cf+"] rendering: "+renderingString);
|
||||
|
||||
super.addDebugMenuStringsToList(messageList);
|
||||
|
||||
+3
-3
@@ -28,9 +28,9 @@ import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindab
|
||||
*/
|
||||
public interface IKeyedClientLevelManager extends IBindable
|
||||
{
|
||||
IServerKeyedClientLevel getServerKeyedLevel();
|
||||
/** Called when a client level is wrapped by a ServerEnhancedClientLevel, for integration into mod internals. */
|
||||
IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String serverKey, String levelKey);
|
||||
IServerKeyedClientLevel getServerKeyedLevel(IClientLevelWrapper levelWrapper);
|
||||
/** Called when a client level is wrapped by a ServerKeyedClientLevel, for integration into mod internals. */
|
||||
IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String dimensionResource, String serverKey, String levelKey);
|
||||
|
||||
void clearKeyedLevel();
|
||||
boolean isEnabled();
|
||||
|
||||
@@ -128,7 +128,7 @@ public class F3Screen
|
||||
messageList.add("LOD Pos: "+y+detailLevel+"*"+posX+","+posZ+cf);
|
||||
|
||||
AbstractDhRenderApiDefinition renderApiDef = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||
messageList.add("Rendering API: "+a+renderApiDef.getApiName()+cf);
|
||||
messageList.add("Rendering API: "+a+renderApiDef.getEngineName()+cf);
|
||||
}
|
||||
messageList.add("");
|
||||
}
|
||||
|
||||
+3
-1
@@ -13,6 +13,7 @@ import com.seibel.distanthorizons.core.network.event.ScopedNetworkEventSource;
|
||||
import com.seibel.distanthorizons.core.network.event.internal.CloseInternalEvent;
|
||||
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.RequestLevelInitMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.SessionConfigMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceResponseMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSplitMessage;
|
||||
@@ -164,7 +165,8 @@ public class ClientNetworkState implements Closeable
|
||||
// send message //
|
||||
//==============//
|
||||
|
||||
|
||||
public void sendLevelInitRequest(String clientLevelKey)
|
||||
{ this.getSession().sendMessage(new RequestLevelInitMessage(clientLevelKey)); }
|
||||
|
||||
public void sendConfigMessage() { this.sendConfigMessage(true); }
|
||||
public void sendConfigMessage(boolean blocking)
|
||||
|
||||
+24
-23
@@ -1,7 +1,7 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer.server;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.level.AbstractDhServerLevel;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.SessionConfig;
|
||||
import com.seibel.distanthorizons.core.multiplayer.fullData.FullDataPayloadSender;
|
||||
@@ -9,13 +9,16 @@ import com.seibel.distanthorizons.core.multiplayer.fullData.SharedBandwidthLimit
|
||||
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.RequestLevelInitMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.SessionConfigMessage;
|
||||
import com.seibel.distanthorizons.core.network.event.internal.CloseInternalEvent;
|
||||
import com.seibel.distanthorizons.core.network.exceptions.RateLimitedException;
|
||||
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceRequestMessage;
|
||||
import com.seibel.distanthorizons.core.network.session.NetworkSession;
|
||||
import com.seibel.distanthorizons.core.util.ratelimiting.SupplierBasedRateAndConcurrencyLimiter;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.Closeable;
|
||||
@@ -23,16 +26,14 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ServerPlayerState implements Closeable
|
||||
{
|
||||
private final ConfigChangeListener<String> levelKeyPrefixChangeListener
|
||||
= new ConfigChangeListener<>(Config.Server.levelKeyPrefix, this::onLevelKeyPrefixConfigChanged);
|
||||
private final SessionConfig.AnyChangeListener configAnyChangeListener = new SessionConfig.AnyChangeListener(this::sendConfigMessage);
|
||||
private final IMinecraftSharedWrapper MC_SHARED = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class);
|
||||
|
||||
private final SessionConfig.AnyChangeListener configAnyChangeListener = new SessionConfig.AnyChangeListener(this::sendConfigMessage);
|
||||
|
||||
private final String serverKeyWithoutId = Config.Server.serverKey.get();
|
||||
private final String serverKey = (this.serverKeyWithoutId.isEmpty() ? "" : Config.Server.serverId.get() + "_" + this.serverKeyWithoutId.trim())
|
||||
.replaceAll("[^" + LevelInitMessage.ALLOWED_CHARS_REGEX + " ]", "")
|
||||
.replaceAll(" ", "_");
|
||||
private String lastLevelKey = "";
|
||||
|
||||
|
||||
public final NetworkSession networkSession;
|
||||
@@ -61,11 +62,27 @@ public class ServerPlayerState implements Closeable
|
||||
this.networkSession.registerHandler(SessionConfigMessage.class, (sessionConfigMessage) ->
|
||||
{
|
||||
this.sessionConfig.constrainingConfig = sessionConfigMessage.config;
|
||||
|
||||
this.sendLevelKey();
|
||||
this.sendConfigMessage();
|
||||
});
|
||||
|
||||
this.networkSession.registerHandler(RequestLevelInitMessage.class, msg ->
|
||||
{
|
||||
if (!Config.Server.sendLevelKeys.get())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IServerLevelWrapper serverLevelWrapper = MC_SHARED.getLevelWrapper(msg.dimensionResourceLocation);
|
||||
if (serverLevelWrapper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
String levelKey = serverLevelWrapper.getKeyedLevelDimensionName();
|
||||
this.networkSession.sendMessage(new LevelInitMessage(msg.dimensionResourceLocation, this.serverKey, levelKey));
|
||||
});
|
||||
|
||||
|
||||
this.networkSession.registerHandler(CloseInternalEvent.class, event -> {
|
||||
// No-op. prevents "Unhandled message" log entries
|
||||
});
|
||||
@@ -84,21 +101,6 @@ public class ServerPlayerState implements Closeable
|
||||
// client updating //
|
||||
//=================//
|
||||
|
||||
private void onLevelKeyPrefixConfigChanged(String newLevelKey) { this.sendLevelKey(); }
|
||||
private void sendLevelKey()
|
||||
{
|
||||
if (Config.Server.sendLevelKeys.get())
|
||||
{
|
||||
// let the client's know about the change
|
||||
String levelKey = this.getServerPlayer().getLevel().getKeyedLevelDimensionName();
|
||||
if (!levelKey.equals(this.lastLevelKey))
|
||||
{
|
||||
this.lastLevelKey = levelKey;
|
||||
this.networkSession.sendMessage(new LevelInitMessage(this.serverKey, levelKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendConfigMessage()
|
||||
{
|
||||
double coordinateScale = this.getServerPlayer().getLevel().getDimensionType().getCoordinateScale();
|
||||
@@ -118,7 +120,6 @@ public class ServerPlayerState implements Closeable
|
||||
public void close()
|
||||
{
|
||||
this.fullDataPayloadSender.close();
|
||||
this.levelKeyPrefixChangeListener.close();
|
||||
this.configAnyChangeListener.close();
|
||||
this.networkSession.close();
|
||||
}
|
||||
|
||||
+2
-4
@@ -21,12 +21,9 @@ package com.seibel.distanthorizons.core.network.messages;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.SessionConfigMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.*;
|
||||
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSplitMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.requests.CancelMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.requests.ExceptionMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataPartialUpdateMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceRequestMessage;
|
||||
@@ -60,6 +57,7 @@ public class MessageRegistry
|
||||
|
||||
// Level keys
|
||||
this.registerMessage(LevelInitMessage.class, LevelInitMessage::new);
|
||||
this.registerMessage(RequestLevelInitMessage.class, RequestLevelInitMessage::new);
|
||||
|
||||
// Config (for full DH support)
|
||||
this.registerMessage(SessionConfigMessage.class, SessionConfigMessage::new);
|
||||
|
||||
+6
-1
@@ -21,6 +21,7 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
MAX_LENGTH, ALLOWED_CHARS_REGEX, ALLOWED_CHARS_REGEX, ALLOWED_CHARS_REGEX);
|
||||
|
||||
|
||||
public String dimensionResourceLocation;
|
||||
public String serverKey;
|
||||
public String levelKey;
|
||||
public long serverTime;
|
||||
@@ -32,8 +33,9 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
//==============//
|
||||
|
||||
public LevelInitMessage() { }
|
||||
public LevelInitMessage(String serverKey, String levelKey)
|
||||
public LevelInitMessage(String dimensionResourceLocation, String serverKey, String levelKey)
|
||||
{
|
||||
this.dimensionResourceLocation = dimensionResourceLocation;
|
||||
this.serverKey = serverKey;
|
||||
this.levelKey = levelKey;
|
||||
this.serverTime = System.currentTimeMillis();
|
||||
@@ -48,6 +50,7 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
@Override
|
||||
public void encode(ByteBuf out)
|
||||
{
|
||||
this.writeString(this.dimensionResourceLocation, out);
|
||||
this.writeString(this.serverKey, out);
|
||||
this.writeString(this.levelKey, out);
|
||||
out.writeLong(this.serverTime);
|
||||
@@ -56,6 +59,7 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
@Override
|
||||
public void decode(ByteBuf in)
|
||||
{
|
||||
this.dimensionResourceLocation = this.readString(in);
|
||||
this.serverKey = this.readString(in);
|
||||
this.levelKey = this.readString(in);
|
||||
this.serverTime = in.readLong();
|
||||
@@ -71,6 +75,7 @@ public class LevelInitMessage extends AbstractNetworkMessage
|
||||
public MoreObjects.ToStringHelper toStringHelper()
|
||||
{
|
||||
return super.toStringHelper()
|
||||
.add("dimensionResourceLocation", this.dimensionResourceLocation)
|
||||
.add("serverKey", this.serverKey)
|
||||
.add("levelKey", this.levelKey)
|
||||
.add("serverTime", this.serverTime);
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.network.messages.base;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/** used for full DH support */
|
||||
public class RequestLevelInitMessage extends AbstractNetworkMessage
|
||||
{
|
||||
public String dimensionResourceLocation;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public RequestLevelInitMessage() { }
|
||||
public RequestLevelInitMessage(String dimensionResourceLocation) { this.dimensionResourceLocation = dimensionResourceLocation; }
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// serialization //
|
||||
//===============//
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf out) { this.writeString(this.dimensionResourceLocation, out); }
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf in) { this.dimensionResourceLocation = this.readString(in); }
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public MoreObjects.ToStringHelper toStringHelper()
|
||||
{
|
||||
return super.toStringHelper()
|
||||
.add("dimensionResourceLocation", this.dimensionResourceLocation);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ package com.seibel.distanthorizons.core.pos;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
|
||||
/**
|
||||
* immutable <br><br>
|
||||
@@ -65,7 +65,7 @@ public class DhChunkPos
|
||||
// >> 4 is the Same as div 16
|
||||
this(blockPos.x >> 4, blockPos.z >> 4);
|
||||
}
|
||||
public DhChunkPos(Vec3d pos)
|
||||
public DhChunkPos(DhVec3d pos)
|
||||
{
|
||||
// >> 4 is the Same as div 16
|
||||
this(((int)pos.x) >> 4, ((int)pos.z) >> 4);
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.render;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy;
|
||||
import com.seibel.distanthorizons.api.objects.DhApiResult;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
@@ -28,6 +30,8 @@ import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||
import com.seibel.distanthorizons.core.world.AbstractDhWorld;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Used to interact with Distant Horizons' rendering systems.
|
||||
@@ -43,6 +47,18 @@ public class DhApiRenderProxy implements IDhApiRenderProxy
|
||||
|
||||
private boolean deferTransparentRendering = false;
|
||||
|
||||
private static AbstractDhRenderApiDefinition renderApiDef = null;
|
||||
@Nullable
|
||||
private static AbstractDhRenderApiDefinition tryGetApiDef()
|
||||
{
|
||||
if (renderApiDef == null)
|
||||
{
|
||||
renderApiDef = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||
}
|
||||
|
||||
return renderApiDef;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
@@ -57,6 +73,7 @@ public class DhApiRenderProxy implements IDhApiRenderProxy
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public DhApiResult<Boolean> clearRenderDataCache()
|
||||
{
|
||||
// make sure this is a valid time to run the method
|
||||
@@ -80,6 +97,32 @@ public class DhApiRenderProxy implements IDhApiRenderProxy
|
||||
return DhApiResult.createSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EDhApiRenderingApi getRenderingApi() throws IllegalStateException
|
||||
{
|
||||
AbstractDhRenderApiDefinition apiDef = tryGetApiDef();
|
||||
if (apiDef == null)
|
||||
{
|
||||
// The rendering API hasn't been set up yet
|
||||
throw new IllegalStateException("Distant Horizons hasn't finished setup yet. No renderer has been set.");
|
||||
}
|
||||
|
||||
return apiDef.getRenderApi();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeRenderer() throws IllegalStateException
|
||||
{
|
||||
AbstractDhRenderApiDefinition apiDef = tryGetApiDef();
|
||||
if (apiDef == null)
|
||||
{
|
||||
// The rendering API hasn't been set up yet
|
||||
throw new IllegalStateException("Distant Horizons hasn't finished setup yet. No renderer has been set.");
|
||||
}
|
||||
|
||||
return apiDef.isNativeRenderer();
|
||||
}
|
||||
|
||||
|
||||
public static int activeOpenGlDhDepthTextureId = -1;
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.seibel.distanthorizons.core.render;
|
||||
|
||||
/**
|
||||
* FORWARD_Z, <br>
|
||||
* REVERSE_Z, <br>
|
||||
*/
|
||||
public enum EDhRenderDepth
|
||||
{
|
||||
/**
|
||||
* AKA Zero to One <br>
|
||||
* MC 26.1.2 and older (OpenGL) = false (near = 0.0f, far = 1.0f)
|
||||
*/
|
||||
FORWARD_Z(0.0f, 1.0f),
|
||||
/**
|
||||
* AKA One to Zero <br>
|
||||
* MC 26.2.0 and newer (Vulkan/GL) = true (near = 1.0f, far = 0.0f)
|
||||
*/
|
||||
REVERSE_Z(1.0f, 0.0f);
|
||||
|
||||
|
||||
public final float nearDepth;
|
||||
public final float farDepth;
|
||||
|
||||
EDhRenderDepth(float nearDepth, float farDepth)
|
||||
{
|
||||
this.nearDepth = nearDepth;
|
||||
this.farDepth = farDepth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -73,7 +73,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
private static final AbstractDebugWireframeRenderer DEBUG_RENDERER = SingletonInjector.INSTANCE.get(AbstractDebugWireframeRenderer.class);
|
||||
|
||||
/** there should only ever be one {@link LodQuadTree} so having the thread static should be fine */
|
||||
private static final ThreadPoolExecutor FULL_DATA_RETRIEVAL_QUEUE_THREAD = ThreadUtil.makeSingleThreadPool("LodQuadTree Data Retrieval Queue");
|
||||
private static final ThreadPoolExecutor FULL_DATA_RETRIEVAL_QUEUE_THREAD = ThreadUtil.makeSingleDaemonThreadPool("LodQuadTree Data Retrieval Queue");
|
||||
|
||||
|
||||
public final int blockRenderDistanceDiameter;
|
||||
@@ -185,7 +185,13 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
this.enabledRenderSectionLock.lock();
|
||||
|
||||
tempProcessNodeList.clear();
|
||||
tempProcessNodeList.addAll(this.enabledSections);
|
||||
|
||||
// manual add and loop to reduce GC pressure due to addAll() doing unnecessary
|
||||
// array copies
|
||||
for (int i = 0; i < this.enabledSections.size(); i++)
|
||||
{
|
||||
tempProcessNodeList.add(this.enabledSections.get(i));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
+26
-16
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.render.QuadTree;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiTransparency;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource;
|
||||
@@ -46,6 +47,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.WillNotClose;
|
||||
import java.awt.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -170,20 +173,26 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
try
|
||||
{
|
||||
// build LOD data on a DH thread
|
||||
LodQuadBuilder lodQuadBuilder = this.getAndBuildRenderData();
|
||||
if (lodQuadBuilder == null)
|
||||
try (LodQuadBuilder lodQuadBuilder = this.getAndBuildRenderData())
|
||||
{
|
||||
future.complete(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// uploading will primarily happen on the render thread
|
||||
this.uploadToGpuAsync(future, lodQuadBuilder)
|
||||
.thenRun(() ->
|
||||
if (lodQuadBuilder == null)
|
||||
{
|
||||
// the future is passed in separately (IE not using the local var) to prevent any possible race condition null pointers
|
||||
future.complete(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// create CPU vertex buffers
|
||||
ArrayList<ByteBuffer> opaqueBuffers = lodQuadBuilder.makeOpaqueVertexBuffers();
|
||||
ArrayList<ByteBuffer> transparentBuffers = lodQuadBuilder.makeTransparentVertexBuffers();
|
||||
|
||||
// uploading will primarily happen on the render thread
|
||||
this.uploadToGpuAsync(future, opaqueBuffers, transparentBuffers)
|
||||
.thenRun(() ->
|
||||
{
|
||||
// the future is passed in separately (IE not using the local var) to prevent any possible race condition null pointers
|
||||
future.complete(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -223,8 +232,8 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
}
|
||||
|
||||
|
||||
boolean enableTransparency = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled;
|
||||
LodQuadBuilder lodQuadBuilder = new LodQuadBuilder(enableTransparency, this.clientLevel.getClientLevelWrapper());
|
||||
boolean enableTransparency = Config.Client.Advanced.Graphics.Quality.transparency.get() == EDhApiTransparency.COMPLETE;
|
||||
LodQuadBuilder lodQuadBuilder = LodQuadBuilder.getBuilder(enableTransparency, this.clientLevel.getClientLevelWrapper());
|
||||
|
||||
|
||||
// get the adjacent positions
|
||||
@@ -302,10 +311,11 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
|
||||
|
||||
private synchronized CompletableFuture<LodBufferContainer> uploadToGpuAsync(
|
||||
CompletableFuture<Void> parentFuture,
|
||||
LodQuadBuilder lodQuadBuilder)
|
||||
CompletableFuture<Void> parentFuture,
|
||||
ArrayList<ByteBuffer> opaqueBuffers,
|
||||
ArrayList<ByteBuffer> transparentBuffers)
|
||||
{
|
||||
CompletableFuture<LodBufferContainer> uploadFuture = LodBufferContainer.tryMakeAndUploadBuffersAsync(this.pos, this.clientLevel, lodQuadBuilder);
|
||||
CompletableFuture<LodBufferContainer> uploadFuture = LodBufferContainer.tryMakeAndUploadBuffersAsync(this.pos, this.clientLevel, opaqueBuffers, transparentBuffers);
|
||||
uploadFuture.whenComplete((bufferContainer, e) ->
|
||||
{
|
||||
try
|
||||
|
||||
+37
-16
@@ -36,14 +36,15 @@ import com.seibel.distanthorizons.core.render.QuadTree.LodRenderSection;
|
||||
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
|
||||
import com.seibel.distanthorizons.core.render.renderer.cullingFrustum.DhFrustumBounds;
|
||||
import com.seibel.distanthorizons.core.render.renderer.cullingFrustum.NeverCullFrustum;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhMat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -58,6 +59,13 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
|
||||
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
|
||||
|
||||
// static values for re-use to reduce GC pressure
|
||||
private static final float[] JOML_TRANSPOSE_ARRAY = new float[16];
|
||||
private static final Matrix4f WORLD_VIEW_JOML_MATRIX = new Matrix4f();
|
||||
private static final Matrix4f WORLD_VIEW_PROJ_JOML_MATRIX = new Matrix4f();
|
||||
private static final DhMat4f FRUSTOM_DH_MATRIX = new DhMat4f();
|
||||
|
||||
|
||||
/** contains all relevant data */
|
||||
public final LodQuadTree lodQuadTree;
|
||||
|
||||
@@ -123,6 +131,14 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
*/
|
||||
public void buildRenderList(RenderParams renderParams)
|
||||
{
|
||||
if (ModInfo.IS_DEV_BUILD)
|
||||
{
|
||||
if (!RenderThreadTaskHandler.INSTANCE.isCurrentThread())
|
||||
{
|
||||
LodUtil.assertNotReach("Should only be run on the render thread");
|
||||
}
|
||||
}
|
||||
|
||||
// clear the old list so we can start fresh
|
||||
this.loadedNearToFarBuffers.clear();
|
||||
|
||||
@@ -154,20 +170,21 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
int worldMinY = renderParams.clientLevelWrapper.getMinHeight();
|
||||
int worldHeight = renderParams.clientLevelWrapper.getMaxHeight();
|
||||
|
||||
Vec3d cameraPos = MC_RENDER.getCameraExactPosition();
|
||||
renderParams.mcModelViewMatrix.putValuesInArray(JOML_TRANSPOSE_ARRAY);
|
||||
WORLD_VIEW_JOML_MATRIX
|
||||
.setTransposed(JOML_TRANSPOSE_ARRAY)
|
||||
.translate(
|
||||
-(float) renderParams.exactCameraPosition.x,
|
||||
-(float) renderParams.exactCameraPosition.y,
|
||||
-(float) renderParams.exactCameraPosition.z);
|
||||
|
||||
Matrix4fc matWorldView = new Matrix4f()
|
||||
.setTransposed(renderParams.mcModelViewMatrix.getValuesAsArray())
|
||||
.translate(
|
||||
-(float) cameraPos.x,
|
||||
-(float) cameraPos.y,
|
||||
-(float) cameraPos.z);
|
||||
|
||||
Matrix4fc matWorldViewProjection = new Matrix4f()
|
||||
.setTransposed(renderParams.dhProjectionMatrix.getValuesAsArray())
|
||||
.mul(matWorldView);
|
||||
|
||||
frustum.update(worldMinY, worldMinY + worldHeight, new Mat4f(matWorldViewProjection));
|
||||
renderParams.dhProjectionMatrix.putValuesInArray(JOML_TRANSPOSE_ARRAY);
|
||||
WORLD_VIEW_PROJ_JOML_MATRIX
|
||||
.setTransposed(JOML_TRANSPOSE_ARRAY)
|
||||
.mul(WORLD_VIEW_JOML_MATRIX);
|
||||
|
||||
FRUSTOM_DH_MATRIX.set(WORLD_VIEW_PROJ_JOML_MATRIX);
|
||||
frustum.update(worldMinY, worldMinY + worldHeight, FRUSTOM_DH_MATRIX);
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +192,7 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
//=========================//
|
||||
// Update the section list //
|
||||
//=========================//
|
||||
//region
|
||||
|
||||
if (isShadowPass)
|
||||
{
|
||||
@@ -251,6 +269,9 @@ public class RenderBufferHandler implements AutoCloseable
|
||||
{
|
||||
this.visibleBufferCount = this.loadedNearToFarBuffers.size();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
@@ -6,18 +6,14 @@ import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import com.seibel.distanthorizons.core.api.internal.rendering.DhRenderState;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
||||
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.DhMat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.world.IDhClientWorld;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
@@ -34,8 +30,12 @@ public class RenderParams extends DhApiRenderParam
|
||||
|
||||
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
|
||||
|
||||
private static final long TIME_FOR_MAC_TO_FINISH_COMPILING_IN_MS = 10_000;
|
||||
private static boolean initialLoadingComplete = false;
|
||||
/**
|
||||
* Copy used for API events. <br>
|
||||
* A separate copy is used to prevent API users from accidentally setting values
|
||||
* that screw up DH's copy of the render parameters.
|
||||
*/
|
||||
public final DhApiRenderParam apiCopy = new DhApiRenderParam();
|
||||
|
||||
|
||||
public IDhClientWorld dhClientWorld;
|
||||
@@ -45,7 +45,7 @@ public class RenderParams extends DhApiRenderParam
|
||||
public ILightMapWrapper lightmap;
|
||||
public RenderBufferHandler renderBufferHandler;
|
||||
public IDhGenericRenderer genericRenderer;
|
||||
public Vec3d exactCameraPosition;
|
||||
public DhVec3d exactCameraPosition;
|
||||
/** @see DhRenderState#vanillaFogEnabled */
|
||||
public boolean vanillaFogEnabled;
|
||||
|
||||
@@ -58,36 +58,27 @@ public class RenderParams extends DhApiRenderParam
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public RenderParams(EDhApiRenderPass renderPass, DhRenderState renderState)
|
||||
public void update(EDhApiRenderPass renderPass, DhRenderState renderState)
|
||||
{
|
||||
this(renderPass,
|
||||
renderState.partialTickTime,
|
||||
renderState.mcProjectionMatrix, renderState.mcModelViewMatrix,
|
||||
renderState.clientLevelWrapper,
|
||||
renderState.vanillaFogEnabled
|
||||
);
|
||||
}
|
||||
private RenderParams(
|
||||
EDhApiRenderPass renderPass,
|
||||
float newPartialTicks,
|
||||
Mat4f newMcProjectionMatrix, Mat4f newMcModelViewMatrix,
|
||||
IClientLevelWrapper clientLevelWrapper,
|
||||
boolean vanillaFogEnabled
|
||||
)
|
||||
{
|
||||
super(renderPass,
|
||||
newPartialTicks,
|
||||
RenderUtil.getNearClipPlaneInBlocks(), RenderUtil.getFarClipPlaneDistanceInBlocks(),
|
||||
newMcProjectionMatrix, newMcModelViewMatrix,
|
||||
RenderUtil.createLodProjectionMatrix(newMcProjectionMatrix), RenderUtil.createLodModelViewMatrix(newMcModelViewMatrix),
|
||||
clientLevelWrapper.getMinHeight(),
|
||||
clientLevelWrapper);
|
||||
RenderUtil.setDhProjectionMatrix(this.dhProjectionMatrix, renderState.mcProjectionMatrix);
|
||||
this.dhModelViewMatrix.set(renderState.mcModelViewMatrix); // DH and MC MVM matrix are the same
|
||||
|
||||
super.update(renderPass,
|
||||
renderState.partialTickTime,
|
||||
RenderUtil.getNearClipPlaneInBlocks(), RenderUtil.getFarClipPlaneDistanceInBlocks(),
|
||||
renderState.mcProjectionMatrix, renderState.mcModelViewMatrix,
|
||||
this.dhProjectionMatrix, this.dhModelViewMatrix,
|
||||
renderState.clientLevelWrapper.getMinHeight(),
|
||||
renderState.clientLevelWrapper);
|
||||
|
||||
|
||||
|
||||
this.clientLevelWrapper = renderState.clientLevelWrapper;
|
||||
|
||||
this.dhClientWorld = SharedApi.tryGetDhClientWorld();
|
||||
if (this.dhClientWorld != null)
|
||||
{
|
||||
this.dhClientLevel = (IDhClientLevel) this.dhClientWorld.getLevel(clientLevelWrapper);
|
||||
this.dhClientLevel = this.dhClientWorld.getOrLoadClientLevel(clientLevelWrapper);
|
||||
if (this.dhClientLevel != null)
|
||||
{
|
||||
this.renderBufferHandler = this.dhClientLevel.getRenderBufferHandler();
|
||||
@@ -95,7 +86,6 @@ public class RenderParams extends DhApiRenderParam
|
||||
}
|
||||
}
|
||||
|
||||
this.clientLevelWrapper = clientLevelWrapper;
|
||||
this.lightmap = MC_RENDER.getLightmapWrapper(this.clientLevelWrapper);
|
||||
|
||||
if (MC_CLIENT.playerExists())
|
||||
@@ -103,8 +93,9 @@ public class RenderParams extends DhApiRenderParam
|
||||
this.exactCameraPosition = MC_RENDER.getCameraExactPosition();
|
||||
}
|
||||
|
||||
this.vanillaFogEnabled = vanillaFogEnabled;
|
||||
this.vanillaFogEnabled = renderState.vanillaFogEnabled;
|
||||
|
||||
this.apiCopy.update(this);
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -120,7 +111,7 @@ public class RenderParams extends DhApiRenderParam
|
||||
* Should be called before rendering is done.
|
||||
* @return a message if LODs shouldn't be rendered, null if the LODs can render
|
||||
*/
|
||||
public String getValidationErrorMessage(long firstRenderTimeMs)
|
||||
public String getValidationErrorMessage()
|
||||
{
|
||||
// Note: all strings here should be constants to prevent String allocations
|
||||
|
||||
@@ -162,12 +153,21 @@ public class RenderParams extends DhApiRenderParam
|
||||
return "No Generic Renderer Present";
|
||||
}
|
||||
|
||||
if (this.dhModelViewMatrix == null
|
||||
|| this.mcModelViewMatrix == null)
|
||||
if (this.dhModelViewMatrix.equals(DhMat4f.IDENTITY)
|
||||
|| this.dhModelViewMatrix.equals(DhMat4f.EMPTY))
|
||||
{
|
||||
return "No MVM or Proj Matrix Given";
|
||||
return "No DH MVM Matrix Given";
|
||||
}
|
||||
|
||||
if (this.mcModelViewMatrix.equals(DhMat4f.IDENTITY)
|
||||
|| this.mcModelViewMatrix.equals(DhMat4f.EMPTY))
|
||||
{
|
||||
return "No MC MVM Matrix Given";
|
||||
}
|
||||
|
||||
// projection matrix not checked since there are some MC versions where
|
||||
// the MVM and projection matrices are pre-multiplied together
|
||||
|
||||
if (OPTIFINE_ACCESSOR != null
|
||||
&& MC_RENDER.getTargetFramebuffer() == -1)
|
||||
{
|
||||
|
||||
+14
-15
@@ -7,9 +7,9 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhMat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3f;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -35,8 +35,8 @@ public abstract class AbstractDebugWireframeRenderer implements IBindable
|
||||
protected final PriorityBlockingQueue<BoxParticle> particles = new PriorityBlockingQueue<>();
|
||||
|
||||
// used when rendering
|
||||
protected Mat4f dhMvmProjMatrixThisFrame;
|
||||
protected Vec3f camPosFloatThisFrame;
|
||||
protected DhMat4f dhMvmProjMatrixThisFrame;
|
||||
protected DhVec3f camPosFloatThisFrame;
|
||||
|
||||
|
||||
|
||||
@@ -47,9 +47,8 @@ public abstract class AbstractDebugWireframeRenderer implements IBindable
|
||||
|
||||
public void render(RenderParams renderParams)
|
||||
{
|
||||
this.dhMvmProjMatrixThisFrame = new Mat4f(renderParams.dhMvmProjMatrix);
|
||||
Vec3d camPos = MC_RENDER.getCameraExactPosition();
|
||||
this.camPosFloatThisFrame = new Vec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
|
||||
this.dhMvmProjMatrixThisFrame = new DhMat4f(renderParams.dhMvmProjMatrix);
|
||||
this.camPosFloatThisFrame = new DhVec3f(renderParams.exactCameraPosition);
|
||||
|
||||
|
||||
this.rendererLists.render(this);
|
||||
@@ -113,8 +112,8 @@ public abstract class AbstractDebugWireframeRenderer implements IBindable
|
||||
|
||||
public static final class Box
|
||||
{
|
||||
public Vec3f minPos;
|
||||
public Vec3f maxPos;
|
||||
public DhVec3f minPos;
|
||||
public DhVec3f maxPos;
|
||||
public Color color;
|
||||
|
||||
|
||||
@@ -128,13 +127,13 @@ public abstract class AbstractDebugWireframeRenderer implements IBindable
|
||||
int maxBlockPosX = minBlockPosX + DhSectionPos.getBlockWidth(pos);
|
||||
int maxBlockPosZ = minBlockPosZ + DhSectionPos.getBlockWidth(pos);
|
||||
|
||||
this.minPos = new Vec3f(minBlockPosX + edgeOffset, minY, minBlockPosZ + edgeOffset);
|
||||
this.maxPos = new Vec3f(maxBlockPosX - edgeOffset, maxY, maxBlockPosZ - edgeOffset);
|
||||
this.minPos = new DhVec3f(minBlockPosX + edgeOffset, minY, minBlockPosZ + edgeOffset);
|
||||
this.maxPos = new DhVec3f(maxBlockPosX - edgeOffset, maxY, maxBlockPosZ - edgeOffset);
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/** only used for */
|
||||
public Box(Vec3f minPos, Vec3f maxPos, Color color)
|
||||
public Box(DhVec3f minPos, DhVec3f maxPos, Color color)
|
||||
{
|
||||
this.minPos = minPos;
|
||||
this.maxPos = maxPos;
|
||||
@@ -177,8 +176,8 @@ public abstract class AbstractDebugWireframeRenderer implements IBindable
|
||||
float yDiff = this.yChange * percent;
|
||||
|
||||
return new Box(
|
||||
new Vec3f(this.box.minPos.x, this.box.minPos.y + yDiff, this.box.minPos.z),
|
||||
new Vec3f(this.box.maxPos.x, this.box.maxPos.y + yDiff, this.box.maxPos.z),
|
||||
new DhVec3f(this.box.minPos.x, this.box.minPos.y + yDiff, this.box.minPos.z),
|
||||
new DhVec3f(this.box.maxPos.x, this.box.maxPos.y + yDiff, this.box.maxPos.z),
|
||||
this.box.color);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -34,7 +34,7 @@ import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
|
||||
@@ -138,7 +138,7 @@ public class BeaconRenderHandler
|
||||
// lock to make sure we don't try adding beacons to the arrays while processing them
|
||||
this.updateLock.lock();
|
||||
|
||||
Vec3d cameraPos = MC_RENDER.getCameraExactPosition();
|
||||
DhVec3d cameraPos = MC_RENDER.getCameraExactPosition();
|
||||
|
||||
// fading by the overdraw prevention amount helps reduce beacons from rendering strangely
|
||||
// on the border of DH's render distance
|
||||
@@ -156,7 +156,7 @@ public class BeaconRenderHandler
|
||||
for (DhApiRenderableBox box : this.fullBeaconBoxList)
|
||||
{
|
||||
// if a beacon is outside the vanilla render distance render it
|
||||
double distance = Vec3d.getHorizontalDistance(cameraPos, box.minPos);
|
||||
double distance = DhVec3d.getHorizontalDistance(cameraPos, box.minPos);
|
||||
if (distance > dhFadeDistance)
|
||||
{
|
||||
this.activeBeaconBoxRenderGroup.add(box);
|
||||
|
||||
+115
-68
@@ -31,8 +31,8 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3f;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
@@ -74,25 +74,28 @@ public class CloudRenderHandler
|
||||
*/
|
||||
private static final int CLOUD_INSTANCE_RADIUS_COUNT = 5;
|
||||
|
||||
/** if multi-layer clouds are enabled how many layers should be rendered? */
|
||||
private static final int CLOUD_LAYER_COUNT = 3;
|
||||
|
||||
private static final float MOVE_SPEED_IN_BLOCKS_PER_SECOND = 6.0f;
|
||||
|
||||
|
||||
private final IDhApiRenderableBoxGroup[][] boxGroupByOffset
|
||||
private final IDhApiRenderableBoxGroup[][][] boxGroupByOffset
|
||||
// radius * 2 to get the diameter
|
||||
// + 1 so we get an odd number wide (needed so we can have a center position)
|
||||
= new IDhApiRenderableBoxGroup[(CLOUD_INSTANCE_RADIUS_COUNT * 2) + 1][(CLOUD_INSTANCE_RADIUS_COUNT * 2) + 1];
|
||||
= new IDhApiRenderableBoxGroup[CLOUD_LAYER_COUNT][(CLOUD_INSTANCE_RADIUS_COUNT * 2) + 1][(CLOUD_INSTANCE_RADIUS_COUNT * 2) + 1];
|
||||
|
||||
private final IDhClientLevel level;
|
||||
private final IDhGenericRenderer renderer;
|
||||
|
||||
/** cached array so we don't need to re-create it each frame for each cloud group */
|
||||
private final Vec3d[] cullingCorners = new Vec3d[]
|
||||
private final DhVec3d[] cullingCorners = new DhVec3d[]
|
||||
{
|
||||
// the values of each will be overwritten during the culling pass
|
||||
new Vec3d(),
|
||||
new Vec3d(),
|
||||
new Vec3d(),
|
||||
new Vec3d(),
|
||||
new DhVec3d(),
|
||||
new DhVec3d(),
|
||||
new DhVec3d(),
|
||||
new DhVec3d(),
|
||||
};
|
||||
|
||||
|
||||
@@ -260,32 +263,42 @@ public class CloudRenderHandler
|
||||
|
||||
// slightly lighter shading than the default
|
||||
DhApiRenderableBoxGroupShading cloudShading = DhApiRenderableBoxGroupShading.getUnshaded();
|
||||
cloudShading.north = cloudShading.south = 0.9f;
|
||||
cloudShading.east = cloudShading.west = 0.8f;
|
||||
cloudShading.top = 1.0f;
|
||||
cloudShading.bottom = 0.7f;
|
||||
|
||||
|
||||
for (int x = -CLOUD_INSTANCE_RADIUS_COUNT; x <= CLOUD_INSTANCE_RADIUS_COUNT; x++)
|
||||
{
|
||||
for (int z = -CLOUD_INSTANCE_RADIUS_COUNT; z <= CLOUD_INSTANCE_RADIUS_COUNT; z++)
|
||||
cloudShading.north = 0.9f;
|
||||
cloudShading.south = cloudShading.north;
|
||||
|
||||
cloudShading.east = 0.8f;
|
||||
cloudShading.west = cloudShading.east;
|
||||
|
||||
cloudShading.top = 1.0f;
|
||||
cloudShading.bottom = 0.7f;
|
||||
}
|
||||
|
||||
for (int y = CLOUD_LAYER_COUNT-1; y >= 0; y--) // start from the top down so transparency could be attempted
|
||||
{
|
||||
for (int x = -CLOUD_INSTANCE_RADIUS_COUNT; x <= CLOUD_INSTANCE_RADIUS_COUNT; x++)
|
||||
{
|
||||
IDhApiRenderableBoxGroup boxGroup = GENERIC_OBJECT_FACTORY.createRelativePositionedGroup(
|
||||
for (int z = -CLOUD_INSTANCE_RADIUS_COUNT; z <= CLOUD_INSTANCE_RADIUS_COUNT; z++)
|
||||
{
|
||||
IDhApiRenderableBoxGroup boxGroup = GENERIC_OBJECT_FACTORY.createRelativePositionedGroup(
|
||||
ModInfo.NAME + ":Clouds",
|
||||
new DhApiVec3d(0, 0, 0), // the offset will be set during rendering
|
||||
boxList);
|
||||
|
||||
// since cloud colors are set by the level based on the time of day lighting should affect it
|
||||
boxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||
boxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||
boxGroup.setSsaoEnabled(false);
|
||||
boxGroup.setShading(cloudShading);
|
||||
|
||||
CloudParams cloudParams = new CloudParams(textureWidth, x, z);
|
||||
boxGroup.setPreRenderFunc((renderParam) -> this.preRender(renderParam, cloudParams));
|
||||
|
||||
this.renderer.add(boxGroup);
|
||||
this.boxGroupByOffset[x+CLOUD_INSTANCE_RADIUS_COUNT][z+CLOUD_INSTANCE_RADIUS_COUNT] = boxGroup;
|
||||
|
||||
// since cloud colors are set by the level based on the time of day lighting should affect it
|
||||
boxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||
boxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||
boxGroup.setSsaoEnabled(false);
|
||||
boxGroup.setShading(cloudShading);
|
||||
|
||||
CloudParams cloudParams = new CloudParams(
|
||||
textureWidth,
|
||||
y, x, z);
|
||||
boxGroup.setPreRenderFunc((renderParam) -> this.preRender(renderParam, cloudParams));
|
||||
|
||||
this.renderer.add(boxGroup);
|
||||
this.boxGroupByOffset[y][x + CLOUD_INSTANCE_RADIUS_COUNT][z + CLOUD_INSTANCE_RADIUS_COUNT] = boxGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,15 +314,24 @@ public class CloudRenderHandler
|
||||
|
||||
private void preRender(DhApiRenderParam renderParam, CloudParams cloudParams)
|
||||
{
|
||||
IDhApiRenderableBoxGroup boxGroup = this.boxGroupByOffset[cloudParams.instanceOffsetX+CLOUD_INSTANCE_RADIUS_COUNT][cloudParams.instanceOffsetZ+CLOUD_INSTANCE_RADIUS_COUNT];
|
||||
IDhApiRenderableBoxGroup boxGroup = this.boxGroupByOffset[cloudParams.instanceOffsetY][cloudParams.instanceOffsetX+CLOUD_INSTANCE_RADIUS_COUNT][cloudParams.instanceOffsetZ+CLOUD_INSTANCE_RADIUS_COUNT];
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// should we render? //
|
||||
//===================//
|
||||
//region
|
||||
|
||||
boolean renderClouds = Config.Client.Advanced.Graphics.GenericRendering.enableCloudRendering.get();
|
||||
|
||||
boolean renderSingleCloudLayer = !Config.Client.Advanced.Graphics.GenericRendering.enableMultiLayerClouds.get();
|
||||
if (renderSingleCloudLayer
|
||||
&& cloudParams.instanceOffsetY != 0)
|
||||
{
|
||||
renderClouds = false;
|
||||
}
|
||||
|
||||
boxGroup.setActive(renderClouds);
|
||||
if(!renderClouds)
|
||||
{
|
||||
@@ -322,27 +344,33 @@ public class CloudRenderHandler
|
||||
return;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// cloud movement //
|
||||
//================//
|
||||
//region
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
float deltaTime = (currentTime - cloudParams.lastFrameTime) / 1000.0f; // Delta time in seconds
|
||||
cloudParams.lastFrameTime = currentTime;
|
||||
|
||||
float deltaX = MOVE_SPEED_IN_BLOCKS_PER_SECOND * deltaTime;
|
||||
float deltaX = (MOVE_SPEED_IN_BLOCKS_PER_SECOND + cloudParams.heightSpeedOffset) * deltaTime;
|
||||
// negative delta is to match vanilla's cloud movement
|
||||
cloudParams.deltaOffsetX -= deltaX;
|
||||
// wrap the cloud around after reaching the edge
|
||||
cloudParams.deltaOffsetX %= cloudParams.widthInBlocks;
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//============================//
|
||||
// camera movement and offset //
|
||||
//============================//
|
||||
//region
|
||||
|
||||
// camera position
|
||||
int cameraPosX = (int)MC_RENDER.getCameraExactPosition().x;
|
||||
@@ -360,13 +388,17 @@ public class CloudRenderHandler
|
||||
|
||||
|
||||
float newMinPosX =
|
||||
cloudParams.deltaOffsetX
|
||||
+ (cloudParams.instanceOffsetX * cloudParams.widthInBlocks)
|
||||
+ instanceOffsetX + cloudParams.halfWidthInBlocks;
|
||||
float newMinPosY = this.level.getLevelWrapper().getMaxHeight() + 200;
|
||||
float newMinPosZ = cloudParams.deltaOffsetZ
|
||||
+ (cloudParams.instanceOffsetZ * cloudParams.widthInBlocks)
|
||||
+ instanceOffsetZ + cloudParams.halfWidthInBlocks;
|
||||
cloudParams.deltaOffsetX
|
||||
+ (cloudParams.instanceOffsetX * cloudParams.widthInBlocks)
|
||||
+ instanceOffsetX + cloudParams.halfWidthInBlocks;
|
||||
float newMinPosY =
|
||||
this.level.getLevelWrapper().getMaxHeight()
|
||||
+ 100 // render clouds at least 200 blocks above the height limit to prevent players/blocks from intersecting (since DH always renders behind everything else)
|
||||
+ cloudParams.heightOffset;
|
||||
float newMinPosZ =
|
||||
cloudParams.deltaOffsetZ
|
||||
+ (cloudParams.instanceOffsetZ * cloudParams.widthInBlocks)
|
||||
+ instanceOffsetZ + cloudParams.halfWidthInBlocks;
|
||||
|
||||
boolean cullCloud = this.shouldCloudBeCulled(
|
||||
newMinPosX, newMinPosY, newMinPosZ,
|
||||
@@ -377,28 +409,25 @@ public class CloudRenderHandler
|
||||
boxGroup.setActive(false);
|
||||
}
|
||||
|
||||
boxGroup.setOriginBlockPos(new DhApiVec3d(newMinPosX, newMinPosY, newMinPosZ));
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// update color and position //
|
||||
//===========================//
|
||||
//region
|
||||
|
||||
// if debug colors are enabled don't change them
|
||||
if (!DEBUG_BORDER_COLORS
|
||||
// don't modify cloud groups that aren't active
|
||||
&& boxGroup.isActive())
|
||||
// don't replace the debug colors
|
||||
if (!DEBUG_BORDER_COLORS)
|
||||
{
|
||||
// cloud color changes based on the time of day and weather so we need to get it from the level
|
||||
Color newCloudColor = clientLevelWrapper.getCloudColor(renderParam.partialTicks);
|
||||
|
||||
|
||||
// all boxes should have the same color, so we can get their current color
|
||||
// via the first box
|
||||
DhApiRenderableBox firstBox = boxGroup.get(0);
|
||||
Color currentBoxColor = firstBox.color;
|
||||
|
||||
// update the boxes if their color should be changed
|
||||
if (!newCloudColor.equals(currentBoxColor))
|
||||
if (!newCloudColor.equals(cloudParams.previousColor))
|
||||
{
|
||||
// Note: cloud instances may share boxes
|
||||
// because of that this method may only need to be called once per all clouds
|
||||
@@ -406,20 +435,20 @@ public class CloudRenderHandler
|
||||
{
|
||||
box.color = newCloudColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// trigger an update if this cloud section has a different color
|
||||
if (!cloudParams.previousColor.equals(newCloudColor))
|
||||
{
|
||||
|
||||
cloudParams.previousColor = newCloudColor;
|
||||
|
||||
boxGroup.triggerBoxChange();
|
||||
}
|
||||
}
|
||||
|
||||
boxGroup.setOriginBlockPos(new DhApiVec3d(newMinPosX, newMinPosY, newMinPosZ));
|
||||
//endregion
|
||||
}
|
||||
/**
|
||||
* based on the OpenGL spec <br>
|
||||
* https://registry.khronos.org/OpenGL-Refpages/gl4/html/mix.xhtml
|
||||
*/
|
||||
private float mixColors(float x, float y, float a) { return x * (1 - a) + y * a; }
|
||||
private boolean shouldCloudBeCulled(
|
||||
float minPosX, float minPosY, float minPosZ,
|
||||
CloudParams cloudParams)
|
||||
@@ -460,14 +489,17 @@ public class CloudRenderHandler
|
||||
this.cullingCorners[3].y = minPosY;
|
||||
this.cullingCorners[3].z = minPosZ + cloudParams.widthInBlocks;
|
||||
|
||||
Vec3d cameraPos = MC_RENDER.getCameraExactPosition();
|
||||
Vec3f cameraLookAtVector = MC_RENDER.getLookAtVector();
|
||||
DhVec3d cameraPos = MC_RENDER.getCameraExactPosition();
|
||||
DhVec3f cameraLookAtVector = MC_RENDER.getLookAtVector();
|
||||
cameraLookAtVector.normalize();
|
||||
|
||||
double renderDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get()
|
||||
// * 1.5 is so we have a little extra buffer where clouds will render further than
|
||||
// necessary to prevent seeing the cloud border
|
||||
* LodUtil.CHUNK_WIDTH * 1.5;
|
||||
double renderDistance =
|
||||
// minimum distance of 256 to handle 3-layer clouds correctly,
|
||||
// otherwise the upper layers will be culled
|
||||
Math.max(Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get(), 256)
|
||||
// * 1.5 is so we have a little extra buffer where clouds will render further than
|
||||
// necessary to prevent seeing the cloud border
|
||||
* LodUtil.CHUNK_WIDTH * 1.5;
|
||||
|
||||
|
||||
|
||||
@@ -478,14 +510,14 @@ public class CloudRenderHandler
|
||||
boolean allOutsideRenderDistance = true;
|
||||
boolean allBehindCamera = true;
|
||||
|
||||
for (Vec3d corner : this.cullingCorners)
|
||||
for (DhVec3d corner : this.cullingCorners)
|
||||
{
|
||||
// Check if the corner is within the render distance
|
||||
// (ignoring height, since LODs also ignore height)
|
||||
|
||||
Vec3d cornerNoHeight = new Vec3d(corner);
|
||||
DhVec3d cornerNoHeight = new DhVec3d(corner);
|
||||
cornerNoHeight.y = 0;
|
||||
Vec3d cameraPosNoHeight = new Vec3d(cameraPos);
|
||||
DhVec3d cameraPosNoHeight = new DhVec3d(cameraPos);
|
||||
cameraPosNoHeight.y = 0;
|
||||
|
||||
double cornerDistance = cornerNoHeight.getDistance(cameraPosNoHeight);
|
||||
@@ -496,7 +528,7 @@ public class CloudRenderHandler
|
||||
|
||||
|
||||
// Check if the corner is in front of the camera (dot product > 0 means in front)
|
||||
Vec3f toCorner = new Vec3f(
|
||||
DhVec3f toCorner = new DhVec3f(
|
||||
(float) (corner.x - cameraPos.x),
|
||||
(float) (corner.y - cameraPos.y),
|
||||
(float) (corner.z - cameraPos.z));
|
||||
@@ -568,9 +600,13 @@ public class CloudRenderHandler
|
||||
public final int widthInBlocks;
|
||||
public final int halfWidthInBlocks;
|
||||
|
||||
public final int instanceOffsetY;
|
||||
public final int instanceOffsetX;
|
||||
public final int instanceOffsetZ;
|
||||
|
||||
public final int heightOffset;
|
||||
public final float heightSpeedOffset;
|
||||
|
||||
|
||||
/** how far this cloud group has moved in the X direction based on time */
|
||||
public float deltaOffsetX = 0;
|
||||
@@ -586,14 +622,25 @@ public class CloudRenderHandler
|
||||
|
||||
// constructor //
|
||||
|
||||
public CloudParams(int textureWidth, int instanceOffsetX, int instanceOffsetZ)
|
||||
public CloudParams(int textureWidth, int instanceOffsetY, int instanceOffsetX, int instanceOffsetZ)
|
||||
{
|
||||
this.textureWidth = textureWidth;
|
||||
this.widthInBlocks = (this.textureWidth * CLOUD_BOX_WIDTH);
|
||||
this.halfWidthInBlocks = this.widthInBlocks / 2;
|
||||
|
||||
this.instanceOffsetY = instanceOffsetY;
|
||||
this.instanceOffsetX = instanceOffsetX;
|
||||
this.instanceOffsetZ = instanceOffsetZ;
|
||||
|
||||
|
||||
// each layer up increases by 512 blocks
|
||||
this.heightOffset = instanceOffsetY * 512;
|
||||
// have higher cloud layers move faster
|
||||
this.heightSpeedOffset = instanceOffsetY * 10f;
|
||||
|
||||
// offset each layer a bit so the duplicated texture use isn't as obvious
|
||||
this.deltaOffsetX = this.widthInBlocks * instanceOffsetY * 0.75f;
|
||||
this.deltaOffsetZ = this.widthInBlocks * instanceOffsetY * 1.5f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package com.seibel.distanthorizons.core.render.renderer;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogFalloff;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeFogRenderEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiFogRenderParam;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @see DhApiFogRenderParam
|
||||
* @see DhApiBeforeFogRenderEvent.EventParam
|
||||
*/
|
||||
public class FogRenderParamFactory
|
||||
{
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
/** cached object to reduce GC pressure */
|
||||
private static final DhApiBeforeFogRenderEvent.EventParam EVENT_PARAM = new DhApiBeforeFogRenderEvent.EventParam();
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
/** returns a cached object to reduce GC pressure */
|
||||
public static DhApiBeforeFogRenderEvent.EventParam getRenderParam(RenderParams renderParams)
|
||||
{
|
||||
Color fogColor = getFogColor(renderParams.partialTicks);
|
||||
|
||||
// far fog
|
||||
EDhApiFogFalloff farFogFalloff = Config.Client.Advanced.Graphics.Fog.farFogFalloff.get();
|
||||
float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get();
|
||||
float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get();
|
||||
float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get();
|
||||
float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get();
|
||||
float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get();
|
||||
|
||||
|
||||
// height fog
|
||||
EDhApiFogFalloff heightFogFalloff = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get();
|
||||
EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get();
|
||||
EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get();
|
||||
|
||||
float heightFogBaseHeight = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get();
|
||||
float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get();
|
||||
float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get();
|
||||
float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get();
|
||||
float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get();
|
||||
float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get();
|
||||
|
||||
// override fog if underwater
|
||||
if (MC_RENDER.isFogStateSpecial())
|
||||
{
|
||||
// hide everything behind fog
|
||||
farFogStart = 0.0f;
|
||||
farFogEnd = 1.0f;
|
||||
farFogMin = 1.0f; // minimum fog thickness is 1 so everything renders in fog
|
||||
farFogMax = 1.0f;
|
||||
farFogDensity = 1.0f; // always render max density
|
||||
}
|
||||
|
||||
DhApiFogRenderParam fogRenderParam = new DhApiFogRenderParam(
|
||||
fogColor,
|
||||
|
||||
// far fog
|
||||
farFogFalloff,
|
||||
farFogStart, farFogEnd,
|
||||
farFogMin, farFogMax,
|
||||
farFogDensity,
|
||||
|
||||
// height fog
|
||||
heightFogFalloff,
|
||||
heightFogMixingMode, heightFogCameraDirection,
|
||||
heightFogBaseHeight,
|
||||
heightFogStart, heightFogEnd,
|
||||
heightFogMin, heightFogMax,
|
||||
heightFogDensity
|
||||
);
|
||||
|
||||
EVENT_PARAM.update(renderParams, fogRenderParam);
|
||||
return EVENT_PARAM;
|
||||
}
|
||||
|
||||
private static Color getFogColor(float partialTicks)
|
||||
{
|
||||
Color fogColor;
|
||||
|
||||
if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EDhApiFogColorMode.USE_SKY_COLOR
|
||||
// when underwater or special fogs are being used, don't use the sky color
|
||||
&& !MC_RENDER.isFogStateSpecial())
|
||||
{
|
||||
fogColor = MC_RENDER.getSkyColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
fogColor = MC_RENDER.getFogColor(partialTicks);
|
||||
}
|
||||
|
||||
return fogColor;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+26
-20
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.render.renderer;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiTransparency;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||
@@ -117,9 +118,9 @@ public class LodRenderer
|
||||
|
||||
private void renderTerrain(RenderParams renderParams, IProfilerWrapper profiler, boolean runningDeferredPass)
|
||||
{
|
||||
//====================//
|
||||
// validate rendering //
|
||||
//====================//
|
||||
//===============//
|
||||
// validate pass //
|
||||
//===============//
|
||||
//region
|
||||
|
||||
boolean deferTransparentRendering = DhApiRenderProxy.INSTANCE.getDeferTransparentRendering();
|
||||
@@ -145,7 +146,7 @@ public class LodRenderer
|
||||
//=================//
|
||||
//region
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderSetupEvent.class, renderParams);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderSetupEvent.class, renderParams.apiCopy);
|
||||
try (IProfilerWrapper.IProfileBlock terrainRender_profile = profiler.push("LOD GL setup")) // starts the new profile block for most DH rendering
|
||||
{
|
||||
|
||||
@@ -201,6 +202,8 @@ public class LodRenderer
|
||||
renderFog |= renderParams.vanillaFogEnabled;
|
||||
}
|
||||
|
||||
DhApiBeforeFogRenderEvent.EventParam fogRenderEventParam = FogRenderParamFactory.getRenderParam(renderParams);
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
@@ -212,7 +215,7 @@ public class LodRenderer
|
||||
if (!runningDeferredPass)
|
||||
{
|
||||
// needs to be fired after all the textures have been created/bound
|
||||
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderParams);
|
||||
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderParams.apiCopy);
|
||||
if (clearTextures)
|
||||
{
|
||||
this.metaRenderer.clearDhDepthAndColorTextures(renderParams);
|
||||
@@ -253,12 +256,22 @@ public class LodRenderer
|
||||
|
||||
// combined pass transparent rendering
|
||||
if (!deferTransparentRendering
|
||||
&& Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled)
|
||||
&& Config.Client.Advanced.Graphics.Quality.transparency.get() == EDhApiTransparency.COMPLETE)
|
||||
{
|
||||
profiler.popPush("LOD Transparent");
|
||||
this.renderTerrain(this.terrainRenderer, renderBufferHandler, renderParams, /*opaquePass*/ false, profiler);
|
||||
}
|
||||
|
||||
// fog
|
||||
boolean cancelFogEvent = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeFogRenderEvent.class, fogRenderEventParam);
|
||||
if (renderFog
|
||||
&& !cancelFogEvent)
|
||||
{
|
||||
profiler.popPush("LOD Fog");
|
||||
|
||||
this.fogRenderer.render(renderParams, fogRenderEventParam.getFogRenderParam());
|
||||
}
|
||||
|
||||
// far plane clip fading
|
||||
if (Config.Client.Advanced.Graphics.Quality.dhFadeFarClipPlane.get()
|
||||
&& IRIS_ACCESSOR == null)
|
||||
@@ -267,15 +280,6 @@ public class LodRenderer
|
||||
this.farFadeRenderer.render(renderParams);
|
||||
}
|
||||
|
||||
// fog
|
||||
|
||||
if (renderFog)
|
||||
{
|
||||
profiler.popPush("LOD Fog");
|
||||
|
||||
this.fogRenderer.render(renderParams);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
@@ -312,7 +316,7 @@ public class LodRenderer
|
||||
// Apply to the MC Framebuffer //
|
||||
//=============================//
|
||||
|
||||
boolean cancelApplyShader = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeApplyShaderRenderEvent.class, renderParams);
|
||||
boolean cancelApplyShader = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeApplyShaderRenderEvent.class, renderParams.apiCopy);
|
||||
if (!cancelApplyShader)
|
||||
{
|
||||
profiler.popPush("Apply to MC");
|
||||
@@ -326,17 +330,19 @@ public class LodRenderer
|
||||
// deferred rendering //
|
||||
//====================//
|
||||
|
||||
if (Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled)
|
||||
if (Config.Client.Advanced.Graphics.Quality.transparency.get() == EDhApiTransparency.COMPLETE)
|
||||
{
|
||||
profiler.popPush("LOD Transparent");
|
||||
this.renderTerrain(this.terrainRenderer, renderBufferHandler, renderParams, /*opaquePass*/ false, profiler);
|
||||
|
||||
|
||||
if (renderFog)
|
||||
boolean cancelFogEvent = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeFogRenderEvent.class, fogRenderEventParam);
|
||||
if (renderFog
|
||||
&& !cancelFogEvent)
|
||||
{
|
||||
profiler.popPush("LOD Fog");
|
||||
|
||||
this.fogRenderer.render(renderParams);
|
||||
this.fogRenderer.render(renderParams, fogRenderEventParam.getFogRenderParam());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,7 +354,7 @@ public class LodRenderer
|
||||
//================//
|
||||
|
||||
profiler.popPush("LOD cleanup");
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderCleanupEvent.class, renderParams);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderCleanupEvent.class, renderParams.apiCopy);
|
||||
|
||||
this.metaRenderer.runRenderPassCleanup(renderParams);
|
||||
}
|
||||
|
||||
+8
-6
@@ -205,21 +205,20 @@ public class RenderableBoxGroup
|
||||
this.vertexBufferContainer = this.altVertexBufferContainer;
|
||||
this.altVertexBufferContainer = temp;
|
||||
|
||||
this.vertexDataDirty = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if the vertex data is already up to date, do nothing
|
||||
if (!this.vertexDataDirty)
|
||||
// executor should always be available, if not that probably means the level is being shut down
|
||||
PriorityTaskPicker.Executor executor = ThreadPoolUtil.getRenderLoadingExecutor();
|
||||
if (executor == null || executor.isTerminated())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PriorityTaskPicker.Executor executor = ThreadPoolUtil.getRenderLoadingExecutor();
|
||||
if (executor == null || executor.isTerminated())
|
||||
// if the vertex data is already up to date, do nothing
|
||||
if (!this.vertexDataDirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -250,6 +249,9 @@ public class RenderableBoxGroup
|
||||
{
|
||||
this.altVertexBufferContainer.updateVertexData(this.uploadBoxList);
|
||||
this.altVertexBufferContainer.setState(IDhGenericObjectVertexBufferContainer.EState.READY_TO_UPLOAD);
|
||||
|
||||
// upload complete
|
||||
this.vertexDataDirty = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package com.seibel.distanthorizons.core.render.renderer.cullingFrustum;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhMat4f;
|
||||
import org.joml.FrustumIntersection;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
@@ -41,7 +41,7 @@ public class DhFrustumBounds implements IDhApiCullingFrustum
|
||||
this.worldMinY = worldMinBlockY;
|
||||
this.worldMaxY = worldMaxBlockY;
|
||||
|
||||
Matrix4f worldViewProjection = new Matrix4f(Mat4f.createJomlMatrix(dhWorldViewProjection));
|
||||
Matrix4f worldViewProjection = new Matrix4f(DhMat4f.createJomlMatrix(dhWorldViewProjection));
|
||||
this.frustum.set(worldViewProjection);
|
||||
|
||||
Matrix4fc matWorldViewProjectionInv = new Matrix4f(worldViewProjection).invert();
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.seibel.distanthorizons.core.sql;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Used to simplify handling when a database is corrupted
|
||||
* since Java doesn't have a specific exception to handle corrupted databases
|
||||
*/
|
||||
public class DbCorruptedException extends SQLException
|
||||
{
|
||||
public DbCorruptedException(String message) { super(message); }
|
||||
public DbCorruptedException(String message, Throwable cause) { super(message, cause); }
|
||||
public DbCorruptedException(Throwable cause) { super(cause); }
|
||||
|
||||
|
||||
// helper methods //
|
||||
|
||||
public static boolean isCorruptedException(SQLException e)
|
||||
{
|
||||
String message = e.getMessage().toLowerCase();
|
||||
return message.contains("sqlite_corrupt")
|
||||
|| message.contains("malformed");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,10 +19,13 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.sql.repo;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.sql.DatabaseUpdater;
|
||||
import com.seibel.distanthorizons.core.sql.DbConnectionClosedException;
|
||||
import com.seibel.distanthorizons.core.sql.DbCorruptedException;
|
||||
import com.seibel.distanthorizons.core.sql.dto.IBaseDTO;
|
||||
import com.seibel.distanthorizons.core.sql.repo.phantoms.AutoClosableTrackingWrapper;
|
||||
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||
@@ -37,6 +40,7 @@ import java.io.IOException;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -55,6 +59,7 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
||||
|
||||
private static final ConcurrentHashMap<String, Connection> CONNECTIONS_BY_CONNECTION_STRING = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<AbstractDhRepo<?, ?>, String> ACTIVE_CONNECTION_STRINGS_BY_REPO = new ConcurrentHashMap<>();
|
||||
private static final Set<String> CORRUPTED_DB_PATHS = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
|
||||
|
||||
@@ -70,6 +75,8 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
||||
|
||||
protected final KeyedLockContainer<TKey> saveLockContainer = new KeyedLockContainer<>();
|
||||
|
||||
private final AtomicBoolean databaseCorruptedRef = new AtomicBoolean(false);
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
@@ -227,7 +234,6 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
||||
finally
|
||||
{
|
||||
saveLock.unlock();
|
||||
//this.tryTriggerWalFlush();
|
||||
}
|
||||
}
|
||||
private void insert(TDTO dto)
|
||||
@@ -392,6 +398,13 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
||||
@Nullable
|
||||
public ResultSet query(@Nullable PreparedStatement statement) throws RuntimeException
|
||||
{
|
||||
// if the DB is corrupted act as if it's closed
|
||||
// that should prevent further harm
|
||||
if (this.databaseCorruptedRef.get())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// This is done so we don't have to add "if null" checks everywhere.
|
||||
// Normally this should only happen once the DB has been closed.
|
||||
if (statement == null)
|
||||
@@ -425,6 +438,33 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (DbCorruptedException.isCorruptedException(e))
|
||||
{
|
||||
// error may trigger on multiple threads at once
|
||||
synchronized (this)
|
||||
{
|
||||
// only trigger this error once per database
|
||||
if (!this.databaseCorruptedRef.getAndSet(true)
|
||||
// multiple repos may be open for the same path (client and server levels in singleplayer)
|
||||
&& CORRUPTED_DB_PATHS.add(this.databaseFile.getPath()))
|
||||
{
|
||||
LOGGER.error("DH database file at [" + this.databaseFile.getPath() + "] is corrupted. \n" +
|
||||
"All operations to this DB are disabled, DH may behave strangely if you continue playing. \n" +
|
||||
"Please leave the world and delete the corrupted database file to fix. \n" +
|
||||
"Error: [" + e.getMessage() + "]", e);
|
||||
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(
|
||||
MinecraftTextFormat.DARK_RED + MinecraftTextFormat.BOLD + "DH database is corrupted." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"DH will behave strangely if your continue playing. \n" +
|
||||
"Please leave the world and delete the corrupted database file at: \n" +
|
||||
MinecraftTextFormat.YELLOW + this.databaseFile.getPath() + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"to resolve the issue. \n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
String message = "Unexpected Query error: [" + e.getMessage() + "], for prepared statement: [" + statement + "].";
|
||||
@@ -512,6 +552,10 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
||||
LOGGER.error("Unable to close the connection ["+connectionString+"], error: ["+e.getMessage()+"]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// clear the errors so they can be re-fired if needed
|
||||
CORRUPTED_DB_PATHS.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+24
-32
@@ -479,25 +479,21 @@ public class RenderDataPointReducingList extends AbstractPhantomArrayList
|
||||
@VisibleForTesting
|
||||
public void sortBySize(int size)
|
||||
{
|
||||
ShortArrayList array = this.sortingArray;
|
||||
it.unimi.dsi.fastutil.Arrays.quickSort(
|
||||
0,
|
||||
size,
|
||||
// comparator
|
||||
(int index1, int index2) ->
|
||||
{
|
||||
return Integer.compare(
|
||||
this.getSize(this.getSortingIndex(index1)),
|
||||
this.getSize(this.getSortingIndex(index2))
|
||||
);
|
||||
},
|
||||
// swapper
|
||||
(int index1, int index2) ->
|
||||
{
|
||||
ShortArrays.swap(array.elements(), index1, index2);
|
||||
}
|
||||
0, size,
|
||||
this::sortBySizeComparator,
|
||||
this::sortBySizeSwapper
|
||||
);
|
||||
}
|
||||
// class methods to try reducing GC pressure vs in-line lambdas
|
||||
private int sortBySizeComparator(int index1, int index2)
|
||||
{
|
||||
return Integer.compare(
|
||||
this.getSize(this.getSortingIndex(index1)),
|
||||
this.getSize(this.getSortingIndex(index2))
|
||||
);
|
||||
}
|
||||
private void sortBySizeSwapper(int index1, int index2) { ShortArrays.swap(this.sortingArray.elements(), index1, index2); }
|
||||
|
||||
/**
|
||||
* sorts our {@link #sortingArray} in order of lowest-to-highest,
|
||||
@@ -506,25 +502,21 @@ public class RenderDataPointReducingList extends AbstractPhantomArrayList
|
||||
@VisibleForTesting
|
||||
public void sortByPosition(int size)
|
||||
{
|
||||
ShortArrayList array = this.sortingArray;
|
||||
it.unimi.dsi.fastutil.Arrays.quickSort(
|
||||
0,
|
||||
size,
|
||||
// comparator
|
||||
(int index1, int index2) ->
|
||||
{
|
||||
return Integer.compare(
|
||||
this.getMinY(this.getSortingIndex(index1)),
|
||||
this.getMinY(this.getSortingIndex(index2))
|
||||
);
|
||||
},
|
||||
// swapper
|
||||
(int index1, int index2) ->
|
||||
{
|
||||
ShortArrays.swap(array.elements(), index1, index2);
|
||||
}
|
||||
0, size,
|
||||
this::sortByPositionComparator,
|
||||
this::sortByPositionSwapper
|
||||
);
|
||||
}
|
||||
// class methods to try reducing GC pressure vs in-line lambdas
|
||||
private int sortByPositionComparator(int index1, int index2)
|
||||
{
|
||||
return Integer.compare(
|
||||
this.getMinY(this.getSortingIndex(index1)),
|
||||
this.getMinY(this.getSortingIndex(index2))
|
||||
);
|
||||
}
|
||||
private void sortByPositionSwapper(int index1, int index2) { ShortArrays.swap(this.sortingArray.elements(), index1, index2); }
|
||||
|
||||
/**
|
||||
* moves the smaller node to the correct position in the list,
|
||||
|
||||
@@ -27,12 +27,13 @@ import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.util.MathUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
|
||||
/**
|
||||
* This holds miscellaneous helper code
|
||||
@@ -45,6 +46,7 @@ public class RenderUtil
|
||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
|
||||
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||
|
||||
/**
|
||||
* all speeds are measured in blocks per second
|
||||
@@ -73,7 +75,7 @@ public class RenderUtil
|
||||
*
|
||||
* @param mcProjMat Minecraft's current projection matrix
|
||||
*/
|
||||
public static Mat4f createLodProjectionMatrix(DhApiMat4f mcProjMat)
|
||||
public static void setDhProjectionMatrix(DhApiMat4f updateMatrix, DhApiMat4f mcProjMat)
|
||||
{
|
||||
// in James' testing a near clip plane distance of 2 blocks is enough to allow the fragment
|
||||
// culling to take effect instead of seeing the near clip plane.
|
||||
@@ -90,18 +92,32 @@ public class RenderUtil
|
||||
float farClipDist = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||
|
||||
// Create a copy of the current matrix, so it won't be modified.
|
||||
Mat4f lodProj = new Mat4f(mcProjMat);
|
||||
updateMatrix.set(mcProjMat);
|
||||
|
||||
|
||||
// Set new far and near clip plane values.
|
||||
lodProj.setClipPlanes(nearClipDist, farClipDist);
|
||||
return lodProj;
|
||||
if (RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.FORWARD_Z)
|
||||
{
|
||||
setClipPlanes(updateMatrix, nearClipDist, farClipDist, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
setClipPlanes(updateMatrix, farClipDist, nearClipDist, true);
|
||||
}
|
||||
}
|
||||
|
||||
/** create and return a new projection matrix based on MC's modelView and projection matrices */
|
||||
public static Mat4f createLodModelViewMatrix(DhApiMat4f mcModelViewMat)
|
||||
/**
|
||||
* 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 static void setClipPlanes(DhApiMat4f matrix, float nearClip, float farClip, boolean zZeroToOne)
|
||||
{
|
||||
// nothing beyond copying needs to be done to MC's MVM currently,
|
||||
// this method is just here in case that changes in the future
|
||||
return new Mat4f(mcModelViewMat);
|
||||
// formula copied JOML's implementation to match Minecraft
|
||||
matrix.m22 = (zZeroToOne ? farClip : farClip + nearClip) / (nearClip - farClip);
|
||||
matrix.m23 = (zZeroToOne ? farClip : farClip + farClip) * nearClip / (nearClip - farClip);
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -163,7 +179,7 @@ public class RenderUtil
|
||||
|
||||
if (Config.Client.Advanced.Graphics.Culling.reduceOverdrawWithFastMovement.get())
|
||||
{
|
||||
double avgSpeed = ClientApi.INSTANCE.cameraSpeedRollingAverage.getAverage();
|
||||
double avgSpeed = ClientApi.INSTANCE.getAvgCameraSpeed();
|
||||
if (avgSpeed >= DynamicOverdraw.MIN_SPEED)
|
||||
{
|
||||
// if the player is moving fast enough,
|
||||
@@ -187,6 +203,9 @@ public class RenderUtil
|
||||
int chunkRenderDistance = MC_RENDER.getRenderDistance();
|
||||
int vanillaBlockRenderedDistance = chunkRenderDistance * LodUtil.CHUNK_WIDTH;
|
||||
|
||||
// Note: setting this to a number lower than 1.0 (ie 1 block)
|
||||
// can cause distant clouds to flash due to depth buffer precision loss.
|
||||
// This is not an issue when using Reverse Z depth.
|
||||
float nearClipPlane;
|
||||
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.util.math;
|
||||
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* An (almost) exact copy of Minecraft's 1.16.5
|
||||
* implementation of a 4x4 float matrix.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-11-2021
|
||||
*/
|
||||
public class DhMat4f extends DhApiMat4f
|
||||
{
|
||||
/**
|
||||
* A matrix containing all 0's. <br><br>
|
||||
*
|
||||
* Should not be modified. <br>
|
||||
* Can be used for comparison testing.
|
||||
*/
|
||||
public static final DhApiMat4f EMPTY = new DhApiMat4f();
|
||||
/**
|
||||
* The 4x4 identity matrix. <br><br>
|
||||
*
|
||||
* Should not be modified. <br>
|
||||
* Can be used for comparison testing.
|
||||
*/
|
||||
public static final DhApiMat4f IDENTITY = new DhApiMat4f();
|
||||
static
|
||||
{
|
||||
IDENTITY.setIdentity();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
/** all values are 0 */
|
||||
public DhMat4f() { }
|
||||
|
||||
public DhMat4f(DhApiMat4f sourceMatrix) { super(sourceMatrix); }
|
||||
|
||||
/** Expects the values of the input buffer to be in row major order (AKA rows then columns) */
|
||||
public DhMat4f(FloatBuffer buffer) { this(buffer.array()); }
|
||||
/** Expects the values of the input array to be in row major order (AKA rows then columns) */
|
||||
public DhMat4f(float[] values) { super(values); }
|
||||
|
||||
public DhMat4f(Matrix4fc sourceMatrix) { this.set(sourceMatrix); }
|
||||
|
||||
public void set(Matrix4fc sourceMatrix)
|
||||
{
|
||||
// JOML matricies are stored transposed vs DH's matricies
|
||||
this.m00 = sourceMatrix.m00();
|
||||
this.m01 = sourceMatrix.m10();
|
||||
this.m02 = sourceMatrix.m20();
|
||||
this.m03 = sourceMatrix.m30();
|
||||
|
||||
this.m10 = sourceMatrix.m01();
|
||||
this.m11 = sourceMatrix.m11();
|
||||
this.m12 = sourceMatrix.m21();
|
||||
this.m13 = sourceMatrix.m31();
|
||||
|
||||
this.m20 = sourceMatrix.m02();
|
||||
this.m21 = sourceMatrix.m12();
|
||||
this.m22 = sourceMatrix.m22();
|
||||
this.m23 = sourceMatrix.m32();
|
||||
|
||||
this.m30 = sourceMatrix.m03();
|
||||
this.m31 = sourceMatrix.m13();
|
||||
this.m32 = sourceMatrix.m23();
|
||||
this.m33 = sourceMatrix.m33();
|
||||
}
|
||||
|
||||
public static Matrix4f createJomlMatrix(DhApiMat4f matrix)
|
||||
{
|
||||
return new Matrix4f(
|
||||
matrix.m00, matrix.m10, matrix.m20, matrix.m30,
|
||||
matrix.m01, matrix.m11, matrix.m21, matrix.m31,
|
||||
matrix.m02, matrix.m12, matrix.m22, matrix.m32,
|
||||
matrix.m03, matrix.m13, matrix.m23, matrix.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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
public static DhMat4f perspective(double fov, float widthHeightRatio, float nearClipPlane, float farClipPlane)
|
||||
{
|
||||
float f = (float) (1.0D / Math.tan(fov * ((float) Math.PI / 180F) / 2.0D));
|
||||
DhMat4f matrix = new DhMat4f();
|
||||
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;
|
||||
}
|
||||
|
||||
/** originally "translate" from Minecraft's MatrixStack */
|
||||
public void multiplyTranslationMatrix(double x, double y, double z)
|
||||
{ multiply(createTranslateMatrix((float) x, (float) y, (float) z)); }
|
||||
|
||||
public static DhMat4f createScaleMatrix(float x, float y, float z)
|
||||
{
|
||||
DhMat4f matrix = new DhMat4f();
|
||||
matrix.m00 = x;
|
||||
matrix.m11 = y;
|
||||
matrix.m22 = z;
|
||||
matrix.m33 = 1.0F;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static DhMat4f createTranslateMatrix(float x, float y, float z)
|
||||
{
|
||||
DhMat4f matrix = new DhMat4f();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// Forge methods //
|
||||
//===============//
|
||||
|
||||
public void add(DhApiMat4f 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(DhApiMat4f other)
|
||||
{
|
||||
DhApiMat4f 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;
|
||||
}
|
||||
|
||||
public DhMat4f copy() { return new DhMat4f(this); }
|
||||
|
||||
|
||||
|
||||
}
|
||||
+22
-23
@@ -20,7 +20,6 @@
|
||||
package com.seibel.distanthorizons.core.util.math;
|
||||
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
|
||||
import com.seibel.distanthorizons.coreapi.util.MathUtil;
|
||||
|
||||
/**
|
||||
@@ -31,16 +30,16 @@ import com.seibel.distanthorizons.coreapi.util.MathUtil;
|
||||
* @author James Seibel
|
||||
* @version 11-18-2021
|
||||
*/
|
||||
public class Vec3d extends DhApiVec3d
|
||||
public class DhVec3d extends DhApiVec3d
|
||||
{
|
||||
public static Vec3d XNeg = new Vec3d(-1.0F, 0.0F, 0.0F);
|
||||
public static Vec3d XPos = new Vec3d(1.0F, 0.0F, 0.0F);
|
||||
public static Vec3d YNeg = new Vec3d(0.0F, -1.0F, 0.0F);
|
||||
public static Vec3d YPos = new Vec3d(0.0F, 1.0F, 0.0F);
|
||||
public static Vec3d ZNeg = new Vec3d(0.0F, 0.0F, -1.0F);
|
||||
public static Vec3d ZPos = new Vec3d(0.0F, 0.0F, 1.0F);
|
||||
public static DhVec3d XNeg = new DhVec3d(-1.0F, 0.0F, 0.0F);
|
||||
public static DhVec3d XPos = new DhVec3d(1.0F, 0.0F, 0.0F);
|
||||
public static DhVec3d YNeg = new DhVec3d(0.0F, -1.0F, 0.0F);
|
||||
public static DhVec3d YPos = new DhVec3d(0.0F, 1.0F, 0.0F);
|
||||
public static DhVec3d ZNeg = new DhVec3d(0.0F, 0.0F, -1.0F);
|
||||
public static DhVec3d ZPos = new DhVec3d(0.0F, 0.0F, 1.0F);
|
||||
|
||||
public static final Vec3d ZERO_VECTOR = new Vec3d(0.0D, 0.0D, 0.0D);
|
||||
public static final DhVec3d ZERO_VECTOR = new DhVec3d(0.0D, 0.0D, 0.0D);
|
||||
|
||||
|
||||
|
||||
@@ -48,26 +47,26 @@ public class Vec3d extends DhApiVec3d
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public Vec3d() { }
|
||||
public DhVec3d() { }
|
||||
|
||||
public Vec3d(double x, double y, double z)
|
||||
public DhVec3d(double x, double y, double z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vec3d(DhApiVec3d that)
|
||||
public DhVec3d(DhApiVec3d that)
|
||||
{
|
||||
this.x = that.x;
|
||||
this.y = that.y;
|
||||
this.z = that.z;
|
||||
}
|
||||
|
||||
public Vec3d(double[] values) { this.set(values); }
|
||||
public DhVec3d(double[] values) { this.set(values); }
|
||||
|
||||
|
||||
public Vec3d copy() { return new Vec3d(this); }
|
||||
public DhVec3d copy() { return new DhVec3d(this); }
|
||||
|
||||
|
||||
|
||||
@@ -110,29 +109,29 @@ public class Vec3d extends DhApiVec3d
|
||||
this.z += z;
|
||||
}
|
||||
|
||||
public void add(Vec3d vector)
|
||||
public void add(DhVec3d vector)
|
||||
{
|
||||
this.x += vector.x;
|
||||
this.y += vector.y;
|
||||
this.z += vector.z;
|
||||
}
|
||||
|
||||
public void subtract(Vec3d vector)
|
||||
public void subtract(DhVec3d vector)
|
||||
{
|
||||
this.x -= vector.x;
|
||||
this.y -= vector.y;
|
||||
this.z -= vector.z;
|
||||
}
|
||||
|
||||
public double dotProduct(Vec3d vector) { return this.x * vector.x + this.y * vector.y + this.z * vector.z; }
|
||||
public double dotProduct(DhVec3d vector) { return this.x * vector.x + this.y * vector.y + this.z * vector.z; }
|
||||
|
||||
public Vec3d normalize()
|
||||
public DhVec3d normalize()
|
||||
{
|
||||
double value = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||
return value < 1.0E-4D ? ZERO_VECTOR : new Vec3d(this.x / value, this.y / value, this.z / value);
|
||||
return value < 1.0E-4D ? ZERO_VECTOR : new DhVec3d(this.x / value, this.y / value, this.z / value);
|
||||
}
|
||||
|
||||
public void crossProduct(Vec3d vector)
|
||||
public void crossProduct(DhVec3d vector)
|
||||
{
|
||||
double f = this.x;
|
||||
double f1 = this.y;
|
||||
@@ -168,9 +167,9 @@ public class Vec3d extends DhApiVec3d
|
||||
+ Math.pow(a.z - b.z, 2));
|
||||
}
|
||||
|
||||
/** @see Vec3d#getSquaredDistance(DhApiVec3d, DhApiVec3d) */
|
||||
/** @see DhVec3d#getSquaredDistance(DhApiVec3d, DhApiVec3d) */
|
||||
public double getSquaredDistance(DhApiVec3d other) { return getSquaredDistance(this, other); }
|
||||
/** slightly faster version of {@link Vec3d#getDistance} */
|
||||
/** slightly faster version of {@link DhVec3d#getDistance} */
|
||||
public static double getSquaredDistance(DhApiVec3d a, DhApiVec3d b)
|
||||
{
|
||||
return Math.pow(a.x - b.x, 2)
|
||||
@@ -178,7 +177,7 @@ public class Vec3d extends DhApiVec3d
|
||||
+ Math.pow(a.z - b.z, 2);
|
||||
}
|
||||
|
||||
/** @see Vec3d#getHorizontalDistance(DhApiVec3d, DhApiVec3d) */
|
||||
/** @see DhVec3d#getHorizontalDistance(DhApiVec3d, DhApiVec3d) */
|
||||
public double getHorizontalDistance(DhApiVec3d other) { return getHorizontalDistance(this, other); }
|
||||
/** Gets the distance between points A and B, ignoring Y height. */
|
||||
public static double getHorizontalDistance(DhApiVec3d a, DhApiVec3d b)
|
||||
+10
-10
@@ -29,29 +29,29 @@ import com.seibel.distanthorizons.coreapi.util.MathUtil;
|
||||
* @author James Seibel
|
||||
* @version 11-11-2021
|
||||
*/
|
||||
public class Vec3f extends DhApiVec3f
|
||||
public class DhVec3f extends DhApiVec3f
|
||||
{
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public Vec3f() { this(0,0,0); }
|
||||
public DhVec3f() { this(0,0,0); }
|
||||
|
||||
public Vec3f(float x, float y, float z)
|
||||
public DhVec3f(float x, float y, float z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vec3f(DhApiVec3f pos)
|
||||
public DhVec3f(DhApiVec3f pos)
|
||||
{
|
||||
this.x = pos.x;
|
||||
this.y = pos.y;
|
||||
this.z = pos.z;
|
||||
}
|
||||
|
||||
public Vec3f(Vec3d pos)
|
||||
public DhVec3f(DhVec3d pos)
|
||||
{
|
||||
this.x = (float) pos.x;
|
||||
this.y = (float) pos.y;
|
||||
@@ -93,21 +93,21 @@ public class Vec3f extends DhApiVec3f
|
||||
this.z += z;
|
||||
}
|
||||
|
||||
public void add(Vec3f vector)
|
||||
public void add(DhVec3f vector)
|
||||
{
|
||||
this.x += vector.x;
|
||||
this.y += vector.y;
|
||||
this.z += vector.z;
|
||||
}
|
||||
|
||||
public void subtract(Vec3f vector)
|
||||
public void subtract(DhVec3f 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; }
|
||||
public float dotProduct(DhVec3f vector) { return this.x * vector.x + this.y * vector.y + this.z * vector.z; }
|
||||
|
||||
/** @return true if normalization had to be done */
|
||||
public boolean normalize()
|
||||
@@ -127,7 +127,7 @@ public class Vec3f extends DhApiVec3f
|
||||
}
|
||||
}
|
||||
|
||||
public void crossProduct(Vec3f vector)
|
||||
public void crossProduct(DhVec3f vector)
|
||||
{
|
||||
float f = this.x;
|
||||
float f1 = this.y;
|
||||
@@ -167,6 +167,6 @@ public class Vec3f extends DhApiVec3f
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vec3f copy() { return new Vec3f(this.x, this.y, this.z); }
|
||||
public DhVec3f copy() { return new DhVec3f(this.x, this.y, this.z); }
|
||||
|
||||
}
|
||||
+18
-18
@@ -29,27 +29,27 @@ import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
|
||||
* @author James Seibel
|
||||
* @version 2022-11-19
|
||||
*/
|
||||
public class Vec3i extends DhApiVec3i // extends the API object so it can be returned through the API
|
||||
public class DhVec3i extends DhApiVec3i // extends the API object so it can be returned through the API
|
||||
{
|
||||
public static Vec3i XNeg = new Vec3i(-1, 0, 0);
|
||||
public static Vec3i XPos = new Vec3i(1, 0, 0);
|
||||
public static Vec3i YNeg = new Vec3i(0, -1, 0);
|
||||
public static Vec3i YPos = new Vec3i(0, 1, 0);
|
||||
public static Vec3i ZNeg = new Vec3i(0, 0, -1);
|
||||
public static Vec3i ZPos = new Vec3i(0, 0, 1);
|
||||
public static DhVec3i XNeg = new DhVec3i(-1, 0, 0);
|
||||
public static DhVec3i XPos = new DhVec3i(1, 0, 0);
|
||||
public static DhVec3i YNeg = new DhVec3i(0, -1, 0);
|
||||
public static DhVec3i YPos = new DhVec3i(0, 1, 0);
|
||||
public static DhVec3i ZNeg = new DhVec3i(0, 0, -1);
|
||||
public static DhVec3i ZPos = new DhVec3i(0, 0, 1);
|
||||
|
||||
// x,y,z variables are handled in the parent object
|
||||
|
||||
|
||||
|
||||
public Vec3i()
|
||||
public DhVec3i()
|
||||
{
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
}
|
||||
|
||||
public Vec3i(int x, int y, int z)
|
||||
public DhVec3i(int x, int y, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -93,14 +93,14 @@ public class Vec3i extends DhApiVec3i // extends the API object so it can be ret
|
||||
this.z += z;
|
||||
}
|
||||
|
||||
public void add(Vec3i vector)
|
||||
public void add(DhVec3i vector)
|
||||
{
|
||||
this.x += vector.x;
|
||||
this.y += vector.y;
|
||||
this.z += vector.z;
|
||||
}
|
||||
|
||||
public void subtract(Vec3i vector)
|
||||
public void subtract(DhVec3i vector)
|
||||
{
|
||||
this.x -= vector.x;
|
||||
this.y -= vector.y;
|
||||
@@ -116,7 +116,7 @@ public class Vec3i extends DhApiVec3i // extends the API object so it can be ret
|
||||
return (xAdd * xAdd) + (yAdd * yAdd) + (zAdd * zAdd);
|
||||
}
|
||||
|
||||
public int distManhattan(Vec3i otherVec)
|
||||
public int distManhattan(DhVec3i otherVec)
|
||||
{
|
||||
float xSub = Math.abs(otherVec.x - this.x);
|
||||
float ySub = Math.abs(otherVec.y - this.y);
|
||||
@@ -125,30 +125,30 @@ public class Vec3i extends DhApiVec3i // extends the API object so it can be ret
|
||||
}
|
||||
|
||||
/** inner product */
|
||||
public float dotProduct(Vec3i vector)
|
||||
public float dotProduct(DhVec3i vector)
|
||||
{
|
||||
return (this.x * vector.x) + (this.y * vector.y) + (this.z * vector.z);
|
||||
}
|
||||
|
||||
/** Cross product */
|
||||
public Vec3i cross(Vec3i otherVec)
|
||||
public DhVec3i cross(DhVec3i otherVec)
|
||||
{
|
||||
return new Vec3i(
|
||||
return new DhVec3i(
|
||||
(this.y * otherVec.z) - (this.z * otherVec.y),
|
||||
(this.z * otherVec.x) - (this.x * otherVec.z),
|
||||
(this.x * otherVec.y) - (this.y * otherVec.x));
|
||||
}
|
||||
|
||||
public Vec3i copy()
|
||||
public DhVec3i copy()
|
||||
{
|
||||
return new Vec3i(this.x, this.y, this.z);
|
||||
return new DhVec3i(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Forge start
|
||||
public Vec3i(int[] values) { this.set(values); }
|
||||
public DhVec3i(int[] values) { this.set(values); }
|
||||
|
||||
public void set(int[] values)
|
||||
{
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.util.math;
|
||||
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* An (almost) exact copy of Minecraft's 1.16.5
|
||||
* implementation of a 4x4 float matrix.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-11-2021
|
||||
*/
|
||||
public class Mat4f extends DhApiMat4f
|
||||
{
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public Mat4f() { /* all values are 0 */ }
|
||||
|
||||
public Mat4f(DhApiMat4f sourceMatrix) { super(sourceMatrix); }
|
||||
|
||||
/** Expects the values of the input buffer to be in row major order (AKA rows then columns) */
|
||||
public Mat4f(FloatBuffer buffer) { this(buffer.array()); }
|
||||
/** Expects the values of the input array to be in row major order (AKA rows then columns) */
|
||||
public Mat4f(float[] values) { super(values); }
|
||||
|
||||
public Mat4f(Matrix4fc sourceMatrix) { this(convertJomlMatrixToArray(sourceMatrix)); }
|
||||
private static float[] convertJomlMatrixToArray(Matrix4fc sourceMatrix)
|
||||
{
|
||||
FloatBuffer buffer = FloatBuffer.allocate(16);
|
||||
|
||||
buffer.put(bufferIndex(0, 0), sourceMatrix.m00());
|
||||
buffer.put(bufferIndex(0, 1), sourceMatrix.m01());
|
||||
buffer.put(bufferIndex(0, 2), sourceMatrix.m02());
|
||||
buffer.put(bufferIndex(0, 3), sourceMatrix.m03());
|
||||
|
||||
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();
|
||||
}
|
||||
private static int bufferIndex(int xIndex, int zIndex) { return (zIndex * 4) + xIndex; }
|
||||
|
||||
|
||||
public void store(FloatBuffer floatBuffer)
|
||||
{
|
||||
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 static Matrix4f createJomlMatrix(DhApiMat4f matrix)
|
||||
{
|
||||
return new Matrix4f(
|
||||
matrix.m00, matrix.m10, matrix.m20, matrix.m30,
|
||||
matrix.m01, matrix.m11, matrix.m21, matrix.m31,
|
||||
matrix.m02, matrix.m12, matrix.m22, matrix.m32,
|
||||
matrix.m03, matrix.m13, matrix.m23, matrix.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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/** originally "translate" from Minecraft's MatrixStack */
|
||||
public void multiplyTranslationMatrix(double x, double y, double z)
|
||||
{ multiply(createTranslateMatrix((float) x, (float) y, (float) z)); }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// Forge methods //
|
||||
//===============//
|
||||
|
||||
public void set(DhApiMat4f mat)
|
||||
{
|
||||
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(DhApiMat4f 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(DhApiMat4f other)
|
||||
{
|
||||
DhApiMat4f 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;
|
||||
}
|
||||
|
||||
public Mat4f copy() { return new Mat4f(this); }
|
||||
|
||||
}
|
||||
+2
-2
@@ -60,7 +60,7 @@ public class ThreadPoolUtil
|
||||
public static PriorityTaskPicker.Executor getWorldGenExecutor() { return worldGenThreadPool; }
|
||||
|
||||
public static final String CLEANUP_THREAD_NAME = "Cleanup";
|
||||
private static final ThreadPoolExecutor cleanupThreadPool = ThreadUtil.makeSingleThreadPool(CLEANUP_THREAD_NAME);
|
||||
private static final ThreadPoolExecutor cleanupThreadPool = ThreadUtil.makeSingleDaemonThreadPool(CLEANUP_THREAD_NAME);
|
||||
/** not null since cleanup always needs to be run even when DH has been shut down */
|
||||
@NotNull
|
||||
public static ThreadPoolExecutor getCleanupExecutor() { return cleanupThreadPool; }
|
||||
@@ -170,7 +170,7 @@ public class ThreadPoolUtil
|
||||
*/
|
||||
public static boolean worldGenThreadsCanRun()
|
||||
{
|
||||
double cameraSpeed = ClientApi.INSTANCE.cameraSpeedRollingAverage.getAverage();
|
||||
double cameraSpeed = ClientApi.INSTANCE.getAvgCameraSpeed();
|
||||
// stop these threads if moving a little bit slower than max elytra speed
|
||||
double maxAllowedSpeed = (LodUtil.ROCKET_ELYTRA_SPEED_IN_BLOCKS_PER_SEC - 10.0);
|
||||
if (cameraSpeed > maxAllowedSpeed)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
|
||||
import com.seibel.distanthorizons.core.file.structure.LocalSaveStructure;
|
||||
import com.seibel.distanthorizons.core.level.AbstractDhServerLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
@@ -8,6 +9,7 @@ import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerStateManag
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -138,6 +140,7 @@ public abstract class AbstractDhServerWorld<TDhServerLevel extends AbstractDhSer
|
||||
if (serverLevelWrapper != null)
|
||||
{
|
||||
serverLevelWrapper.onUnload();
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(serverLevelWrapper));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,14 +19,18 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.level.DhClientServerLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@@ -34,7 +38,18 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLevel> implements IDhClientWorld
|
||||
{
|
||||
private final Set<DhClientServerLevel> dhLevels = Collections.synchronizedSet(new HashSet<>());
|
||||
/**
|
||||
* Having a set of level wrappers is done to handle an issue where the client
|
||||
* level would get unloaded when jumping back and forth between dimensions. <br><br>
|
||||
*
|
||||
* We might have more than one {@link ILevelWrapper} pointing to the same {@link IDhLevel}
|
||||
* since they're not immediately unloaded, and we don't want to unload the {@link IDhLevel}
|
||||
* until all the {@link ILevelWrapper} for that {@link IDhLevel} have been unloaded.
|
||||
* Any stale {@link IDhLevel} references should disappear on their own after about
|
||||
* 30 seconds or so thanks to the automatic cleanup.
|
||||
*/
|
||||
private final Map<DhClientServerLevel, Set<ILevelWrapper>> clientLevelWrapperSetByDhLevel
|
||||
= Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
private final Timer clientTickTimer = TimerUtil.CreateTimer("ClientTickTimer");
|
||||
|
||||
@@ -47,14 +62,14 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
||||
public DhClientServerWorld()
|
||||
{
|
||||
super(EWorldEnvironment.CLIENT_SERVER);
|
||||
LOGGER.info("Started DhWorld of type " + this.environment);
|
||||
LOGGER.info("Started DhWorld of type [" + this.environment + "].");
|
||||
|
||||
this.clientTickTimer.scheduleAtFixedRate(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
DhClientServerWorld.this.dhLevels.forEach(DhClientServerLevel::clientTick);
|
||||
DhClientServerWorld.this.clientLevelWrapperSetByDhLevel.keySet().forEach(DhClientServerLevel::clientTick);
|
||||
}
|
||||
}, 0, IDhClientWorld.TICK_RATE_IN_MS);
|
||||
}
|
||||
@@ -75,16 +90,22 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
||||
try
|
||||
{
|
||||
DhClientServerLevel level = new DhClientServerLevel(this.saveStructure, (IServerLevelWrapper) levelWrapper, this.getServerPlayerStateManager());
|
||||
this.dhLevels.add(level);
|
||||
this.clientLevelWrapperSetByDhLevel.computeIfAbsent(level, (clientServerLevel) -> Collections.synchronizedSet(new HashSet<>()));
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(wrapper));
|
||||
return level;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.fatal("Failed to load client-server level, error: ["+e.getMessage()+"].", e);
|
||||
|
||||
String r = MinecraftTextFormat.RED;
|
||||
String y = MinecraftTextFormat.YELLOW;
|
||||
String cf = MinecraftTextFormat.CLEAR_FORMATTING;
|
||||
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(// red text
|
||||
MinecraftTextFormat.RED + "Distant Horizons: ClientServer level loading failed." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Unable to load level ["+levelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||
r + "Distant Horizons: ClientServer level loading failed." + cf + "\n" +
|
||||
"Unable to load level ["+y+levelWrapper.getDhIdentifier()+cf+"], LODs may not appear. See log for more information.\n" +
|
||||
"");
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -92,11 +113,22 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wrapper instanceof IClientLevelWrapper)
|
||||
{
|
||||
((IClientLevelWrapper) wrapper).markAccessed();
|
||||
}
|
||||
|
||||
return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper, (levelWrapper) ->
|
||||
{
|
||||
if (!(levelWrapper instanceof IClientLevelWrapper))
|
||||
{
|
||||
LodUtil.assertNotReach("tryGetServerSideWrapper given a non-IClientLevelWrapper.");
|
||||
}
|
||||
|
||||
IClientLevelWrapper clientLevelWrapper = (IClientLevelWrapper) levelWrapper;
|
||||
IServerLevelWrapper serverLevelWrapper = clientLevelWrapper.tryGetServerSideWrapper();
|
||||
LodUtil.assertTrue(serverLevelWrapper != null);
|
||||
|
||||
if (!clientLevelWrapper.getDimensionType().equals(serverLevelWrapper.getDimensionType()))
|
||||
{
|
||||
LodUtil.assertNotReach("tryGetServerSideWrapper returned a level for a different dimension. ClientLevelWrapper dim: [" + clientLevelWrapper.getDhIdentifier() + "] ServerLevelWrapper dim: [" + serverLevelWrapper.getDhIdentifier() + "].");
|
||||
@@ -111,13 +143,14 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
||||
|
||||
level.startRenderer();
|
||||
clientLevelWrapper.setDhLevel(level);
|
||||
clientLevelWrapperSetByDhLevel.get(level).add(wrapper);
|
||||
return level;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
public boolean unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (this.dhLevelByLevelWrapper.containsKey(wrapper))
|
||||
{
|
||||
@@ -128,16 +161,33 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
||||
|
||||
DhClientServerLevel clientServerLevel = this.dhLevelByLevelWrapper.remove(wrapper);
|
||||
clientServerLevel.close();
|
||||
this.dhLevels.remove(clientServerLevel);
|
||||
this.clientLevelWrapperSetByDhLevel.remove(clientServerLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the level wrapper is a Client Level Wrapper, then that means the client side leaves the level,
|
||||
// but note that the server side still has the level loaded. So, we don't want to unload the level,
|
||||
// we just want to stop rendering it.
|
||||
this.dhLevelByLevelWrapper.remove(wrapper).stopRenderer(); // Ignore resource warning. The level obj is referenced elsewhere.
|
||||
DhClientServerLevel level = this.dhLevelByLevelWrapper.remove(wrapper); // Ignore resource warning. The level obj is referenced elsewhere.
|
||||
Set<ILevelWrapper> wrappers = clientLevelWrapperSetByDhLevel.get(level);
|
||||
if (wrappers != null)
|
||||
{
|
||||
wrappers.remove(wrapper);
|
||||
}
|
||||
|
||||
if ((wrappers == null || wrappers.isEmpty())
|
||||
&& level.isRendering())
|
||||
{
|
||||
level.stopRenderer();
|
||||
}
|
||||
wrapper.onUnload(); // We still want to unload the wrapper though.
|
||||
}
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(wrapper));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,16 +202,24 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
||||
{
|
||||
ArrayList<CompletableFuture<Void>> closeFutures = new ArrayList<>();
|
||||
|
||||
synchronized (this.dhLevels)
|
||||
synchronized (this.clientLevelWrapperSetByDhLevel)
|
||||
{
|
||||
// close each level
|
||||
for (DhClientServerLevel level : this.dhLevels)
|
||||
for (DhClientServerLevel level : this.clientLevelWrapperSetByDhLevel.keySet())
|
||||
{
|
||||
// level wrapper shouldn't be null, but just in case
|
||||
IServerLevelWrapper serverLevelWrapper = level.getServerLevelWrapper();
|
||||
if (serverLevelWrapper != null)
|
||||
{
|
||||
serverLevelWrapper.onUnload();
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(serverLevelWrapper));
|
||||
}
|
||||
|
||||
IClientLevelWrapper clientLevelWrapper = level.getClientLevelWrapper();
|
||||
if (clientLevelWrapper != null)
|
||||
{
|
||||
clientLevelWrapper.onUnload();
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(clientLevelWrapper));
|
||||
}
|
||||
|
||||
// close levels asynchronously to speed up
|
||||
|
||||
@@ -19,32 +19,52 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientPluginChannelApi;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
{
|
||||
private final ConcurrentHashMap<IClientLevelWrapper, DhClientLevel> levels;
|
||||
public final ClientOnlySaveStructure saveStructure;
|
||||
public final ClientNetworkState networkState = new ClientNetworkState();
|
||||
|
||||
|
||||
private final ConcurrentHashMap<String, DhClientLevel> clientLevelByDhId;
|
||||
/**
|
||||
* Having a set of level wrappers is done to handle an issue where the client
|
||||
* level would get unloaded when jumping back and forth between dimensions. <br><br>
|
||||
*
|
||||
* We might have more than one {@link ILevelWrapper} pointing to the same {@link IDhLevel}
|
||||
* since they're not immediately unloaded, and we don't want to unload the {@link IDhLevel}
|
||||
* until all the {@link ILevelWrapper} for that {@link IDhLevel} have been unloaded.
|
||||
* Any stale {@link IDhLevel} references should disappear on their own after about
|
||||
* 30 seconds or so thanks to the automatic cleanup.
|
||||
*/
|
||||
private final Map<String, Set<IClientLevelWrapper>> clientLevelWrapperSetByDhId = new ConcurrentHashMap<>();
|
||||
|
||||
private final Timer clientTickTimer = TimerUtil.CreateTimer("ClientTickTimer");
|
||||
|
||||
public final ClientPluginChannelApi pluginChannelApi = new ClientPluginChannelApi();
|
||||
private static final long FIRST_LEVEL_LOAD_DELAY_IN_MS = 1_000;
|
||||
/** Delay loading the first level to give the server some time to respond with level to actually load */
|
||||
private long allowLoadingLevelsAfter = 0;
|
||||
private final Set</* ClientLevel */ Object> levelInitRequestedClientLevels = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>()));
|
||||
|
||||
|
||||
//==============//
|
||||
@@ -56,16 +76,19 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
super(EWorldEnvironment.CLIENT_ONLY);
|
||||
|
||||
this.saveStructure = new ClientOnlySaveStructure();
|
||||
this.levels = new ConcurrentHashMap<>();
|
||||
this.clientLevelByDhId = new ConcurrentHashMap<>();
|
||||
|
||||
LOGGER.info("Started DhWorld of type " + this.environment);
|
||||
|
||||
this.pluginChannelApi.onJoinServer(networkState.getSession());
|
||||
this.networkState.sendConfigMessage();
|
||||
|
||||
this.clientTickTimer.scheduleAtFixedRate(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
DhClientWorld.this.levels.values().forEach(DhClientLevel::clientTick);
|
||||
DhClientWorld.this.clientLevelByDhId.values().forEach(DhClientLevel::clientTick);
|
||||
}
|
||||
}, 0, IDhClientWorld.TICK_RATE_IN_MS);
|
||||
}
|
||||
@@ -84,24 +107,99 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.levels.computeIfAbsent((IClientLevelWrapper) wrapper,
|
||||
(clientLevelWrapper) ->
|
||||
IClientLevelWrapper clientLevelWrapper = (IClientLevelWrapper) wrapper;
|
||||
clientLevelWrapper.markAccessed();
|
||||
DhClientLevel storedLevel = this.clientLevelByDhId.computeIfAbsent(wrapper.getDhIdentifier(),
|
||||
(key) -> createClientLevel(clientLevelWrapper)
|
||||
);
|
||||
|
||||
if (storedLevel != null
|
||||
&& storedLevel.getClientLevelWrapper() != wrapper)
|
||||
{
|
||||
unloadLevel(storedLevel.getLevelWrapper());
|
||||
storedLevel = createClientLevel(clientLevelWrapper);
|
||||
if (storedLevel != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new DhClientLevel(this.saveStructure, clientLevelWrapper, this.networkState);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.fatal("Failed to load client level, error: ["+e.getMessage()+"].", e);
|
||||
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(
|
||||
MinecraftTextFormat.RED + "Distant Horizons: Client level loading failed." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Unable to load level ["+clientLevelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
this.clientLevelByDhId.put(wrapper.getDhIdentifier(), storedLevel);
|
||||
}
|
||||
}
|
||||
return storedLevel;
|
||||
}
|
||||
private DhClientLevel createClientLevel(@NotNull IClientLevelWrapper clientLevelWrapper)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.ensureLevelKeyWhenAvailable(clientLevelWrapper))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DhClientLevel level = new DhClientLevel(this.saveStructure, clientLevelWrapper, this.networkState);
|
||||
clientLevelWrapperSetByDhId.computeIfAbsent(clientLevelWrapper.getDhIdentifier(), (dhId) -> Collections.synchronizedSet(new HashSet<>())).add(clientLevelWrapper);
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(clientLevelWrapper));
|
||||
ClientApi.INSTANCE.loadWaitingChunksForLevel(clientLevelWrapper);
|
||||
|
||||
return level;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.fatal("Failed to load client level, error: ["+e.getMessage()+"].", e);
|
||||
|
||||
String r = MinecraftTextFormat.RED;
|
||||
String y = MinecraftTextFormat.YELLOW;
|
||||
String cf = MinecraftTextFormat.CLEAR_FORMATTING;
|
||||
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(
|
||||
r + "Distant Horizons: Client level loading failed." + cf + "\n" +
|
||||
"Unable to load level ["+y+clientLevelWrapper.getDhIdentifier()+cf+"], LODs may not appear. See log for more information. \n" +
|
||||
"");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ensureLevelKeyWhenAvailable(@NotNull IClientLevelWrapper clientLevelWrapper)
|
||||
{
|
||||
if (!this.pluginChannelApi.allowLevelLoading(clientLevelWrapper))
|
||||
{
|
||||
LOGGER.debug("Client levels in this connection are managed by the server, skipping auto-load of: ["+clientLevelWrapper+"]");
|
||||
|
||||
// Instead of attempting to load themselves, send the config and wait for a server provided level key
|
||||
this.sendLevelInitRequestIfNeed(clientLevelWrapper);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (clientLevelWrapper instanceof IServerKeyedClientLevel)
|
||||
{
|
||||
this.sendLevelInitRequestIfNeed(clientLevelWrapper);
|
||||
}
|
||||
|
||||
// Make non-keyed levels wait some delay since first attempt to load anything,
|
||||
// so the server can reply to the level key request
|
||||
if (!(clientLevelWrapper instanceof IServerKeyedClientLevel))
|
||||
{
|
||||
this.sendLevelInitRequestIfNeed(clientLevelWrapper);
|
||||
|
||||
if (this.allowLoadingLevelsAfter == 0)
|
||||
{
|
||||
this.allowLoadingLevelsAfter = System.currentTimeMillis() + FIRST_LEVEL_LOAD_DELAY_IN_MS;
|
||||
}
|
||||
|
||||
return System.currentTimeMillis() >= this.allowLoadingLevelsAfter;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sendLevelInitRequestIfNeed(@NotNull IClientLevelWrapper clientLevelWrapper)
|
||||
{
|
||||
Object clientLevelObject = clientLevelWrapper.getWrappedMcObject();
|
||||
if (clientLevelObject != null
|
||||
&& this.levelInitRequestedClientLevels.add(clientLevelObject))
|
||||
{
|
||||
this.networkState.sendLevelInitRequest(clientLevelWrapper.getDimensionName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,28 +210,39 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.levels.get(wrapper);
|
||||
return this.clientLevelByDhId.get(wrapper.getDhIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.levels.values(); }
|
||||
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.clientLevelByDhId.values(); }
|
||||
@Override
|
||||
public int getLoadedLevelCount() { return this.levels.size(); }
|
||||
public int getLoadedLevelCount() { return this.clientLevelByDhId.size(); }
|
||||
|
||||
@Override
|
||||
public void unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
public boolean unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (!(wrapper instanceof IClientLevelWrapper))
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.levels.containsKey(wrapper))
|
||||
if (this.clientLevelByDhId.containsKey(wrapper.getDhIdentifier()))
|
||||
{
|
||||
LOGGER.info("Unloading level " + this.levels.get(wrapper));
|
||||
LOGGER.info("Unloading level [" + this.clientLevelByDhId.get(wrapper.getDhIdentifier()) + "].");
|
||||
wrapper.onUnload();
|
||||
this.levels.remove(wrapper).close();
|
||||
Set<IClientLevelWrapper> wrapperSet = this.clientLevelWrapperSetByDhId.get(wrapper.getDhIdentifier());
|
||||
wrapperSet.remove(wrapper);
|
||||
if (wrapperSet.isEmpty())
|
||||
{
|
||||
this.clientLevelByDhId.remove(wrapper.getDhIdentifier()).close();
|
||||
}
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(wrapper));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,15 +256,17 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
public void close()
|
||||
{
|
||||
this.networkState.close();
|
||||
this.pluginChannelApi.reset();
|
||||
|
||||
ArrayList<CompletableFuture<Void>> closeFutures = new ArrayList<>();
|
||||
for (DhClientLevel dhClientLevel : this.levels.values())
|
||||
for (DhClientLevel dhClientLevel : this.clientLevelByDhId.values())
|
||||
{
|
||||
// level wrapper shouldn't be null, but just in case
|
||||
IClientLevelWrapper clientLevelWrapper = dhClientLevel.getClientLevelWrapper();
|
||||
if (clientLevelWrapper != null)
|
||||
{
|
||||
clientLevelWrapper.onUnload();
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(clientLevelWrapper));
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +288,9 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
future.join();
|
||||
}
|
||||
|
||||
this.levels.clear();
|
||||
this.clientLevelByDhId.clear();
|
||||
this.clientLevelWrapperSetByDhId.clear();
|
||||
this.levelInitRequestedClientLevels.clear();
|
||||
this.clientTickTimer.cancel();
|
||||
LOGGER.info("Closed DhWorld of type [" + this.environment + "].");
|
||||
}
|
||||
|
||||
@@ -19,12 +19,15 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.generation.PregenManager;
|
||||
import com.seibel.distanthorizons.core.level.DhServerLevel;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -64,15 +67,22 @@ public class DhServerWorld extends AbstractDhServerWorld<DhServerLevel>
|
||||
{
|
||||
try
|
||||
{
|
||||
return new DhServerLevel(this.saveStructure, (IServerLevelWrapper) serverLevelWrapper, this.getServerPlayerStateManager());
|
||||
DhServerLevel level = new DhServerLevel(this.saveStructure, (IServerLevelWrapper) serverLevelWrapper, this.getServerPlayerStateManager());
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(wrapper));
|
||||
return level;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.fatal("Failed to load server level, error: ["+e.getMessage()+"].", e);
|
||||
|
||||
String r = MinecraftTextFormat.RED;
|
||||
String y = MinecraftTextFormat.YELLOW;
|
||||
String cf = MinecraftTextFormat.CLEAR_FORMATTING;
|
||||
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(
|
||||
MinecraftTextFormat.RED + "Distant Horizons: Server level loading failed." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Unable to load level ["+serverLevelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||
r + "Distant Horizons: Server level loading failed." + cf + "\n" +
|
||||
"Unable to load level ["+y+serverLevelWrapper.getDhIdentifier()+cf+"], LODs may not appear. See log for more information.\n" +
|
||||
"");
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -80,19 +90,22 @@ public class DhServerWorld extends AbstractDhServerWorld<DhServerLevel>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
public boolean unloadLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
if (!(wrapper instanceof IServerLevelWrapper))
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.dhLevelByLevelWrapper.containsKey(wrapper))
|
||||
{
|
||||
DhServerLevel level = this.dhLevelByLevelWrapper.get(wrapper);
|
||||
wrapper.onUnload();
|
||||
this.dhLevelByLevelWrapper.remove(wrapper).close();
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(wrapper));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -41,7 +41,6 @@ import java.util.concurrent.CompletableFuture;
|
||||
*/
|
||||
public interface IDhWorld extends Closeable
|
||||
{
|
||||
|
||||
@Nullable
|
||||
IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper);
|
||||
@Nullable
|
||||
@@ -49,6 +48,14 @@ public interface IDhWorld extends Closeable
|
||||
Iterable<? extends IDhLevel> getAllLoadedLevels();
|
||||
int getLoadedLevelCount();
|
||||
|
||||
void unloadLevel(@NotNull ILevelWrapper levelWrapper);
|
||||
/**
|
||||
* Returns
|
||||
* true if the level was unloaded,
|
||||
* false if the level isn't present in this world
|
||||
* or couldn't be unloaded for some other reason
|
||||
*/
|
||||
boolean unloadLevel(@NotNull ILevelWrapper levelWrapper);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||
|
||||
/**
|
||||
@@ -34,6 +34,6 @@ public interface IVersionConstants extends IBindable
|
||||
{
|
||||
String getMinecraftVersion();
|
||||
|
||||
EDhApiRenderApi getDefaultRenderingApi();
|
||||
EDhApiRenderingEngine getDefaultRenderingEngine();
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface IMinecraftClientWrapper extends IBindable
|
||||
{
|
||||
@@ -64,11 +65,13 @@ public interface IMinecraftClientWrapper extends IBindable
|
||||
* Returns the level the client is currently in. <br>
|
||||
* Returns null if the client isn't in a level.
|
||||
*/
|
||||
@Nullable
|
||||
IClientLevelWrapper getWrappedClientLevel();
|
||||
/**
|
||||
* Returns the level the client is currently in. <br>
|
||||
* Returns null if the client isn't in a level.
|
||||
*/
|
||||
@Nullable
|
||||
IClientLevelWrapper getWrappedClientLevel(boolean bypassLevelKeyManager);
|
||||
|
||||
|
||||
|
||||
+16
-9
@@ -22,11 +22,11 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.minecraft;
|
||||
import java.awt.Color;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.rendering.DhRenderState;
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3f;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -40,7 +40,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
public interface IMinecraftRenderWrapper extends IBindable
|
||||
{
|
||||
Vec3f getLookAtVector();
|
||||
DhVec3f getLookAtVector();
|
||||
|
||||
boolean playerHasBlindingEffect();
|
||||
|
||||
@@ -59,7 +59,14 @@ public interface IMinecraftRenderWrapper extends IBindable
|
||||
*/
|
||||
float getPartialTickTime();
|
||||
|
||||
Vec3d getCameraExactPosition();
|
||||
/**
|
||||
* When other mods are present and
|
||||
* this method is called outside the render thread
|
||||
* this may return undesirable positions.
|
||||
* (Normally this position is used to get
|
||||
* the position the player's camera).
|
||||
*/
|
||||
DhVec3d getCameraExactPosition();
|
||||
|
||||
Color getFogColor(float partialTicks);
|
||||
|
||||
@@ -75,14 +82,16 @@ public interface IMinecraftRenderWrapper extends IBindable
|
||||
|
||||
boolean mcRendersToFrameBuffer();
|
||||
boolean runningLegacyOpenGL();
|
||||
/** Returns the Graphics API Minecraft is currently using for rendering */
|
||||
EDhApiRenderingApi getMcRenderingApi();
|
||||
|
||||
/** @return -1 if no valid framebuffer is available yet */
|
||||
int getTargetFramebuffer(); // Note: Iris is now hooking onto this for DH + Iris compat, try not to change (unless we wanna deal with some annoyances)
|
||||
// Iris commit: https://github.com/IrisShaders/Iris/commit/a76a240527e93780bbcba57c09bef377419d47a7#diff-7b9ded0c79bbcdb130010373387756a28ee8d3640d522c0a5b7acd0abbfc20aeR16
|
||||
/** @return -1 if there was an issue or no texture exists */
|
||||
int getDepthTextureId();
|
||||
int getGlDepthTextureId();
|
||||
/** @return -1 if there was an issue or no texture exists */
|
||||
int getColorTextureId();
|
||||
int getGlColorTextureId();
|
||||
int getTargetFramebufferViewportWidth();
|
||||
int getTargetFramebufferViewportHeight();
|
||||
|
||||
@@ -96,8 +105,6 @@ public interface IMinecraftRenderWrapper extends IBindable
|
||||
@Nullable
|
||||
ILightMapWrapper getLightmapWrapper(@NotNull ILevelWrapper level);
|
||||
|
||||
float getShade(EDhDirection lodDirection);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+5
@@ -19,7 +19,9 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.minecraft;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -31,6 +33,9 @@ public interface IMinecraftSharedWrapper extends IBindable
|
||||
|
||||
int getPlayerCount();
|
||||
|
||||
/** If used on the client will only return a non-null object if the client is hosting a LAN server */
|
||||
@Nullable
|
||||
IServerLevelWrapper getLevelWrapper(String dimensionResourceLocation);
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -21,9 +21,7 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.misc;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
|
||||
public interface IServerPlayerWrapper extends IDhApiUnsafeWrapper
|
||||
{
|
||||
@@ -31,6 +29,6 @@ public interface IServerPlayerWrapper extends IDhApiUnsafeWrapper
|
||||
|
||||
IServerLevelWrapper getLevel();
|
||||
|
||||
Vec3d getPosition();
|
||||
DhVec3d getPosition();
|
||||
|
||||
}
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiCancelableEventParam;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AbstractImmersivePortalsAccessor implements IImmersivePortalsAccessor
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static MethodHandle isRenderingMethodHandle;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public AbstractImmersivePortalsAccessor()
|
||||
{
|
||||
LOGGER.info("Immersive Portals detected: some DH features will be disabled or may only partially function.");
|
||||
|
||||
BeforeRenderEvent event = new BeforeRenderEvent(this);
|
||||
DhApi.events.bind(DhApiBeforeRenderEvent.class, event);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// reflection handling //
|
||||
//=====================//
|
||||
//region
|
||||
|
||||
private static Class<?> getPortalRenderingClass()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName("qouteall.imm_ptl.core.render.context_management.PortalRendering");
|
||||
}
|
||||
catch (ClassNotFoundException first)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName("com.qouteall.immersive_portals.render.context_management.PortalRendering"); // 1.16
|
||||
}
|
||||
catch (ClassNotFoundException second)
|
||||
{
|
||||
RuntimeException err = new RuntimeException(first);
|
||||
err.addSuppressed(second);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// overrides //
|
||||
//===========//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public String getModName() { return "Immersive Portals"; }
|
||||
|
||||
@Override
|
||||
public boolean isRenderingPortal()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isRenderingMethodHandle == null)
|
||||
{
|
||||
isRenderingMethodHandle = MethodHandles.lookup().findStatic(
|
||||
getPortalRenderingClass(),
|
||||
"isRendering", MethodType.methodType(Boolean.TYPE)
|
||||
);
|
||||
}
|
||||
|
||||
return (boolean) isRenderingMethodHandle.invoke();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=======//
|
||||
// event //
|
||||
//=======//
|
||||
//region
|
||||
|
||||
private static class BeforeRenderEvent extends DhApiBeforeRenderEvent
|
||||
{
|
||||
@NotNull
|
||||
private final IImmersivePortalsAccessor immersivePortals;
|
||||
|
||||
|
||||
public BeforeRenderEvent(@NotNull IImmersivePortalsAccessor portalAccessor) { this.immersivePortals = portalAccessor; }
|
||||
|
||||
|
||||
@Override
|
||||
public void beforeRender(DhApiCancelableEventParam<DhApiRenderParam> event)
|
||||
{
|
||||
// needed because otherwise DH doesn't render to the level anyway
|
||||
// and will probably render the level the player is currently in instead
|
||||
if (this.immersivePortals.isRenderingPortal())
|
||||
{
|
||||
event.cancelEvent();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor;
|
||||
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.util.math.DhVec3d;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface IImmersivePortalsAccessor extends IModAccessor
|
||||
{
|
||||
/**
|
||||
* Returns true if Immersive Portals is currently rendering a portal.
|
||||
* This can be used to determine if the level currently being rendered
|
||||
* is being seen through a portal if called on the render thread.
|
||||
*/
|
||||
boolean isRenderingPortal();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the player's position for the level they're currently in.
|
||||
* <br><br>
|
||||
* Necessary since Immersive Portals messes with vanilla MC's
|
||||
* variables in order to render the camera in multiple dimensions.
|
||||
*/
|
||||
@Nullable
|
||||
DhBlockPos getActualPlayerBlockPos();
|
||||
|
||||
/**
|
||||
* Returns the player's position for the level they're currently in.
|
||||
* <br><br>
|
||||
* Necessary since Immersive Portals messes with vanilla MC's
|
||||
* variables in order to render the camera in multiple dimensions.
|
||||
*/
|
||||
@Nullable
|
||||
DhChunkPos getActualPlayerChunkPos();
|
||||
|
||||
/**
|
||||
* Returns the client level the player is currently in.
|
||||
* <br><br>
|
||||
* Necessary since Immersive Portals messes with vanilla MC's
|
||||
* variables in order to render the camera in multiple dimensions.
|
||||
*/
|
||||
@Nullable
|
||||
IClientLevelWrapper getActualClientLevelWrapper();
|
||||
|
||||
/**
|
||||
* Returns the camera position for the level the player is currently in.
|
||||
* <br><br>
|
||||
* Necessary since Immersive Portals messes with vanilla MC's
|
||||
* variables in order to render the camera in multiple dimensions.
|
||||
*/
|
||||
@Nullable
|
||||
DhVec3d getActualCameraPos();
|
||||
|
||||
|
||||
|
||||
}
|
||||
+16
-1
@@ -1,7 +1,10 @@
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.render;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
|
||||
@@ -17,7 +20,7 @@ public abstract class AbstractDhRenderApiDefinition implements IBindable
|
||||
//region
|
||||
|
||||
/** Used for debugging */
|
||||
public abstract String getApiName();
|
||||
public abstract String getEngineName();
|
||||
|
||||
private final boolean useSingleIbo = (EPlatform.get() != EPlatform.MACOS);
|
||||
/**
|
||||
@@ -29,6 +32,18 @@ public abstract class AbstractDhRenderApiDefinition implements IBindable
|
||||
*/
|
||||
public boolean useSingleIbo() { return this.useSingleIbo; }
|
||||
|
||||
public abstract EDhRenderDepth getRenderDepth();
|
||||
public abstract EDhApiRenderingApi getRenderApi();
|
||||
/**
|
||||
* Returns true if the current renderer
|
||||
* is calling the base rendering API's method calls. <br>
|
||||
* ie GL.drawArrays() for OpenGL. <Br><br>
|
||||
*
|
||||
* If DH is using Blaze3D (Mojang's rendering API)
|
||||
* this will return false.
|
||||
*/
|
||||
public abstract boolean isNativeRenderer();
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -24,11 +24,11 @@ import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBuff
|
||||
/**
|
||||
* @see LodBufferContainer
|
||||
*/
|
||||
public interface ILodContainerUniformBufferWrapper extends IUniformBufferWrapper
|
||||
public interface ILodContainerUniformBufferWrapper extends AutoCloseable
|
||||
{
|
||||
/** does nothing if the buffer has already been uploaded */
|
||||
void tryUpload(LodBufferContainer bufferContainer);
|
||||
|
||||
void createUniformData(LodBufferContainer bufferContainer);
|
||||
|
||||
void tryUpload();
|
||||
@Override void close();
|
||||
|
||||
}
|
||||
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.render.objects;
|
||||
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||
|
||||
public interface IUniformBufferWrapper extends IBindable, AutoCloseable
|
||||
{
|
||||
void upload();
|
||||
|
||||
@Override
|
||||
void close();
|
||||
|
||||
}
|
||||
+2
-1
@@ -19,12 +19,13 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass;
|
||||
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiFogRenderParam;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||
|
||||
public interface IDhFogRenderer extends IBindable
|
||||
{
|
||||
|
||||
void render(RenderParams renderParams);
|
||||
void render(RenderParams renderParams, DhApiFogRenderParam fogRenderParams);
|
||||
|
||||
}
|
||||
|
||||
-2
@@ -20,8 +20,6 @@
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass;
|
||||
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||
|
||||
public interface IDhVanillaFadeRenderer extends IBindable
|
||||
|
||||
+9
-1
@@ -20,6 +20,7 @@
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.world;
|
||||
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -29,14 +30,21 @@ import java.awt.*;
|
||||
public interface IClientLevelWrapper extends ILevelWrapper
|
||||
{
|
||||
|
||||
/** used to track when this level was last used for Immersive portals support */
|
||||
void markAccessed();
|
||||
|
||||
@Nullable
|
||||
IServerLevelWrapper tryGetServerSideWrapper();
|
||||
|
||||
int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, FullDataSourceV2 fullDataSource, IBlockStateWrapper blockState);
|
||||
default int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, FullDataSourceV2 fullDataSource, IBlockStateWrapper blockState)
|
||||
{ return this.getBlockColor(pos, biome, fullDataSource, blockState, true); }
|
||||
int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, FullDataSourceV2 fullDataSource, IBlockStateWrapper blockState, boolean allowApiOverride);
|
||||
/** @return -1 if there was a problem getting the color */
|
||||
int getDirtBlockColor();
|
||||
void clearBlockColorCache();
|
||||
|
||||
Color getCloudColor(float tickDelta);
|
||||
|
||||
float getShade(EDhDirection lodDirection);
|
||||
|
||||
}
|
||||
|
||||
@@ -28,15 +28,18 @@
|
||||
"API LOCK",
|
||||
"distanthorizons.general.disabledByApi.@tooltip":
|
||||
"This option is controlled by another mod via DH's API \nso it cannot be changed via the UI or config file.",
|
||||
|
||||
"distanthorizons.general.unsupportedMcVersion":
|
||||
"VER LOCK",
|
||||
"distanthorizons.general.unsupportedMcVersion.@tooltip":
|
||||
"DH doesn't support changing this option on this version of Minecraft. \nAny config file or API set values will be ignored.",
|
||||
|
||||
|
||||
|
||||
"distanthorizons.updater.title":
|
||||
"Distant Horizons auto updater",
|
||||
"distanthorizons.updater.text1":
|
||||
"distanthorizons.updater.updateAvailable":
|
||||
"§lNew update available!",
|
||||
"distanthorizons.updater.text2":
|
||||
"distanthorizons.updater.updateConfirmation":
|
||||
"§fDo you want to update from %s§f to %s§f?",
|
||||
"distanthorizons.updater.later":
|
||||
"Not now",
|
||||
@@ -64,7 +67,7 @@
|
||||
"distanthorizons.config.client.quickEnableRendering":
|
||||
"Enable Rendering",
|
||||
"distanthorizons.config.client.quickEnableRendering.@tooltip":
|
||||
"Determines if Distant Horizons Renders LODs.",
|
||||
"If true, Distant Horizons will render LODs beyond the vanilla render distance.",
|
||||
|
||||
"distanthorizons.config.client.quickShowWorldGenProgress":
|
||||
"Show LOD Gen/Import Progress",
|
||||
@@ -78,7 +81,7 @@
|
||||
"distanthorizons.config.client.threadPresetSetting":
|
||||
"CPU Load",
|
||||
"distanthorizons.config.client.threadPresetSetting.@tooltip":
|
||||
"Modifies how many threads Distant Horizons' will use. \n\nIncreasing this setting will improve the Distant Generator speed and LOD loading speed, \nbut will also increase CPU/memory usage and may introduce stuttering. \n\nNote: This is a CPU relative setting. \nIt should put an equal amount of strain on a 2 core CPU as a 64 core CPU.",
|
||||
"Modifies how many threads Distant Horizons' will use. \n\nIncreasing this setting will increase the Distant Generator's speed and LOD loading speed, \nbut will also increase CPU/memory usage and may introduce stuttering. \n\nNote: This is a CPU relative setting. \nIt should put an equal amount of strain on a 2 core CPU as a 64 core CPU.",
|
||||
|
||||
"distanthorizons.config.client.optionsButton":
|
||||
"Show The Options Button",
|
||||
@@ -111,33 +114,29 @@
|
||||
"distanthorizons.config.client.advanced.graphics.quality.lodChunkRenderDistanceRadius":
|
||||
"LOD Chunk Render Distance Radius",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.lodChunkRenderDistanceRadius.@tooltip":
|
||||
"Distant Horizons' render distance, measured in chunks. \n\nNote: this is a best effort number. \nThe render distance may be above or below this number \ndepending on your other graphic settings.",
|
||||
"Distant Horizons' render distance, measured in chunks. \n\nNote: this is a best effort number. \nThe actual render distance may be above or below this number \ndepending on your other graphic settings.",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.horizontalQuality":
|
||||
"LOD Dropoff Distance",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.horizontalQuality.@tooltip":
|
||||
"How far apart drops in quality are.\n\nHigher settings will increase the distance between drops\nbut will increase memory and GPU usage.",
|
||||
"This indicates how far apart drops in LOD quality are.\n\nHigher settings will increase the distance between drops\nbut will increase memory and GPU usage.",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.maxHorizontalResolution":
|
||||
"Max Horizontal Resolution",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.maxHorizontalResolution.@tooltip":
|
||||
"The maximum detail LODs are rendered at.\n\n§6Fastest:§r Chunk\n§6Fanciest:§r Block",
|
||||
"The maximum detail LODs can render at.\n\n§6Fastest:§r Chunk\n§6Fanciest:§r Block",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.verticalQuality":
|
||||
"Vertical Quality",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.verticalQuality.@tooltip":
|
||||
"How well LODs represent overhangs, caves, cliffsides, etc.\n\nHigher options will increase memory and GPU usage.",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.useCameraPositionForQualityDropOff":
|
||||
"Use Camera Pos for Quality Drop-Off",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.useCameraPositionForQualityDropOff.@tooltip":
|
||||
"If true DH will try to use the camera position when \ndetermining LOD quality drop-off. \nIf false DH will use the player's position. \n\nEnabling helps free-cam mods render correctly. \nDisabling helps multi-camera mods render correctly (ie Immersive Portals or camera mods).",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.horizontalScale":
|
||||
"Horizontal Scale",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.horizontalScale.@tooltip":
|
||||
"How quickly LODs drop off in quality.\n\nLarger numbers will improve how distant terrain looks\nbut will increase memory and GPU usage.",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.transparency":
|
||||
"Transparency",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.blocksToIgnore":
|
||||
"Blocks To Ignore",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.blocksToIgnore.@tooltip":
|
||||
"Defines the types of blocks to ignore when generating LODs.",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.tintWithAvoidedBlocks":
|
||||
"Tint With Avoided Blocks",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.tintWithAvoidedBlocks.@tooltip":
|
||||
"§4Note: makes snow, carpet, and trapdoors look really bad§r\nShould the blocks underneath avoided blocks gain the color of the avoided block?\n§6True:§r a red flower on grass will tint the grass below it red\n§6False:§r skipped blocks will not change color of surface below them",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.lodShading":
|
||||
"LOD Shading",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.lodShading.@tooltip":
|
||||
@@ -157,7 +156,7 @@
|
||||
"distanthorizons.config.client.advanced.graphics.quality.dhFadeFarClipPlane":
|
||||
"Fade Before Far Clip Plane",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.dhFadeFarClipPlane.@tooltip":
|
||||
"Should DH fade out before reaching the far plane? \nThis is helpful to prevent DH clouds from cutting off in the distance.",
|
||||
"Should DH fade out before reaching the far clip plane? \nThis is helpful to prevent DH clouds from cutting off in the distance.",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.brightnessMultiplier":
|
||||
"Brightness Multiplier",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.brightnessMultiplier.@tooltip":
|
||||
@@ -169,7 +168,7 @@
|
||||
"distanthorizons.config.client.advanced.graphics.quality.lodBiomeBlending":
|
||||
"Biome Blending",
|
||||
"distanthorizons.config.client.advanced.graphics.quality.lodBiomeBlending.@tooltip":
|
||||
"This is the same as vanilla Biome Blending settings for LOD area. \n\nNote that anything other than '0' will greatly effect Lod building time\nand increase triangle count. The cost on chunk generation speed is also \nquite large if set to too high.\n\n'0' equals to Vanilla Biome Blending of '1x1', \n'1' equals to Vanilla Biome Blending of '3x3', \n'2' equals to Vanilla Biome Blending of '5x5'... \n",
|
||||
"This is the same as vanilla Biome Blending settings for LOD area. \n\nNote: anything above '0' will slow down LOD loading time.\n\n'0' equals to Vanilla Biome Blending of '1x1', \n'1' equals to Vanilla Biome Blending of '3x3', \n'2' equals to Vanilla Biome Blending of '5x5'... \n",
|
||||
|
||||
|
||||
|
||||
@@ -185,13 +184,13 @@
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableGenericRendering":
|
||||
"Enable Generic Rendering",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableGenericRendering.@tooltip":
|
||||
"If true non terrain objects will be rendered in DH's terrain. \nThis includes beacon beams and clouds.",
|
||||
"If true non terrain objects will be rendered by DH. \ni.e. beacon beams and clouds.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableBeaconRendering":
|
||||
"Enable Beacon Rendering",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.beaconRenderHeight":
|
||||
"Beacon render height",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.beaconRenderHeight.@tooltip":
|
||||
"Sets the maximum height at which beacons will render. \nThis will only affect new beacons coming into LOD render distance. \nBeacons currently visible in LOD chunks will not be affected.",
|
||||
"Sets the maximum height beacons will render up to. Requires a world re-load to take affect.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.expandDistantBeacons":
|
||||
"Expand Distant Beacons",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.expandDistantBeacons.@tooltip":
|
||||
@@ -203,18 +202,13 @@
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableCloudRendering.@tooltip":
|
||||
"If true LOD clouds will be rendered.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.dimensionEnabledCloudRenderingCsv":
|
||||
"Enable Cloud Rendering",
|
||||
"Cloud Enabled Dimension CSV List",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.dimensionEnabledCloudRenderingCsv.@tooltip":
|
||||
"A comma separated separated list of dimension resource locations where DH clouds will render. \n\nExample: \"minecraft:overworld,minecraft:the_end\" \n\nChanges will only be seen when the world is re-loaded.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableUnexploredFogRendering":
|
||||
"Enable Unexplored Fog Rendering",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableUnexploredFogRendering.@tooltip":
|
||||
"If true unexplored/ungenerated LODs will be rendered as large dark gray boxes.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableInstancedRendering":
|
||||
"Enable Instanced Rendering",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableInstancedRendering.@tooltip":
|
||||
"Can be disabled to use much slower but more compatible direct rendering. \nDisabling this can be used to fix some crashes on Mac.",
|
||||
|
||||
"A comma separated separated list of dimension resource locations where DH clouds will render. \n\nExample: \"minecraft:overworld,minecraft:the_end\" \n\nChanges require a world re-load.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableMultiLayerClouds":
|
||||
"Enable Multi-layer clouds",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableMultiLayerClouds.@tooltip":
|
||||
"False = DH will render a single layer of clouds, like vanilla Minecraft. \nTrue = DH will render 3 layers of clouds at different heights.",
|
||||
|
||||
|
||||
"distanthorizons.config.client.advanced.graphics.fog":
|
||||
@@ -373,6 +367,14 @@
|
||||
"Water Surface Replacement",
|
||||
"distanthorizons.config.client.advanced.graphics.culling.waterSurfaceBlockReplacementCsv.@tooltip":
|
||||
"A comma separated list of block resource locations that will be removed \nwhen on top of water.",
|
||||
"distanthorizons.config.client.advanced.graphics.culling.blocksToIgnore":
|
||||
"Blocks To Ignore",
|
||||
"distanthorizons.config.client.advanced.graphics.culling.blocksToIgnore.@tooltip":
|
||||
"Defines what blocks should be rendered as LODs. \n\n§NONE:§r Include all blocks in the LODs\n§NON_COLLIDING:§r Only render solid blocks in the LODs (tall grass, torches, etc. will be ignored)",
|
||||
"distanthorizons.config.client.advanced.graphics.culling.tintWithAvoidedBlocks":
|
||||
"Tint With Avoided Blocks",
|
||||
"distanthorizons.config.client.advanced.graphics.culling.tintWithAvoidedBlocks.@tooltip":
|
||||
"§4Note: makes snow, carpet, and trapdoors look really bad§r\nShould the blocks underneath avoided blocks gain the color of the avoided block?\n§6True:§r a red flower on grass will tint the grass below it red\n§6False:§r skipped blocks will not change color of surface below them",
|
||||
|
||||
"distanthorizons.config.client.advanced.graphics.overrideVanillaGraphicsSettings":
|
||||
"Override Vanilla Settings",
|
||||
@@ -391,10 +393,10 @@
|
||||
"distanthorizons.config.client.advanced.graphics.experimental.ignoredDimensionCsv":
|
||||
"Ignored Dimension CSV",
|
||||
"distanthorizons.config.client.advanced.graphics.experimental.ignoredDimensionCsv.@tooltip":
|
||||
"A comma separated list of dimension resource locations where DH won't render. Example: \"minecraft:the_nether,minecraft:the_end\" \n\nNote: \nSome DH settings will be disabled and/or changed to improve \nvisuals when DH rendering is disabled.",
|
||||
"distanthorizons.config.client.advanced.graphics.experimental.renderingApi":
|
||||
"Rendering API",
|
||||
"distanthorizons.config.client.advanced.graphics.experimental.renderingApi.@tooltip":
|
||||
"A comma separated list of dimension resource locations where DH won't render. Example: \"minecraft:the_nether,minecraft:the_end\" \n\nFor Minecraft 1.12.2 and older:\nOpen the F3 screen and copy the dimension name shown in yellow.\n\nNote: \nSome DH settings will be disabled and/or changed to improve \nvisuals when DH rendering is disabled.",
|
||||
"distanthorizons.config.client.advanced.graphics.experimental.renderingEngine":
|
||||
"Rendering Engine",
|
||||
"distanthorizons.config.client.advanced.graphics.experimental.renderingEngine.@tooltip":
|
||||
"Requires a restart to change.",
|
||||
|
||||
|
||||
@@ -502,14 +504,6 @@
|
||||
"OpenGL Error Handling Mode",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.glErrorHandlingMode.@tooltip":
|
||||
"Defines how OpenGL errors are handled. \n Requires rebooting Minecraft to apply. \nMay incorrectly catch OpenGL errors thrown by other mods.",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.validateBufferIdsBeforeRendering":
|
||||
"Validate Buffer IDs Before Rendering",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.validateBufferIdsBeforeRendering.@tooltip":
|
||||
"Massively reduces FPS. \nShould only be used if mysterious EXCEPTION_ACCESS_VIOLATION crashes are happening in DH's rendering code and you're attempting to troubleshoot it.",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.glUploadMode":
|
||||
"Uploade Mode",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.glUploadMode.@tooltip":
|
||||
"Only for debugging",
|
||||
|
||||
|
||||
|
||||
@@ -655,14 +649,6 @@
|
||||
"Disable Unchanged Chunk Check",
|
||||
"distanthorizons.config.common.lodBuilding.disableUnchangedChunkCheck.@tooltip":
|
||||
"Disabling this check may fix issues where LODs aren't updated after\nblocks have been changed.\n",
|
||||
"distanthorizons.config.common.lodBuilding.pullLightingForPregeneratedChunks":
|
||||
"Pull Lighting For Pre-generated Chunks",
|
||||
"distanthorizons.config.common.lodBuilding.pullLightingForPregeneratedChunks.@tooltip":
|
||||
"If true LOD generation for pre-existing chunks will attempt to pull the lighting data \nsaved in Minecraft's Region files. \nIf false DH will pull in chunks without lighting and re-light them. \n\nSetting this to true will result in faster LOD generation \nfor already generated worlds, but is broken by most lighting mods. \n\nSet this to false if LODs are black.",
|
||||
"distanthorizons.config.common.lodBuilding.assumePreExistingChunksAreFinished":
|
||||
"Assume Pre-Existing Chunks Are Finished",
|
||||
"distanthorizons.config.common.lodBuilding.assumePreExistingChunksAreFinished.@tooltip":
|
||||
"Setting this to true may solve some issues when using DH with a pre-generated world.",
|
||||
"distanthorizons.config.common.lodBuilding.dataCompression":
|
||||
"Data Compression",
|
||||
"distanthorizons.config.common.lodBuilding.dataCompression.@tooltip":
|
||||
@@ -671,12 +657,6 @@
|
||||
"Lossy World Compression",
|
||||
"distanthorizons.config.common.lodBuilding.worldCompression.@tooltip":
|
||||
"How should block data be compressed when creating LOD data? \nThis setting will only affect new or updated LOD data, \nany data already generated when this setting is changed will be \nunaffected until it is modified or re-loaded. \n\nMost Accurate: Merge Same Blocks \nHighest Compression: Visually Equal",
|
||||
"distanthorizons.config.common.lodBuilding.recalculateChunkHeightmaps":
|
||||
"Recalculate Chunk Heightmaps",
|
||||
"distanthorizons.config.common.lodBuilding.recalculateChunkHeightmaps.@tooltip":
|
||||
"True: Recalculate chunk height maps before chunks can be used by DH. This can fix problems with worlds created by external tools. \nFalse: Assume any height maps handled by Minecraft are correct. \n\nFastest: False\nMost Compatible: True",
|
||||
"distanthorizons.config.common.lodBuilding.showMigrationChatWarning":
|
||||
"Log Migration In Chat",
|
||||
|
||||
|
||||
"distanthorizons.config.common.lodBuilding.experimental":
|
||||
@@ -718,8 +698,6 @@
|
||||
|
||||
"distanthorizons.config.common.logging.logWorldGenEventToFile":
|
||||
"World Gen Events - File",
|
||||
"distanthorizons.config.common.logging.logWorldGenPerformanceToFile":
|
||||
"World Gen Performance - File",
|
||||
"distanthorizons.config.common.logging.logWorldGenChunkLoadEventToFile":
|
||||
"World Gen Load Events - File",
|
||||
"distanthorizons.config.common.logging.logRendererEventToFile":
|
||||
@@ -751,10 +729,10 @@
|
||||
"Show Slow World Gen Warnings",
|
||||
"distanthorizons.config.common.logging.warning.showModCompatibilityWarningsOnStartup":
|
||||
"Show Mod Compatibility Warnings",
|
||||
"distanthorizons.config.common.logging.warning.showGarbageCollectorWarning":
|
||||
"Show Garbage Collector Warning",
|
||||
"distanthorizons.config.common.logging.warning.logGarbageCollectorWarning":
|
||||
"Log Garbage Collector Warning",
|
||||
"distanthorizons.config.common.logging.warning.showGarbageCollectorWarning":
|
||||
"Show Garbage Collector Warning",
|
||||
|
||||
|
||||
|
||||
@@ -919,18 +897,9 @@
|
||||
|
||||
"distanthorizons.config.enum.EDhApiTransparency.DISABLED":
|
||||
"Disabled",
|
||||
"distanthorizons.config.enum.EDhApiTransparency.FAKE":
|
||||
"Fake",
|
||||
"distanthorizons.config.enum.EDhApiTransparency.COMPLETE":
|
||||
"Complete",
|
||||
|
||||
"distanthorizons.config.enum.EDhApiFogDrawMode.USE_OPTIFINE_SETTING":
|
||||
"Use modded settings",
|
||||
"distanthorizons.config.enum.EDhApiFogDrawMode.FOG_ENABLED":
|
||||
"Enabled",
|
||||
"distanthorizons.config.enum.EDhApiFogDrawMode.FOG_DISABLED":
|
||||
"Disabled",
|
||||
|
||||
"distanthorizons.config.enum.EDhApiFogColorMode.USE_WORLD_FOG_COLOR":
|
||||
"Use world fog",
|
||||
"distanthorizons.config.enum.EDhApiFogColorMode.USE_SKY_COLOR":
|
||||
@@ -977,13 +946,6 @@
|
||||
"distanthorizons.config.enum.EDhApiHeightFogDirection.ABOVE_AND_BELOW_SET_HEIGHT":
|
||||
"Above And Below Set Height",
|
||||
|
||||
"distanthorizons.config.enum.EDhApiVanillaOverdraw.NEVER":
|
||||
"Never",
|
||||
"distanthorizons.config.enum.EDhApiVanillaOverdraw.DYNAMIC":
|
||||
"Dynamic",
|
||||
"distanthorizons.config.enum.EDhApiVanillaOverdraw.ALWAYS":
|
||||
"Always",
|
||||
|
||||
"distanthorizons.config.enum.EDhApiDistantGeneratorMode.NONE":
|
||||
"1. Existing Only",
|
||||
"distanthorizons.config.enum.EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY":
|
||||
@@ -1067,13 +1029,6 @@
|
||||
"distanthorizons.config.enum.EDhApiGLErrorHandlingMode.LOG_THROW":
|
||||
"Log-Throw",
|
||||
|
||||
"distanthorizons.config.enum.EDhApiGlProfileMode.CORE":
|
||||
"Core",
|
||||
"distanthorizons.config.enum.EDhApiGlProfileMode.COMPAT":
|
||||
"Compat",
|
||||
"distanthorizons.config.enum.EDhApiGlProfileMode.ANY":
|
||||
"Any",
|
||||
|
||||
"distanthorizons.config.enum.EDhApiLoggerLevel.ALL":
|
||||
"1. All",
|
||||
"distanthorizons.config.enum.EDhApiLoggerLevel.DEBUG":
|
||||
@@ -1088,19 +1043,6 @@
|
||||
"6. Disabled",
|
||||
|
||||
|
||||
"distanthorizons.config.enum.EDhApiGpuUploadMethod.AUTO":
|
||||
"Auto",
|
||||
"distanthorizons.config.enum.EDhApiGpuUploadMethod.NONE":
|
||||
"None",
|
||||
"distanthorizons.config.enum.EDhApiGpuUploadMethod.BUFFER_STORAGE":
|
||||
"Buffer storage",
|
||||
"distanthorizons.config.enum.EDhApiGpuUploadMethod.SUB_DATA":
|
||||
"Sub data",
|
||||
"distanthorizons.config.enum.EDhApiGpuUploadMethod.BUFFER_MAPPING":
|
||||
"Buffer mapping",
|
||||
"distanthorizons.config.enum.EDhApiGpuUploadMethod.DATA":
|
||||
"Data",
|
||||
|
||||
"distanthorizons.config.enum.EDhApiLodShading.AUTO":
|
||||
"Auto",
|
||||
"distanthorizons.config.enum.EDhApiLodShading.ENABLED":
|
||||
@@ -1122,11 +1064,11 @@
|
||||
"distanthorizons.config.enum.EDhApiGrassSideRendering.AS_DIRT":
|
||||
"As Dirt",
|
||||
|
||||
"distanthorizons.config.enum.EDhApiRenderApi.AUTO":
|
||||
"distanthorizons.config.enum.EDhApiRenderingEngine.AUTO":
|
||||
"Auto",
|
||||
"distanthorizons.config.enum.EDhApiRenderApi.OPEN_GL":
|
||||
"distanthorizons.config.enum.EDhApiRenderingEngine.OPEN_GL":
|
||||
"OpenGL",
|
||||
"distanthorizons.config.enum.EDhApiRenderApi.BLAZE_3D":
|
||||
"distanthorizons.config.enum.EDhApiRenderingEngine.BLAZE_3D":
|
||||
"Blaze3D"
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@ in vec2 TexCoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
layout (std140) uniform baseFragUniformBlock
|
||||
{
|
||||
bool uIsReverseZDepth;
|
||||
};
|
||||
|
||||
uniform sampler2D uSourceColorTexture;
|
||||
uniform sampler2D uSourceDepthTexture;
|
||||
|
||||
@@ -11,11 +16,21 @@ uniform sampler2D uSourceDepthTexture;
|
||||
void main()
|
||||
{
|
||||
fragColor = vec4(0.0);
|
||||
|
||||
// a fragment depth of "1" means the fragment wasn't drawn to,
|
||||
// only update fragments that were drawn to
|
||||
float fragmentDepth = texture(uSourceDepthTexture, TexCoord).r;
|
||||
if (fragmentDepth != 1)
|
||||
|
||||
bool drawnTo;
|
||||
if (uIsReverseZDepth)
|
||||
{
|
||||
drawnTo = (fragmentDepth != 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// a fragment depth of "1" means the fragment wasn't drawn to
|
||||
drawnTo = (fragmentDepth != 1.0f);
|
||||
}
|
||||
|
||||
// only update fragments that were drawn to
|
||||
if (drawnTo)
|
||||
{
|
||||
fragColor = texture(uSourceColorTexture, TexCoord);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user