Skip to content

Commit

Permalink
Merge pull request #224 from lonefelidae16/feat/sun-glare
Browse files Browse the repository at this point in the history
[feat] Bedrock Sun Glare and Sky Color
  • Loading branch information
juancarloscp52 committed Feb 25, 2023
2 parents c393cff + 2de4526 commit 180c2ea
Show file tree
Hide file tree
Showing 16 changed files with 492 additions and 12 deletions.
12 changes: 11 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'fabric-loom' version '0.12.47'
id 'fabric-loom' version '1.1-SNAPSHOT'
id 'maven-publish'
}

Expand All @@ -24,6 +24,8 @@ loom {
runDir "build/datagen"
}
}

createRemapConfigurations(sourceSets.test)
}

sourceSets {
Expand All @@ -43,6 +45,7 @@ repositories {
}
maven { url "https://maven.shedaniel.me/" }
maven { url "https://maven.ryanliptak.com/" } // AppleSkin
maven { url "https://api.modrinth.com/maven" } // Iris
}

dependencies {
Expand All @@ -62,6 +65,13 @@ dependencies {
modCompileOnly("squeek.appleskin:appleskin-fabric:${project.apple_skin}:api") {
transitive = false
}

testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
modTestImplementation "maven.modrinth:iris:${project.iris_version}"
}

test {
useJUnitPlatform()
}

processResources {
Expand Down
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ org.gradle.jvmargs=-Xmx2048m
fabric_version=0.69.1+1.19.3
modmenu_version=5.0.2
cloth_config_version=9.0.94
apple_skin=mc1.19.3-2.4.2
apple_skin=mc1.19.3-2.4.2
iris_version=1.5.1+1.19.3
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.gson.Gson;
import me.juancarloscp52.bedrockify.Bedrockify;
import me.juancarloscp52.bedrockify.client.features.bedrockShading.BedrockBlockShading;
import me.juancarloscp52.bedrockify.client.features.bedrockShading.BedrockSunGlareShading;
import me.juancarloscp52.bedrockify.client.features.fishingBobber.FishingBobber3DModel;
import me.juancarloscp52.bedrockify.client.features.heldItemTooltips.HeldItemTooltips;
import me.juancarloscp52.bedrockify.client.features.hudOpacity.HudOpacity;
Expand Down Expand Up @@ -45,6 +46,7 @@ public class BedrockifyClient implements ClientModInitializer {
public SettingsGUI settingsGUI;
public WorldColorNoiseSampler worldColorNoiseSampler;
public BedrockBlockShading bedrockBlockShading;
public BedrockSunGlareShading bedrockSunGlareShading;
public HudOpacity hudOpacity;
public long deltaTime = 0;
private int timeFlying = 0;
Expand All @@ -66,6 +68,7 @@ public void onInitializeClient() {
settingsGUI=new SettingsGUI();
worldColorNoiseSampler = new WorldColorNoiseSampler();
bedrockBlockShading = new BedrockBlockShading();
bedrockSunGlareShading = new BedrockSunGlareShading();
hudOpacity = new HudOpacity();
keyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding("bedrockIfy.key.settings", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_B, "BedrockIfy"));

Expand Down Expand Up @@ -99,6 +102,7 @@ public void onInitializeClient() {
client.setScreen(settingsGUI.getConfigScreen(client.currentScreen,true));
}
hudOpacity.tick();
bedrockSunGlareShading.tick(client.getTickDelta());

// Stop flying drift
if(settings.disableFlyingMomentum && null != client.player && client.player.getAbilities().flying){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class BedrockifyClientSettings {
public boolean elytraStop = true;
public boolean pickupAnimations = true;
public boolean fishingBobber3D = true;
public int sunlightIntensity = 50;

public boolean isPickupAnimationsEnabled() {
return pickupAnimations;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
package me.juancarloscp52.bedrockify.client.features.bedrockShading;

import com.google.common.collect.Maps;
import me.juancarloscp52.bedrockify.Bedrockify;
import me.juancarloscp52.bedrockify.client.BedrockifyClient;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.util.Util;
import net.minecraft.util.math.MathHelper;
import org.jetbrains.annotations.NotNull;
import org.joml.Math;
import org.joml.Vector3f;

import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* Helper class for the sun glare and the sky color like Bedrock.<br>
* Compatible with Custom Shader mods.
*/
public final class BedrockSunGlareShading {
/**
* Test cases of the {@link ClassMethodHolder} specified by modID.<br>
* See also the unittest package <code>me.juancarloscp52.bedrockify.test.client.features.bedrockShading.sunGlare</code>.
*/
private static final Map<String, ClassMethodHolder> MOD_ID_CLASS_MAP = Util.make(Maps.newHashMap(), (map) -> {
map.put("iris", new ClassMethodHolder("net.coderbot.iris.Iris", "getCurrentPack", new Object[0], (pack) -> {
return ((Optional<?>) pack).isPresent();
}));
});
private static final List<ClassMethodHolder> METHOD_INVOCATION_FAILED_LIST = new ArrayList<>();

private ShaderState shaderState = ShaderState.UNSPECIFIED;
private float skyAttenuation;
private float sunAngleDiff;
private final Vector3f sunVector3f;
private final MinecraftClient client;

public BedrockSunGlareShading() {
onSunlightIntensityChanged();
this.sunVector3f = new Vector3f();
this.client = MinecraftClient.getInstance();
}

/**
* Shows the state of Custom Shader.
*
* @see ShaderState#UNSPECIFIED
* @see ShaderState#VANILLA
* @see ShaderState#EXTERNAL
* @see ShaderState#INVOCATION_FAILED
*/
private enum ShaderState {
/**
* Initial state.
*/
UNSPECIFIED,
/**
* Shader mod is not installed, or external shader is not enabled.
*/
VANILLA,
/**
* Shader mod is present and enabled.
*/
EXTERNAL,
/**
* Shader mod is present, but method invocation failed.
*/
INVOCATION_FAILED
}

/**
* The data only class that holds the name of class, method, and args of method invocation.<br>
* Only supports static method.<br>
* This class is used with package {@link java.lang.reflect}.
*/
private static class ClassMethodHolder {
public final String canonicalName;
public final String methodName;
@NotNull
public final Object[] methodArgs;
@NotNull
public final Predicate<Object> condition;

/**
* Disable feature without method invocation.
*/
public static final ClassMethodHolder CONDITION_TRUE;

static {
CONDITION_TRUE = new ClassMethodHolder("", "", null, object -> true);
}

/**
* @param cName Class canonical name.
* @param mName Method name to invoke.
* @param mArgs Method arguments to invoke.
* @param condition {@link Predicate} for the condition whether the external shader is valid. If returns <code>true</code>, Sun Glare shading will be disabled.
*/
protected ClassMethodHolder(String cName, String mName, @NotNull Object[] mArgs, @NotNull Predicate<Object> condition) {
this.canonicalName = cName;
this.methodName = mName;
this.methodArgs = mArgs;
this.condition = condition;
}
}

public boolean shouldApplyShading() {
return this.shaderState == ShaderState.VANILLA &&
BedrockifyClient.getInstance().settings.bedrockShading &&
this.skyAttenuation < 1f;
}

public void reloadCustomShaderState() {
this.shaderState = this.fetchShaderStateInternal();
}

/**
* Determine the state of Custom Shader.
*
* @see ShaderState
*/
private ShaderState fetchShaderStateInternal() {
if (FabricLoader.getInstance().isModLoaded("optifabric")) {
// Unreachable statement.
// BedrockShading feature is disabled by BedrockIfyMixinPlugin#shouldApplyMixin if optifabric detected. How did you reach here?
return ShaderState.EXTERNAL;
}

boolean enabled = false;

for (Map.Entry<String, ClassMethodHolder> entry : MOD_ID_CLASS_MAP.entrySet()) {
final String modId = entry.getKey();
if (!FabricLoader.getInstance().isModLoaded(modId)) {
// The class probably absent because the mod has not been loaded.
continue;
}

final ClassMethodHolder holder = entry.getValue();
// Check invalid state.
if (METHOD_INVOCATION_FAILED_LIST.contains(holder)) {
return ShaderState.INVOCATION_FAILED;
}

if (holder.canonicalName.isEmpty() || holder.methodName.isEmpty() || holder.methodArgs == null) {
enabled |= holder.condition.test(null);
continue;
}

try {
// Get the class.
final Class<?> clazz = Class.forName(holder.canonicalName);

// Get the method.
final Method invoker = clazz.getMethod(holder.methodName, Arrays.stream(holder.methodArgs).map(Object::getClass).toArray(Class[]::new));
invoker.setAccessible(true);

// Execute invocation and store the result.
enabled |= holder.condition.test(invoker.invoke(clazz, holder.methodArgs));
} catch (Throwable ex) {
// Method invocation failed.
if (!METHOD_INVOCATION_FAILED_LIST.contains(holder)) {
METHOD_INVOCATION_FAILED_LIST.add(holder);

// Output the log only once.
final String message = String.format("[%s] method invocation failed into \"%s::%s(%s)\", provided by the mod \"%s\".",
Bedrockify.class.getSimpleName(),
holder.canonicalName,
holder.methodName,
Arrays.stream(holder.methodArgs).map(arg -> arg.getClass().getSimpleName()).collect(Collectors.joining(", ")),
modId
);
BedrockifyClient.LOGGER.error(message, ex);
}

// Output the log only once.
if (shaderState != ShaderState.INVOCATION_FAILED) {
BedrockifyClient.LOGGER.warn("[{}] Shader mod is present, but cannot determine the shader state. BedrockIfy Sun Glare Shading is now disabled.", Bedrockify.class.getSimpleName());
}

return ShaderState.INVOCATION_FAILED;
}
} // End of the MOD_ID_CLASS_MAP for-each loop.

// Output the log only once.
if (enabled && shaderState != ShaderState.EXTERNAL) {
BedrockifyClient.LOGGER.info("[{}] The condition matches. BedrockIfy Sun Glare Shading is now disabled.", Bedrockify.class.getSimpleName());
}
return (enabled) ? ShaderState.EXTERNAL : ShaderState.VANILLA;
}

/**
* Tick event callback to calculate the sun vector.
*
* @param tickDelta TickDelta to determine the SkyAngle.
*/
public void tick(float tickDelta) {
if (!this.shouldApplyShading()) {
return;
}

if (this.client == null || this.client.world == null) {
return;
}

if (this.client.isPaused()) {
return;
}

final float skyAngleRadian = (float) (this.client.world.getSkyAngle(tickDelta) * 2f * Math.PI);
this.sunVector3f.set(new Vector3f(-Math.sin(skyAngleRadian), Math.cos(skyAngleRadian), 0).normalize());
}

/**
* Helper method that updates the angle difference between Camera and Sun.<br>
* The result will be stored to {@link BedrockSunGlareShading#sunAngleDiff};
* a dot product of camera vector and sun vector including some factors, clamped between <code>0.0 - 1.0</code>.
*
* @see BedrockSunGlareShading#getSunAngleDiff
*/
public void updateAngleDiff() {
final float clampMax = 1f;
final float clampMin = 0f;

if (this.client == null || this.client.world == null || this.client.gameRenderer == null || !this.shouldApplyShading()) {
this.sunAngleDiff = clampMax;
return;
}

if (this.client.isPaused()) {
return;
}

final float sunSetRiseFactor = (this.sunVector3f.y < 0) ? this.sunVector3f.y * -5f : 0;
final Camera camera = this.client.gameRenderer.getCamera();
final Vector3f cameraVec3f = new Vector3f(0, 0, 1).rotate(camera.getRotation()).normalize();

this.sunAngleDiff = Math.clamp(clampMin, clampMax, (Math.safeAcos(cameraVec3f.dot(this.sunVector3f)) - 0.15f) * 2.f + sunSetRiseFactor);
}

public float getSunAngleDiff() {
return this.sunAngleDiff;
}

public float getSkyAttenuation() {
return this.skyAttenuation;
}

public void onSunlightIntensityChanged() {
this.skyAttenuation = MathHelper.clampedLerp(1f, 0.35f, BedrockifyClient.getInstance().settings.sunlightIntensity / 100f);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,14 @@ public Screen getConfigScreen(Screen parent, boolean isTransparent){
guiImprovements.add(entryBuilder.startBooleanToggle(Text.translatable("bedrockify.options.eatingAnimations"), settingsClient.eatingAnimations).setDefaultValue(true).setSaveConsumer(newValue -> settingsClient.eatingAnimations=newValue).build());
guiImprovements.add(entryBuilder.startBooleanToggle(Text.translatable("bedrockify.options.pickupAnimations"), settingsClient.pickupAnimations).setTooltip(wrapLines(Text.translatable("bedrockify.options.pickupAnimations.tooltip"))).setDefaultValue(true).setSaveConsumer(newValue -> settingsClient.pickupAnimations=newValue).build());
guiImprovements.add(entryBuilder.startBooleanToggle(Text.translatable("bedrockify.options.loadingScreen"), settingsClient.loadingScreen).setDefaultValue(true).setSaveConsumer(newValue -> settingsClient.loadingScreen=newValue).build());
guiImprovements.add(entryBuilder.startBooleanToggle(Text.translatable("bedrockify.options.bedrockShading"), settingsClient.bedrockShading).setDefaultValue(true).setSaveConsumer(newValue -> {
guiImprovements.add(entryBuilder.startBooleanToggle(Text.translatable("bedrockify.options.bedrockShading"), settingsClient.bedrockShading).setTooltip(wrapLines(Text.translatable("bedrockify.options.bedrockShading.tooltip"))).setDefaultValue(true).setSaveConsumer(newValue -> {
settingsClient.bedrockShading=newValue;
MinecraftClient.getInstance().worldRenderer.reload();
}).build());
guiImprovements.add(entryBuilder.startIntSlider(Text.translatable("bedrockify.options.sunlightIntensity"), settingsClient.sunlightIntensity,0,100).setTooltip(wrapLines(Text.translatable("bedrockify.options.sunlightIntensity.tooltip"))).setDefaultValue(50).setSaveConsumer(newValue -> {
settingsClient.sunlightIntensity = newValue;
BedrockifyClient.getInstance().bedrockSunGlareShading.onSunlightIntensityChanged();
}).build());
general.addEntry(guiImprovements.build());
SubCategoryBuilder reachAround = entryBuilder.startSubCategory(Text.translatable("bedrockify.options.subCategory.Reach-Around"));
reachAround.add(entryBuilder.startTextDescription(Text.translatable("bedrockify.options.subCategory.Reach-Around.description")).build());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.juancarloscp52.bedrockify.mixin.client.features.bedrockShading;
package me.juancarloscp52.bedrockify.mixin.client.features.bedrockShading.lightBlock;

import me.juancarloscp52.bedrockify.client.BedrockifyClient;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractQuadRenderer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.juancarloscp52.bedrockify.mixin.client.features.bedrockShading;
package me.juancarloscp52.bedrockify.mixin.client.features.bedrockShading.lightBlock;

import me.juancarloscp52.bedrockify.client.BedrockifyClient;
import net.minecraft.block.BlockState;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.juancarloscp52.bedrockify.mixin.client.features.bedrockShading;
package me.juancarloscp52.bedrockify.mixin.client.features.bedrockShading.lightBlock;

import me.juancarloscp52.bedrockify.client.BedrockifyClient;
import net.minecraft.block.BlockState;
Expand Down

0 comments on commit 180c2ea

Please sign in to comment.