init
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
modLoader = "javafml"
|
||||
loaderVersion = "${neoforge_loader_version_range}"
|
||||
issueTrackerURL = "${issues}"
|
||||
license = "${license}"
|
||||
|
||||
[[mods]]
|
||||
modId = "${mod_id}"
|
||||
version = "${version}"
|
||||
displayName = "${mod_name}"
|
||||
authors = "${mod_author}"
|
||||
credits = "${credits}"
|
||||
description = '''${description}'''
|
||||
logoFile = "icon.png"
|
||||
|
||||
["lithium:options"]
|
||||
"mixin.entity.collisions.unpushable_cramming" = false
|
||||
"mixin.world.chunk_access" = false
|
||||
"mixin.world.chunk_ticking" = false
|
||||
"mixin.world.tick_scheduler" = false
|
||||
|
||||
[[mixins]]
|
||||
config = "sable.mixins.json"
|
||||
|
||||
[[mixins]]
|
||||
config = "sable-neoforge.mixins.json"
|
||||
|
||||
[[dependencies.sable]]
|
||||
modId = "neoforge"
|
||||
type = "required"
|
||||
versionRange = "[${neoforge_version},)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
[[dependencies.sable]]
|
||||
modId = "minecraft"
|
||||
type = "required"
|
||||
versionRange = "${minecraft_version_range}"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
[[dependencies.sable]]
|
||||
modId = "flywheel"
|
||||
type = "optional"
|
||||
versionRange = "[1.0.6,)"
|
||||
ordering = "AFTER"
|
||||
side = "CLIENT"
|
||||
|
||||
[[dependencies.sable]]
|
||||
modId = "create"
|
||||
type = "optional"
|
||||
versionRange = "${create_version_range}"
|
||||
ordering = "AFTER"
|
||||
side = "CLIENT"
|
||||
|
||||
[[dependencies.sable]]
|
||||
modId = "sablecompanion"
|
||||
type = "incompatible"
|
||||
versionRange = "(${sable_companion_version},)"
|
||||
reason = "Sable is out of date"
|
||||
|
||||
[[dependencies.sable]]
|
||||
modId = "scalablelux"
|
||||
type = "incompatible"
|
||||
|
||||
[[dependencies.sable]]
|
||||
modId = "littletiles"
|
||||
type = "incompatible"
|
||||
+1
@@ -0,0 +1 @@
|
||||
dev.ryanhcode.sable.neoforge.platform.SableAssemblyPlatformImpl
|
||||
+1
@@ -0,0 +1 @@
|
||||
dev.ryanhcode.sable.neoforge.platform.SableChunkEventPlatformImpl
|
||||
+1
@@ -0,0 +1 @@
|
||||
dev.ryanhcode.sable.neoforge.platform.SableEventPlatformImpl
|
||||
+1
@@ -0,0 +1 @@
|
||||
dev.ryanhcode.sable.neoforge.platform.SableEventPublishPlatformImpl
|
||||
+1
@@ -0,0 +1 @@
|
||||
dev.ryanhcode.sable.neoforge.platform.SableLoaderPlatformImpl
|
||||
+1
@@ -0,0 +1 @@
|
||||
dev.ryanhcode.sable.neoforge.platform.SablePlatformImpl
|
||||
+1
@@ -0,0 +1 @@
|
||||
dev.ryanhcode.sable.neoforge.platform.SablePlotPlatformImpl
|
||||
+1
@@ -0,0 +1 @@
|
||||
dev.ryanhcode.sable.neoforge.platform.SableSubLevelRenderPlatformImpl
|
||||
@@ -0,0 +1,7 @@
|
||||
Sable's sub-levels each contain their own lighting sections, and lighting data.
|
||||
|
||||
We need Flywheel shaders to be aware of this, so we change and override the lighting storage, LUT, and shaders to respect an additional "scene ID".
|
||||
|
||||
I'm not happy with the large amounts of duplicated shader code in these overrides, but it's the route we are going with for now.
|
||||
|
||||
Reference https://github.com/Engine-Room/Flywheel/tree/1.21.1/dev for the original shaders and lighting code that these overrides are based on.
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "flywheel:internal/material.glsl"
|
||||
#include "flywheel:internal/api_impl.glsl"
|
||||
#include "flywheel:internal/uniforms/uniforms.glsl"
|
||||
|
||||
in vec4 flw_vertexPos;
|
||||
in vec4 flw_vertexColor;
|
||||
in vec2 flw_vertexTexCoord;
|
||||
flat in ivec2 flw_vertexOverlay;
|
||||
in vec2 flw_vertexLight;
|
||||
in vec3 flw_vertexNormal;
|
||||
|
||||
in float flw_distance;
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
flat in float flw_skyLightScale;
|
||||
flat in uint flw_vertexLightingSceneId;
|
||||
in vec4 flw_vertexLightingPos;
|
||||
#endif
|
||||
|
||||
vec4 flw_sampleColor;
|
||||
|
||||
FlwMaterial flw_material;
|
||||
|
||||
bool flw_fragDiffuse;
|
||||
vec4 flw_fragColor;
|
||||
ivec2 flw_fragOverlay;
|
||||
vec2 flw_fragLight;
|
||||
|
||||
uniform sampler2D flw_diffuseTex;
|
||||
uniform sampler2D flw_overlayTex;
|
||||
uniform sampler2D flw_lightTex;
|
||||
@@ -0,0 +1,26 @@
|
||||
struct FlwLightAo {
|
||||
vec2 light;
|
||||
float ao;
|
||||
};
|
||||
|
||||
/// Get the light at the given world position relative to flw_renderOrigin from the given normal.
|
||||
/// This may be interpolated for smooth lighting.
|
||||
bool flw_light(uint scene, vec3 worldPos, vec3 normal, ivec3 renderOrigin, out FlwLightAo light);
|
||||
|
||||
/// Fetches the light value at the given block position.
|
||||
/// Returns false if the light for the given block is not available.
|
||||
bool flw_lightFetch(uint scene, ivec3 blockPos, out vec2 light);
|
||||
|
||||
// Backwards compatible overloads
|
||||
|
||||
/// Get the light at the given world position relative to flw_renderOrigin from the given normal.
|
||||
/// This may be interpolated for smooth lighting.
|
||||
bool flw_light(vec3 worldPos, vec3 normal, ivec3 renderOrigin, out FlwLightAo light) {
|
||||
return flw_light(0u, worldPos, normal, renderOrigin, light);
|
||||
}
|
||||
|
||||
/// Fetches the light value at the given block position.
|
||||
/// Returns false if the light for the given block is not available.
|
||||
bool flw_lightFetch(ivec3 blockPos, out vec2 light) {
|
||||
return flw_lightFetch(0u, blockPos, light);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#include "flywheel:internal/fog_distance.glsl"
|
||||
|
||||
#ifdef _FLW_CRUMBLING
|
||||
out vec2 _flw_crumblingTexCoord;
|
||||
|
||||
const int DOWN = 0;
|
||||
const int UP = 1;
|
||||
const int NORTH = 2;
|
||||
const int SOUTH = 3;
|
||||
const int WEST = 4;
|
||||
const int EAST = 5;
|
||||
|
||||
// based on net.minecraftforge.client.ForgeHooksClient.getNearestStable
|
||||
int getNearestFacing(vec3 normal) {
|
||||
float maxAlignment = -2;
|
||||
int face = 2;
|
||||
|
||||
// Calculate the alignment of the normal vector with each axis.
|
||||
// Note that `-dot(normal, axis) == dot(normal, -axis)`.
|
||||
vec3 alignment = vec3(
|
||||
dot(normal, vec3(1., 0., 0.)),
|
||||
dot(normal, vec3(0., 1., 0.)),
|
||||
dot(normal, vec3(0., 0., 1.))
|
||||
);
|
||||
|
||||
if (-alignment.y > maxAlignment) {
|
||||
maxAlignment = -alignment.y;
|
||||
face = DOWN;
|
||||
}
|
||||
if (alignment.y > maxAlignment) {
|
||||
maxAlignment = alignment.y;
|
||||
face = UP;
|
||||
}
|
||||
if (-alignment.z > maxAlignment) {
|
||||
maxAlignment = -alignment.z;
|
||||
face = NORTH;
|
||||
}
|
||||
if (alignment.z > maxAlignment) {
|
||||
maxAlignment = alignment.z;
|
||||
face = SOUTH;
|
||||
}
|
||||
if (-alignment.x > maxAlignment) {
|
||||
maxAlignment = -alignment.x;
|
||||
face = WEST;
|
||||
}
|
||||
if (alignment.x > maxAlignment) {
|
||||
maxAlignment = alignment.x;
|
||||
face = EAST;
|
||||
}
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
vec2 getCrumblingTexCoord() {
|
||||
switch (getNearestFacing(flw_vertexNormal)) {
|
||||
case DOWN: return vec2(flw_vertexPos.x, -flw_vertexPos.z);
|
||||
case UP: return vec2(flw_vertexPos.x, flw_vertexPos.z);
|
||||
case NORTH: return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
|
||||
case SOUTH: return vec2(flw_vertexPos.x, -flw_vertexPos.y);
|
||||
case WEST: return vec2(-flw_vertexPos.z, -flw_vertexPos.y);
|
||||
case EAST: return vec2(flw_vertexPos.z, -flw_vertexPos.y);
|
||||
}
|
||||
|
||||
// default to north
|
||||
return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
mat4 _flw_modelMatrix;
|
||||
mat3 _flw_normalMatrix;
|
||||
uint _flw_lightingSceneId;
|
||||
float _flw_skyLightScale;
|
||||
mat4 _flw_lightingSceneMatrix;
|
||||
flat out uint flw_vertexLightingSceneId;
|
||||
flat out float flw_skyLightScale;
|
||||
out vec4 flw_vertexLightingPos;
|
||||
#endif
|
||||
|
||||
#ifdef _FLW_DEBUG
|
||||
flat out uvec2 _flw_ids;
|
||||
#endif
|
||||
|
||||
void _flw_main(in FlwInstance instance, in uint stableInstanceID, in uint baseVertex) {
|
||||
flw_vertexId = gl_VertexID - baseVertex;
|
||||
|
||||
_flw_layoutVertex();
|
||||
flw_instanceVertex(instance);
|
||||
flw_materialVertex();
|
||||
|
||||
#ifdef _FLW_CRUMBLING
|
||||
_flw_crumblingTexCoord = getCrumblingTexCoord();
|
||||
#endif
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
flw_vertexLightingPos = _flw_lightingSceneMatrix * flw_vertexPos;
|
||||
flw_vertexPos = _flw_modelMatrix * flw_vertexPos;
|
||||
flw_vertexNormal = _flw_normalMatrix * flw_vertexNormal;
|
||||
flw_vertexLightingSceneId = _flw_lightingSceneId;
|
||||
flw_skyLightScale = _flw_skyLightScale;
|
||||
#endif
|
||||
|
||||
flw_vertexNormal = normalize(flw_vertexNormal);
|
||||
|
||||
flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos, flw_fogShape);
|
||||
|
||||
gl_Position = flw_viewProjection * flw_vertexPos;
|
||||
|
||||
#ifdef _FLW_DEBUG
|
||||
_flw_ids = uvec2(stableInstanceID, baseVertex);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "flywheel:internal/common.vert"
|
||||
#include "flywheel:internal/packed_material.glsl"
|
||||
#include "flywheel:internal/indirect/buffer_bindings.glsl"
|
||||
#include "flywheel:internal/indirect/draw_command.glsl"
|
||||
#include "flywheel:internal/indirect/light.glsl"
|
||||
#include "flywheel:internal/indirect/matrices.glsl"
|
||||
|
||||
layout(std430, binding = _FLW_DRAW_INSTANCE_INDEX_BUFFER_BINDING) restrict readonly buffer TargetBuffer {
|
||||
uint _flw_instanceIndices[];
|
||||
};
|
||||
|
||||
layout(std430, binding = _FLW_DRAW_BUFFER_BINDING) restrict readonly buffer DrawBuffer {
|
||||
MeshDrawCommand _flw_drawCommands[];
|
||||
};
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
layout(std430, binding = _FLW_MATRIX_BUFFER_BINDING) restrict buffer MatrixBuffer {
|
||||
Matrices _flw_matrices[];
|
||||
};
|
||||
#endif
|
||||
|
||||
uniform uint _flw_baseDraw;
|
||||
|
||||
flat out uvec2 _flw_packedMaterial;
|
||||
|
||||
#if __VERSION__ < 460
|
||||
#define flw_baseInstance gl_BaseInstanceARB
|
||||
#define flw_drawId gl_DrawIDARB
|
||||
#else
|
||||
#define flw_baseInstance gl_BaseInstance
|
||||
#define flw_drawId gl_DrawID
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
uint drawIndex = flw_drawId + _flw_baseDraw;
|
||||
MeshDrawCommand draw = _flw_drawCommands[drawIndex];
|
||||
|
||||
uint packedMaterialProperties = draw.packedMaterialProperties;
|
||||
_flw_unpackMaterialProperties(packedMaterialProperties, flw_material);
|
||||
_flw_packedMaterial = uvec2(draw.packedFogAndCutout, packedMaterialProperties);
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
_flw_unpackMatrices(_flw_matrices[draw.matrixIndex], _flw_modelMatrix, _flw_normalMatrix, _flw_lightingSceneId, _flw_skyLightScale, _flw_lightingSceneMatrix);
|
||||
#endif
|
||||
|
||||
#ifdef _FLW_CRUMBLING
|
||||
uint instanceIndex = flw_baseInstance;
|
||||
#else
|
||||
uint instanceIndex = _flw_instanceIndices[flw_baseInstance + gl_InstanceID];
|
||||
#endif
|
||||
|
||||
FlwInstance instance = _flw_unpackInstance(instanceIndex);
|
||||
|
||||
_flw_main(instance, instanceIndex, draw.vertexOffset);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
struct Matrices {
|
||||
mat4 pose;
|
||||
vec4 normalA;
|
||||
vec4 normalB;
|
||||
vec4 normalC;
|
||||
float skyLightScale;
|
||||
uint sceneID;
|
||||
float _padding1;
|
||||
float _padding2;
|
||||
mat4 lightingSceneMatrix;
|
||||
};
|
||||
|
||||
void _flw_unpackMatrices(in Matrices mats, out mat4 pose, out mat3 normal, out uint lightingSceneId, out float skyLightScale, out mat4 lightingSceneMatrix) {
|
||||
pose = mats.pose;
|
||||
normal = mat3(mats.normalA.xyz, mats.normalB.xyz, mats.normalC.xyz);
|
||||
lightingSceneId = mats.sceneID;
|
||||
skyLightScale = mats.skyLightScale;
|
||||
lightingSceneMatrix = mats.lightingSceneMatrix;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "flywheel:internal/common.vert"
|
||||
#include "flywheel:internal/packed_material.glsl"
|
||||
#include "flywheel:internal/instancing/light.glsl"
|
||||
|
||||
uniform uvec2 _flw_packedMaterial;
|
||||
uniform int _flw_baseInstance = 0;
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
uniform mat4 _flw_modelMatrixUniform;
|
||||
uniform mat3 _flw_normalMatrixUniform;
|
||||
uniform uint _flw_lightingSceneUniform;
|
||||
uniform float _flw_lightingSkyLightScaleUniform;
|
||||
uniform mat4 _flw_lightingSceneMatrixUniform;
|
||||
#endif
|
||||
|
||||
uniform uint _flw_baseVertex;
|
||||
|
||||
void main() {
|
||||
_flw_unpackMaterialProperties(_flw_packedMaterial.y, flw_material);
|
||||
|
||||
FlwInstance instance = _flw_unpackInstance(_flw_baseInstance + gl_InstanceID);
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
_flw_modelMatrix = _flw_modelMatrixUniform;
|
||||
_flw_normalMatrix = _flw_normalMatrixUniform;
|
||||
_flw_lightingSceneMatrix = _flw_lightingSceneMatrixUniform;
|
||||
_flw_lightingSceneId = _flw_lightingSceneUniform;
|
||||
_flw_skyLightScale = _flw_lightingSkyLightScaleUniform;
|
||||
#endif
|
||||
|
||||
_flw_main(instance, uint(gl_InstanceID), _flw_baseVertex);
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
const uint _FLW_BLOCKS_PER_SECTION = 18u * 18u * 18u;
|
||||
const uint _FLW_LIGHT_SIZE_BYTES = _FLW_BLOCKS_PER_SECTION;
|
||||
const uint _FLW_SOLID_SIZE_BYTES = ((_FLW_BLOCKS_PER_SECTION + 31u) / 32u) * 4u;
|
||||
const uint _FLW_LIGHT_START_BYTES = _FLW_SOLID_SIZE_BYTES;
|
||||
const uint _FLW_LIGHT_SECTION_SIZE_BYTES = _FLW_SOLID_SIZE_BYTES + _FLW_LIGHT_SIZE_BYTES;
|
||||
|
||||
const uint _FLW_SOLID_START_INTS = 0u;
|
||||
const uint _FLW_LIGHT_START_INTS = _FLW_SOLID_SIZE_BYTES / 4u;
|
||||
const uint _FLW_LIGHT_SECTION_SIZE_INTS = _FLW_LIGHT_SECTION_SIZE_BYTES / 4u;
|
||||
|
||||
const uint _FLW_COMPLETELY_SOLID = 0x7FFFFFFu;
|
||||
const float _FLW_EPSILON = 1e-5;
|
||||
|
||||
const uint _FLW_LOWER_10_BITS = 0x3FFu;
|
||||
const uint _FLW_UPPER_10_BITS = 0xFFF00000u;
|
||||
|
||||
const float _FLW_LIGHT_NORMALIZER = 1. / 16.;
|
||||
|
||||
uint _flw_indexLut(uint index);
|
||||
|
||||
uint _flw_indexLight(uint index);
|
||||
|
||||
/// Find the index for the next step in the LUT.
|
||||
/// @param base The base index in the LUT, should point to the start of a coordinate span.
|
||||
/// @param coord The coordinate to look for.
|
||||
/// @param next Output. The index of the next step in the LUT.
|
||||
/// @return true if the coordinate is not in the span.
|
||||
bool _flw_nextLut(uint base, int coord, out uint next) {
|
||||
// The base coordinate.
|
||||
int start = int(_flw_indexLut(base));
|
||||
// The width of the coordinate span.
|
||||
uint size = _flw_indexLut(base + 1u);
|
||||
|
||||
// Index of the coordinate in the span.
|
||||
int i = coord - start;
|
||||
|
||||
if (i < 0 || i >= int(size)) {
|
||||
// We missed.
|
||||
return true;
|
||||
}
|
||||
|
||||
next = _flw_indexLut(base + 2u + uint(i));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _flw_chunkCoordToSectionIndex(uint sceneId, ivec3 sectionPos, out uint index) {
|
||||
uint scene;
|
||||
if (_flw_nextLut(0u, int(sceneId), scene) || scene == 0u) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint first;
|
||||
if (_flw_nextLut(scene, sectionPos.y, first) || first == 0u) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint second;
|
||||
if (_flw_nextLut(first, sectionPos.x, second) || second == 0u) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint sectionIndex;
|
||||
if (_flw_nextLut(second, sectionPos.z, sectionIndex) || sectionIndex == 0u) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The index is written as 1-based so we can properly detect missing sections.
|
||||
index = sectionIndex - 1u;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uvec2 _flw_lightAt(uint sectionOffset, uvec3 blockInSectionPos) {
|
||||
uint byteOffset = blockInSectionPos.x + blockInSectionPos.z * 18u + blockInSectionPos.y * 18u * 18u;
|
||||
|
||||
uint uintOffset = byteOffset >> 2u;
|
||||
uint bitOffset = (byteOffset & 3u) << 3;
|
||||
|
||||
uint raw = _flw_indexLight(sectionOffset + _FLW_LIGHT_START_INTS + uintOffset);
|
||||
uint block = (raw >> bitOffset) & 0xFu;
|
||||
uint sky = (raw >> (bitOffset + 4u)) & 0xFu;
|
||||
|
||||
return uvec2(block, sky);
|
||||
}
|
||||
|
||||
bool _flw_isSolid(uint sectionOffset, uvec3 blockInSectionPos) {
|
||||
uint bitOffset = blockInSectionPos.x + blockInSectionPos.z * 18u + blockInSectionPos.y * 18u * 18u;
|
||||
|
||||
uint uintOffset = bitOffset >> 5u;
|
||||
uint bitInWordOffset = bitOffset & 31u;
|
||||
|
||||
uint word = _flw_indexLight(sectionOffset + _FLW_SOLID_START_INTS + uintOffset);
|
||||
|
||||
return (word & (1u << bitInWordOffset)) != 0u;
|
||||
}
|
||||
|
||||
bool flw_lightFetch(uint scene, ivec3 blockPos, out vec2 lightCoord) {
|
||||
uint lightSectionIndex;
|
||||
if (_flw_chunkCoordToSectionIndex(scene, blockPos >> 4, lightSectionIndex)) {
|
||||
return false;
|
||||
}
|
||||
// The offset of the section in the light buffer.
|
||||
uint sectionOffset = lightSectionIndex * _FLW_LIGHT_SECTION_SIZE_INTS;
|
||||
|
||||
uvec3 blockInSectionPos = uvec3((blockPos & 0xF) + 1);
|
||||
|
||||
lightCoord = vec2(_flw_lightAt(sectionOffset, blockInSectionPos)) * _FLW_LIGHT_NORMALIZER;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint _flw_fetchSolid3x3x3(uint sectionOffset, ivec3 blockInSectionPos) {
|
||||
uint ret = 0u;
|
||||
|
||||
// The formatter does NOT like these macros
|
||||
// @formatter:off
|
||||
|
||||
#define _FLW_FETCH_SOLID(x, y, z, i) { \
|
||||
bool flag = _flw_isSolid(sectionOffset, uvec3(blockInSectionPos + ivec3(x, y, z))); \
|
||||
ret |= uint(flag) << i; \
|
||||
}
|
||||
|
||||
/// fori y, z, x: unrolled
|
||||
_FLW_FETCH_SOLID(-1, -1, -1, 0)
|
||||
_FLW_FETCH_SOLID(0, -1, -1, 1)
|
||||
_FLW_FETCH_SOLID(1, -1, -1, 2)
|
||||
|
||||
_FLW_FETCH_SOLID(-1, -1, 0, 3)
|
||||
_FLW_FETCH_SOLID(0, -1, 0, 4)
|
||||
_FLW_FETCH_SOLID(1, -1, 0, 5)
|
||||
|
||||
_FLW_FETCH_SOLID(-1, -1, 1, 6)
|
||||
_FLW_FETCH_SOLID(0, -1, 1, 7)
|
||||
_FLW_FETCH_SOLID(1, -1, 1, 8)
|
||||
|
||||
_FLW_FETCH_SOLID(-1, 0, -1, 9)
|
||||
_FLW_FETCH_SOLID(0, 0, -1, 10)
|
||||
_FLW_FETCH_SOLID(1, 0, -1, 11)
|
||||
|
||||
_FLW_FETCH_SOLID(-1, 0, 0, 12)
|
||||
_FLW_FETCH_SOLID(0, 0, 0, 13)
|
||||
_FLW_FETCH_SOLID(1, 0, 0, 14)
|
||||
|
||||
_FLW_FETCH_SOLID(-1, 0, 1, 15)
|
||||
_FLW_FETCH_SOLID(0, 0, 1, 16)
|
||||
_FLW_FETCH_SOLID(1, 0, 1, 17)
|
||||
|
||||
_FLW_FETCH_SOLID(-1, 1, -1, 18)
|
||||
_FLW_FETCH_SOLID(0, 1, -1, 19)
|
||||
_FLW_FETCH_SOLID(1, 1, -1, 20)
|
||||
|
||||
_FLW_FETCH_SOLID(-1, 1, 0, 21)
|
||||
_FLW_FETCH_SOLID(0, 1, 0, 22)
|
||||
_FLW_FETCH_SOLID(1, 1, 0, 23)
|
||||
|
||||
_FLW_FETCH_SOLID(-1, 1, 1, 24)
|
||||
_FLW_FETCH_SOLID(0, 1, 1, 25)
|
||||
_FLW_FETCH_SOLID(1, 1, 1, 26)
|
||||
|
||||
// @formatter:on
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Premtively collect all light in a 3x3x3 area centered on our block.
|
||||
/// Depending on the normal, we won't use all the data, but fetching on demand will have many duplicated fetches.
|
||||
/// Only fetching what we'll actually use using a bitmask turned out significantly slower, but perhaps a less
|
||||
/// granular approach could see wins.
|
||||
///
|
||||
/// The output is a 3-component vector <blockLight, skyLight, valid ? 1 : 0> packed into a single uint to save
|
||||
/// memory and ALU ops later on. 10 bits are used for each component. This allows 4 such packed ints to be added
|
||||
/// together with room to spare before overflowing into the next component.
|
||||
uint[27] _flw_fetchLight3x3x3(uint sectionOffset, ivec3 blockInSectionPos, uint solidMask) {
|
||||
uint[27] lights;
|
||||
|
||||
// @formatter:off
|
||||
#define _FLW_FETCH_LIGHT(_x, _y, _z, i) { \
|
||||
uvec2 light = _flw_lightAt(sectionOffset, uvec3(blockInSectionPos + ivec3(_x, _y, _z))); \
|
||||
lights[i] = (light.x) | ((light.y) << 10) | (uint((solidMask & (1u << i)) == 0u) << 20); \
|
||||
}
|
||||
|
||||
/// fori y, z, x: unrolled
|
||||
_FLW_FETCH_LIGHT(-1, -1, -1, 0)
|
||||
_FLW_FETCH_LIGHT(0, -1, -1, 1)
|
||||
_FLW_FETCH_LIGHT(1, -1, -1, 2)
|
||||
|
||||
_FLW_FETCH_LIGHT(-1, -1, 0, 3)
|
||||
_FLW_FETCH_LIGHT(0, -1, 0, 4)
|
||||
_FLW_FETCH_LIGHT(1, -1, 0, 5)
|
||||
|
||||
_FLW_FETCH_LIGHT(-1, -1, 1, 6)
|
||||
_FLW_FETCH_LIGHT(0, -1, 1, 7)
|
||||
_FLW_FETCH_LIGHT(1, -1, 1, 8)
|
||||
|
||||
_FLW_FETCH_LIGHT(-1, 0, -1, 9)
|
||||
_FLW_FETCH_LIGHT(0, 0, -1, 10)
|
||||
_FLW_FETCH_LIGHT(1, 0, -1, 11)
|
||||
|
||||
_FLW_FETCH_LIGHT(-1, 0, 0, 12)
|
||||
_FLW_FETCH_LIGHT(0, 0, 0, 13)
|
||||
_FLW_FETCH_LIGHT(1, 0, 0, 14)
|
||||
|
||||
_FLW_FETCH_LIGHT(-1, 0, 1, 15)
|
||||
_FLW_FETCH_LIGHT(0, 0, 1, 16)
|
||||
_FLW_FETCH_LIGHT(1, 0, 1, 17)
|
||||
|
||||
_FLW_FETCH_LIGHT(-1, 1, -1, 18)
|
||||
_FLW_FETCH_LIGHT(0, 1, -1, 19)
|
||||
_FLW_FETCH_LIGHT(1, 1, -1, 20)
|
||||
|
||||
_FLW_FETCH_LIGHT(-1, 1, 0, 21)
|
||||
_FLW_FETCH_LIGHT(0, 1, 0, 22)
|
||||
_FLW_FETCH_LIGHT(1, 1, 0, 23)
|
||||
|
||||
_FLW_FETCH_LIGHT(-1, 1, 1, 24)
|
||||
_FLW_FETCH_LIGHT(0, 1, 1, 25)
|
||||
_FLW_FETCH_LIGHT(1, 1, 1, 26)
|
||||
|
||||
// @formatter:on
|
||||
|
||||
return lights;
|
||||
}
|
||||
|
||||
#define _flw_index3x3x3(x, y, z) ((x) + (z) * 3u + (y) * 9u)
|
||||
#define _flw_validCountToAo(validCount) (1. - (4. - (validCount)) * 0.2)
|
||||
|
||||
/// Calculate the light for a direction by averaging the light at the corners of the block.
|
||||
///
|
||||
/// To make this reusable across directions, c00..c11 choose what values relative to each corner to use.
|
||||
/// e.g. (0, 0, 0) (0, 0, 1) (0, 1, 0) (0, 1, 1) would give you the light coming from -x at each corner.
|
||||
/// In general, to get the light for a particular direction, you fix the x, y, or z coordinate of the c values, and permutate 0 and 1 for the other two.
|
||||
/// Fixing the x coordinate to 0 gives you the light from -x, 1 gives you the light from +x.
|
||||
///
|
||||
/// @param lights The light data for the 3x3x3 area.
|
||||
/// @param interpolant The position within the center block.
|
||||
/// @param c00..c11 4 offsets to determine which "direction" we are averaging.
|
||||
/// @param oppositeMask A bitmask telling this function which bit to flip to get the opposite index for a given corner
|
||||
vec3 _flw_lightForDirection(uint[27] lights, vec3 interpolant, uint c00, uint c01, uint c10, uint c11, uint oppositeMask) {
|
||||
// Sum up the light and number of valid blocks in each corner for this direction
|
||||
uint[8] summed;
|
||||
|
||||
// @formatter:off
|
||||
|
||||
#define _FLW_SUM_CORNER(_x, _y, _z, i) { \
|
||||
const uint corner = _flw_index3x3x3(_x, _y, _z); \
|
||||
summed[i] = lights[c00 + corner] + lights[c01 + corner] + lights[c10 + corner] + lights[c11 + corner]; \
|
||||
}
|
||||
|
||||
_FLW_SUM_CORNER(0u, 0u, 0u, 0)
|
||||
_FLW_SUM_CORNER(1u, 0u, 0u, 1)
|
||||
_FLW_SUM_CORNER(0u, 0u, 1u, 2)
|
||||
_FLW_SUM_CORNER(1u, 0u, 1u, 3)
|
||||
_FLW_SUM_CORNER(0u, 1u, 0u, 4)
|
||||
_FLW_SUM_CORNER(1u, 1u, 0u, 5)
|
||||
_FLW_SUM_CORNER(0u, 1u, 1u, 6)
|
||||
_FLW_SUM_CORNER(1u, 1u, 1u, 7)
|
||||
|
||||
// @formatter:on
|
||||
|
||||
// The final light and number of valid blocks for each corner.
|
||||
vec3[8] adjusted;
|
||||
|
||||
#ifdef _FLW_INNER_FACE_CORRECTION
|
||||
// If the current corner has no valid blocks, use the opposite
|
||||
// corner's light based on which direction we're evaluating.
|
||||
// Because of how our corners are indexed, moving along one axis is the same as flipping a bit.
|
||||
#define _FLW_CORNER_INDEX(i) ((summed[i] & _FLW_UPPER_10_BITS) == 0u ? i ^ oppositeMask : i)
|
||||
#else
|
||||
#define _FLW_CORNER_INDEX(i) i
|
||||
#endif
|
||||
|
||||
// Division and branching (to avoid dividing by zero) are both kinda expensive, so use this table for the valid block normalization
|
||||
const float[5] normalizers = float[](0., 1., 1. / 2., 1. / 3., 1. / 4.);
|
||||
|
||||
// @formatter:off
|
||||
|
||||
#define _FLW_ADJUST_CORNER(i) { \
|
||||
uint corner = summed[_FLW_CORNER_INDEX(i)]; \
|
||||
uint validCount = corner >> 20u; \
|
||||
adjusted[i].xy = vec2(corner & _FLW_LOWER_10_BITS, (corner >> 10u) & _FLW_LOWER_10_BITS) * normalizers[validCount]; \
|
||||
adjusted[i].z = float(validCount); \
|
||||
}
|
||||
|
||||
_FLW_ADJUST_CORNER(0)
|
||||
_FLW_ADJUST_CORNER(1)
|
||||
_FLW_ADJUST_CORNER(2)
|
||||
_FLW_ADJUST_CORNER(3)
|
||||
_FLW_ADJUST_CORNER(4)
|
||||
_FLW_ADJUST_CORNER(5)
|
||||
_FLW_ADJUST_CORNER(6)
|
||||
_FLW_ADJUST_CORNER(7)
|
||||
|
||||
// @formatter:on
|
||||
|
||||
// Trilinear interpolation, including valid count
|
||||
vec3 light00 = mix(adjusted[0], adjusted[1], interpolant.x);
|
||||
vec3 light01 = mix(adjusted[2], adjusted[3], interpolant.x);
|
||||
vec3 light10 = mix(adjusted[4], adjusted[5], interpolant.x);
|
||||
vec3 light11 = mix(adjusted[6], adjusted[7], interpolant.x);
|
||||
|
||||
vec3 light0 = mix(light00, light01, interpolant.z);
|
||||
vec3 light1 = mix(light10, light11, interpolant.z);
|
||||
|
||||
vec3 light = mix(light0, light1, interpolant.y);
|
||||
|
||||
// Normalize the light coords
|
||||
light.xy *= _FLW_LIGHT_NORMALIZER;
|
||||
// Calculate the AO multiplier from the number of valid blocks
|
||||
light.z = _flw_validCountToAo(light.z);
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
bool flw_light(uint scene, vec3 worldPos, vec3 normal, ivec3 renderOrigin, out FlwLightAo light) {
|
||||
// Always use the section of the block we are contained in to ensure accuracy.
|
||||
// We don't want to interpolate between sections, but also we might not be able
|
||||
// to rely on the existence neighboring sections, so don't do any extra rounding here.
|
||||
ivec3 blockPos = ivec3(floor(worldPos)) + renderOrigin;
|
||||
|
||||
uint lightSectionIndex;
|
||||
if (_flw_chunkCoordToSectionIndex(scene, blockPos >> 4, lightSectionIndex)) {
|
||||
return false;
|
||||
}
|
||||
// The offset of the section in the light buffer.
|
||||
uint sectionOffset = lightSectionIndex * _FLW_LIGHT_SECTION_SIZE_INTS;
|
||||
|
||||
// The block's position in the section adjusted into 18x18x18 space
|
||||
ivec3 blockInSectionPos = (blockPos & 0xF) + 1;
|
||||
|
||||
// Directly trilerp as if sampling a texture
|
||||
#if _FLW_LIGHT_SMOOTHNESS == 1
|
||||
|
||||
// The lowest corner of the 2x2x2 area we'll be trilinear interpolating.
|
||||
// The ugly bit on the end evaluates to -1 or 0 depending on which side of 0.5 we are.
|
||||
uvec3 lowestCorner = blockInSectionPos + ivec3(floor(fract(worldPos) - 0.5));
|
||||
|
||||
// The distance our fragment is from the center of the lowest corner.
|
||||
vec3 interpolant = fract(worldPos - 0.5);
|
||||
|
||||
// Fetch everything for trilinear interpolation
|
||||
// Hypothetically we could re-order these and do some calculations in-between fetches
|
||||
// to help with latency hiding, but the compiler should be able to do that for us.
|
||||
vec2 light000 = vec2(_flw_lightAt(sectionOffset, lowestCorner));
|
||||
vec2 light100 = vec2(_flw_lightAt(sectionOffset, lowestCorner + uvec3(1, 0, 0)));
|
||||
vec2 light001 = vec2(_flw_lightAt(sectionOffset, lowestCorner + uvec3(0, 0, 1)));
|
||||
vec2 light101 = vec2(_flw_lightAt(sectionOffset, lowestCorner + uvec3(1, 0, 1)));
|
||||
vec2 light010 = vec2(_flw_lightAt(sectionOffset, lowestCorner + uvec3(0, 1, 0)));
|
||||
vec2 light110 = vec2(_flw_lightAt(sectionOffset, lowestCorner + uvec3(1, 1, 0)));
|
||||
vec2 light011 = vec2(_flw_lightAt(sectionOffset, lowestCorner + uvec3(0, 1, 1)));
|
||||
vec2 light111 = vec2(_flw_lightAt(sectionOffset, lowestCorner + uvec3(1, 1, 1)));
|
||||
|
||||
vec2 light00 = mix(light000, light001, interpolant.z);
|
||||
vec2 light01 = mix(light010, light011, interpolant.z);
|
||||
vec2 light10 = mix(light100, light101, interpolant.z);
|
||||
vec2 light11 = mix(light110, light111, interpolant.z);
|
||||
|
||||
vec2 light0 = mix(light00, light01, interpolant.y);
|
||||
vec2 light1 = mix(light10, light11, interpolant.y);
|
||||
|
||||
light.light = mix(light0, light1, interpolant.x) * _FLW_LIGHT_NORMALIZER;
|
||||
light.ao = 1.;
|
||||
|
||||
// Lighting and AO accurate to chunk baking
|
||||
#elif _FLW_LIGHT_SMOOTHNESS == 2
|
||||
|
||||
uint solid = _flw_fetchSolid3x3x3(sectionOffset, blockInSectionPos);
|
||||
|
||||
if (solid == _FLW_COMPLETELY_SOLID) {
|
||||
// No point in doing any work if the entire 3x3x3 volume around us is filled.
|
||||
// Kinda rare but this may happen if our fragment is in the middle of a lot of tinted glass
|
||||
light.light = vec2(0.);
|
||||
light.ao = _flw_validCountToAo(0.);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch everything in a 3x3x3 area centered around the block.
|
||||
uint[27] lights = _flw_fetchLight3x3x3(sectionOffset, blockInSectionPos, solid);
|
||||
|
||||
vec3 interpolant = fract(worldPos);
|
||||
|
||||
// Average the light in relevant directions at each corner, skipping directions that would have no influence
|
||||
|
||||
vec3 lightX;
|
||||
if (normal.x > _FLW_EPSILON) {
|
||||
lightX = _flw_lightForDirection(lights, interpolant, _flw_index3x3x3(1u, 0u, 0u), _flw_index3x3x3(1u, 0u, 1u), _flw_index3x3x3(1u, 1u, 0u), _flw_index3x3x3(1u, 1u, 1u), 1u);
|
||||
} else if (normal.x < -_FLW_EPSILON) {
|
||||
lightX = _flw_lightForDirection(lights, interpolant, _flw_index3x3x3(0u, 0u, 0u), _flw_index3x3x3(0u, 0u, 1u), _flw_index3x3x3(0u, 1u, 0u), _flw_index3x3x3(0u, 1u, 1u), 1u);
|
||||
} else {
|
||||
lightX = vec3(0.);
|
||||
}
|
||||
|
||||
vec3 lightZ;
|
||||
if (normal.z > _FLW_EPSILON) {
|
||||
lightZ = _flw_lightForDirection(lights, interpolant, _flw_index3x3x3(0u, 0u, 1u), _flw_index3x3x3(0u, 1u, 1u), _flw_index3x3x3(1u, 0u, 1u), _flw_index3x3x3(1u, 1u, 1u), 2u);
|
||||
} else if (normal.z < -_FLW_EPSILON) {
|
||||
lightZ = _flw_lightForDirection(lights, interpolant, _flw_index3x3x3(0u, 0u, 0u), _flw_index3x3x3(0u, 1u, 0u), _flw_index3x3x3(1u, 0u, 0u), _flw_index3x3x3(1u, 1u, 0u), 2u);
|
||||
} else {
|
||||
lightZ = vec3(0.);
|
||||
}
|
||||
|
||||
vec3 lightY;
|
||||
if (normal.y > _FLW_EPSILON) {
|
||||
lightY = _flw_lightForDirection(lights, interpolant, _flw_index3x3x3(0u, 1u, 0u), _flw_index3x3x3(0u, 1u, 1u), _flw_index3x3x3(1u, 1u, 0u), _flw_index3x3x3(1u, 1u, 1u), 4u);
|
||||
} else if (normal.y < -_FLW_EPSILON) {
|
||||
lightY = _flw_lightForDirection(lights, interpolant, _flw_index3x3x3(0u, 0u, 0u), _flw_index3x3x3(0u, 0u, 1u), _flw_index3x3x3(1u, 0u, 0u), _flw_index3x3x3(1u, 0u, 1u), 4u);
|
||||
} else {
|
||||
lightY = vec3(0.);
|
||||
}
|
||||
|
||||
vec3 n2 = normal * normal;
|
||||
vec3 lightAo = lightX * n2.x + lightY * n2.y + lightZ * n2.z;
|
||||
|
||||
light.light = lightAo.xy;
|
||||
light.ao = lightAo.z;
|
||||
|
||||
// Entirely flat lighting, the lowest setting and a fallback in case an invalid option is set
|
||||
#else
|
||||
|
||||
light.light = vec2(_flw_lightAt(sectionOffset, blockInSectionPos)) * _FLW_LIGHT_NORMALIZER;
|
||||
light.ao = 1.;
|
||||
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
void flw_shaderLight() {
|
||||
vec2 embeddedLight;
|
||||
|
||||
uint sceneId = 0;
|
||||
vec4 vertexLightingPos;
|
||||
ivec3 renderOrigin;
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
renderOrigin = flw_renderOrigin;
|
||||
sceneId = flw_vertexLightingSceneId;
|
||||
vertexLightingPos = flw_vertexLightingPos;
|
||||
|
||||
if (sceneId != 0) {
|
||||
renderOrigin = ivec3(0);
|
||||
}
|
||||
#else
|
||||
renderOrigin = flw_renderOrigin;
|
||||
vertexLightingPos = flw_vertexPos;
|
||||
#endif
|
||||
|
||||
if (flw_lightFetch(sceneId, ivec3(floor(vertexLightingPos.xyz)) + renderOrigin, embeddedLight)) {
|
||||
flw_fragLight = max(flw_fragLight, embeddedLight);
|
||||
}
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
flw_fragLight.y *= flw_skyLightScale;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
void flw_shaderLight() {
|
||||
uint sceneId = 0;
|
||||
vec4 vertexLightingPos;
|
||||
ivec3 renderOrigin;
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
renderOrigin = flw_renderOrigin;
|
||||
sceneId = flw_vertexLightingSceneId;
|
||||
vertexLightingPos = flw_vertexLightingPos;
|
||||
|
||||
if (sceneId != 0) {
|
||||
renderOrigin = ivec3(0);
|
||||
}
|
||||
#else
|
||||
renderOrigin = flw_renderOrigin;
|
||||
vertexLightingPos = flw_vertexPos;
|
||||
#endif
|
||||
|
||||
FlwLightAo light;
|
||||
if (flw_light(sceneId, vertexLightingPos.xyz, flw_vertexNormal, renderOrigin, light)) {
|
||||
flw_fragLight = max(flw_fragLight, light.light);
|
||||
|
||||
if (flw_material.ambientOcclusion) {
|
||||
flw_fragColor.rgb *= light.ao;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
flw_fragLight.y *= flw_skyLightScale;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
void flw_shaderLight() {
|
||||
#ifdef FLW_EMBEDDED
|
||||
ivec3 renderOrigin = flw_renderOrigin;
|
||||
|
||||
if (flw_vertexLightingSceneId != 0) {
|
||||
renderOrigin = ivec3(0);
|
||||
}
|
||||
|
||||
FlwLightAo light;
|
||||
if (flw_light(flw_vertexLightingSceneId, flw_vertexLightingPos.xyz, flw_vertexNormal, renderOrigin, light)) {
|
||||
flw_fragLight = max(flw_fragLight, light.light);
|
||||
|
||||
if (flw_material.ambientOcclusion) {
|
||||
flw_fragColor.rgb *= light.ao;
|
||||
}
|
||||
}
|
||||
|
||||
flw_fragLight.y *= flw_skyLightScale;
|
||||
#endif
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "dev.ryanhcode.sable.neoforge.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"minVersion": "0.8",
|
||||
"mixinextras": {
|
||||
"minVersion": "0.5.0"
|
||||
},
|
||||
"plugin": "dev.ryanhcode.sable.plugin.SableMixinPlugin",
|
||||
"client": [
|
||||
"block_entity_visible.LevelRendererMixin",
|
||||
"block_outline_render.LevelRendererMixin",
|
||||
"camera_rotation.CameraMixin",
|
||||
"compatibility.create.behaviour_compatibility.harvester_block_entity.HarvesterRendererMixin",
|
||||
"compatibility.create.belt.BeltRendererMixin",
|
||||
"compatibility.create.big_outlines_interaction.BigOutlinesMixin",
|
||||
"compatibility.create.blaze_burner.BlazeBurnerBlockEntityMixin",
|
||||
"compatibility.create.contraptions.ContraptionControlsRendererMixin",
|
||||
"compatibility.create.contraptions.ContraptionHandlerClientMixin",
|
||||
"compatibility.create.contraptions.ContraptionVisualMixin",
|
||||
"compatibility.create.contraptions.VisualizationEventHandlerMixin",
|
||||
"compatibility.create.depot.DepotRendererMixin",
|
||||
"compatibility.create.fluid_handling.PipeConnectionMixin",
|
||||
"compatibility.create.frogports.ChainConveyorInteractionHandlerMixin",
|
||||
"compatibility.create.frogports.ChainConveyorRidingHandlerMixin",
|
||||
"compatibility.create.frogports.FrogportRendererMixin",
|
||||
"compatibility.create.frogports.FrogportVisualMixin",
|
||||
"compatibility.create.frogports.SmartBlockEntityRendererMixin",
|
||||
"compatibility.create.particles.AirFlowParticleMixin",
|
||||
"compatibility.create.particles.AirParticleMixin",
|
||||
"compatibility.create.render_fixes.AABBOutlineMixin",
|
||||
"compatibility.create.render_fixes.BeltRendererMixin",
|
||||
"compatibility.create.render_fixes.BlockClusterOutlineMixin",
|
||||
"compatibility.create.render_fixes.ChainConveyorRendererMixin",
|
||||
"compatibility.create.render_fixes.ChasingAABBOutlineMixin",
|
||||
"compatibility.create.render_fixes.ChasingAABBOutlinerMixin",
|
||||
"compatibility.create.render_fixes.FilteringRendererMixin",
|
||||
"compatibility.create.render_fixes.GhostBlockValueBoxMixin",
|
||||
"compatibility.create.render_fixes.LineOutlineMixin",
|
||||
"compatibility.create.render_fixes.LinkRendererMixin",
|
||||
"compatibility.create.render_fixes.OutlineMixin",
|
||||
"compatibility.create.render_fixes.PlacementClientMixin",
|
||||
"compatibility.create.render_fixes.SafeBlockEntityRendererMixin",
|
||||
"compatibility.create.render_fixes.ValueBoxMixin",
|
||||
"compatibility.create.schematics.SchematicHandlerMixin",
|
||||
"compatibility.create.schematics.SchematicRendererMixin",
|
||||
"compatibility.create.schematics.SchematicTransformMixin",
|
||||
"compatibility.create.stock_ticker.EntityHatsMixin",
|
||||
"compatibility.create.tracks.TrackBlockOutlineMixin",
|
||||
"compatibility.create.tracks.TrackTargetingClientMixin",
|
||||
"compatibility.create.trains.CarriageContraptionVisualMixin",
|
||||
"compatibility.create.wand_of_symmetry.SymmetryHandlerMixin",
|
||||
"compatibility.flywheel.AbstractBlockEntityVisualMixin",
|
||||
"compatibility.flywheel.BlockEntityStorageMixin",
|
||||
"compatibility.flywheel.EmbeddedEnvironmentMixin",
|
||||
"compatibility.flywheel.EngineImplMixin",
|
||||
"compatibility.flywheel.EnvironmentStorageMixin",
|
||||
"compatibility.flywheel.LightStorageAccessor",
|
||||
"compatibility.flywheel.MatrixBufferMixin",
|
||||
"compatibility.flywheel.RenderDispatcherImplMixin",
|
||||
"compatibility.flywheel.ShaderSourcesMixin",
|
||||
"compatibility.flywheel.VisualManagerImplMixin",
|
||||
"compatibility.pmweather.RadarRendererMixin",
|
||||
"compatibility.sodiumextras.EmbyToolsMixin",
|
||||
"dynamic_directional_shading.SectionCompilerMixin",
|
||||
"sound.MovingSoundInstanceDelegateMixin"
|
||||
],
|
||||
"mixins": [
|
||||
"compatibility.backpacks.BackpackPickupEventsMixin",
|
||||
"compatibility.create.airflow.AirCurrentMixin",
|
||||
"compatibility.create.airflow.FanProcessingTypeMixin",
|
||||
"compatibility.create.basin_interactions.BasinBlockEntityMixin",
|
||||
"compatibility.create.basin_interactions.BasinOperatingBlockEntityMixin",
|
||||
"compatibility.create.behaviour_compatibility.BlockEntityBehaviourMixin",
|
||||
"compatibility.create.behaviour_compatibility.block_breaking_behaviour.BlockBreakingMovementBehaviourMixin",
|
||||
"compatibility.create.behaviour_compatibility.block_breaking_behaviour.SawMovementBehaviourMixin",
|
||||
"compatibility.create.behaviour_compatibility.harvester_behaviour.HarvesterMovementBehaviourMixin",
|
||||
"compatibility.create.behaviour_compatibility.harvester_block_entity.HarvesterBlockEntityMixin",
|
||||
"compatibility.create.behaviour_compatibility.harvester_block_entity.HarvesterBlockEntityUsageMixin",
|
||||
"compatibility.create.behaviour_compatibility.harvester_block_entity.HarvesterBlockMixin",
|
||||
"compatibility.create.belt.BeltBlockEntityMixin",
|
||||
"compatibility.create.belt.BeltBlockMixin",
|
||||
"compatibility.create.belt.BeltMovementHandlerMixin",
|
||||
"compatibility.create.big_outlines_interaction.BigOutlinesMixin",
|
||||
"compatibility.create.block_breakers.BlockBreakingKineticBlockEntityDamageMixin",
|
||||
"compatibility.create.block_breakers.BlockBreakingKineticBlockEntityMixin",
|
||||
"compatibility.create.blueprint.BlueprintEntityMixin",
|
||||
"compatibility.create.chain_conveyor.ChainConveyorBlockEntityMixin",
|
||||
"compatibility.create.chain_conveyor.ChainConveyorBlockMixin",
|
||||
"compatibility.create.contraptions.AbstractContraptionEntityMixin",
|
||||
"compatibility.create.contraptions.ContraptionColliderMixin",
|
||||
"compatibility.create.contraptions.Matrix3dAccessor",
|
||||
"compatibility.create.crushing_wheel.CrushingWheelBlockMixin",
|
||||
"compatibility.create.crushing_wheel_entity_processing.CrushingWheelControllerBlockEntityMixin",
|
||||
"compatibility.create.deployer.DeployerBlockEntityMixin",
|
||||
"compatibility.create.display_link.ClickToLinkBlockItemMixin",
|
||||
"compatibility.create.display_link.DisplayLinkBlockEntityMixin",
|
||||
"compatibility.create.display_link.DisplayLinkBlockMixin",
|
||||
"compatibility.create.ejector.EjectorBlockEntityMixin",
|
||||
"compatibility.create.elevator_controls.ElevatorControlsHandlerMixin",
|
||||
"compatibility.create.entity_falls_on_block.BasinBlockMixin",
|
||||
"compatibility.create.entity_falls_on_block.BeltMillstoneBlocksMixin",
|
||||
"compatibility.create.entity_falls_on_block.SawBlockMixin",
|
||||
"compatibility.create.entity_falls_on_block.SeatBlockMixin",
|
||||
"compatibility.create.factory_panel.FactoryPanelConnectionHandlerMixin",
|
||||
"compatibility.create.fans_provide_force.EncasedFanBlockEntityMixin",
|
||||
"compatibility.create.fluid_handling.OpenEndedPipeMixin",
|
||||
"compatibility.create.fluid_tank_heating.BoilerDataMixin",
|
||||
"compatibility.create.flywheel.FlywheelBlockEntityMixin",
|
||||
"compatibility.create.frogports.ChainConveyorBlockEntityMixin",
|
||||
"compatibility.create.frogports.ChainConveyorShapeAccessor",
|
||||
"compatibility.create.frogports.ChainPackageInteractionHandlerMixin",
|
||||
"compatibility.create.frogports.ChainPackageInteractionPacketMixin",
|
||||
"compatibility.create.frogports.FrogportBlockEntityMixin",
|
||||
"compatibility.create.frogports.FrogportBlockMixin",
|
||||
"compatibility.create.frogports.PackagePortPlacementPacketMixin",
|
||||
"compatibility.create.frogports.PackagePortTargetMixin",
|
||||
"compatibility.create.frogports.PackagePortTargetSelectionHandlerMixin",
|
||||
"compatibility.create.funnels.FunnelBlockMixin",
|
||||
"compatibility.create.hose_pulley.HosePulleyBlockEntityMixin",
|
||||
"compatibility.create.hose_pulley.HosePulleyFluidHandlerMixin",
|
||||
"compatibility.create.impact.AbstractBellBlockAccessor",
|
||||
"compatibility.create.impact.AbstractBellBlockMixin",
|
||||
"compatibility.create.inventory_manipulation.CapManipulationBehaviourBaseMixin",
|
||||
"compatibility.create.inventory_manipulation.ChuteBlockEntityMixin",
|
||||
"compatibility.create.lectern_controller.LecternControllerBlockEntityMixin",
|
||||
"compatibility.create.lectern_controller.LecternControllerBlockMixin",
|
||||
"compatibility.create.mechnical_arm.MechanicalArmBlockEntity",
|
||||
"compatibility.create.mechnical_arm.MechanicalArmSublevelFailure",
|
||||
"compatibility.create.nozzle.NozzleBlockEntityAccessor",
|
||||
"compatibility.create.nozzle.block_entity.NozzleBEFixesMixin",
|
||||
"compatibility.create.nozzle.block_entity.NozzleHoveringMixin",
|
||||
"compatibility.create.nozzle.block_entity.ValidNozzledirectionMixin",
|
||||
"compatibility.create.raycast.RaycastHelperMixin",
|
||||
"compatibility.create.redstone_contacts.AllBlockEntityTypesMixin",
|
||||
"compatibility.create.redstone_contacts.RedstoneContactBlockMixin",
|
||||
"compatibility.create.redstone_links.RedstoneLinkNetworkHandlerMixin",
|
||||
"compatibility.create.sails_providing_lift.SailBlockMixin",
|
||||
"compatibility.create.saw.SawBlockEntityMixin",
|
||||
"compatibility.create.schematics.DeployToolMixin",
|
||||
"compatibility.create.schematics.SchematicAndQuillHandlerMixin",
|
||||
"compatibility.create.schematics.SchematicExportMixin",
|
||||
"compatibility.create.schematics.SchematicLevelMixin",
|
||||
"compatibility.create.schematics.SchematicPlacePacketMixin",
|
||||
"compatibility.create.schematics.SchematicPrinterMixin",
|
||||
"compatibility.create.schematics.SchematicToolBaseMixin",
|
||||
"compatibility.create.schematics.StructureTemplateMixin",
|
||||
"compatibility.create.sticker.StickerBlockEntityMixin",
|
||||
"compatibility.create.sticker.StickerBlockMixin",
|
||||
"compatibility.create.stock_ticker.StockTickerInteractionHandlerMixin",
|
||||
"compatibility.create.super_glue.LevelAccessor",
|
||||
"compatibility.create.super_glue.SuperGlueEntityMixin",
|
||||
"compatibility.create.super_glue.SuperGlueRemovalPacketMixin",
|
||||
"compatibility.create.super_glue.SuperGlueSelectionHandlerMixin",
|
||||
"compatibility.create.toolbox.ToolBoxClientHandlerMixin",
|
||||
"compatibility.create.toolbox.ToolboxHandlerMixin",
|
||||
"compatibility.create.tracks.CurvedTrackDestroyPacketMixin",
|
||||
"compatibility.create.tracks.TrackBlockItemMixin",
|
||||
"compatibility.create.tracks.TrackBlockMixin",
|
||||
"compatibility.create.tracks.TrackGraphVisualizerMixin",
|
||||
"compatibility.create.tracks.TrackPlacementMixin",
|
||||
"compatibility.create.turntable.TurntableBlockMixin",
|
||||
"compatibility.create.vertical_gearbox.VerticalGearboxItemMixin",
|
||||
"compatibility.create.zapper.ZapperItemMixin",
|
||||
"compatibility.pmweather.AnemometerBlockEntityMixin",
|
||||
"compatibility.pmweather.AnemometerBlockMixin",
|
||||
"compatibility.pmweather.PMWeatherMixin",
|
||||
"entities_stick_sublevels.effects.LivingEntityMixin",
|
||||
"entity.entity_swimming.EntityMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user