Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.

when did i last touch iridescence on this branch :O

Lera 9bafe317 db22033f

+125 -53
+28 -18
common/src/main/java/net/lerariemann/infinity/iridescence/Iridescence.java
··· 14 14 import net.lerariemann.infinity.entity.custom.ChaosCreeper; 15 15 import net.lerariemann.infinity.entity.custom.ChaosPawn; 16 16 import net.lerariemann.infinity.util.InfinityMethods; 17 - import net.lerariemann.infinity.util.core.RandomProvider; 17 + import net.lerariemann.infinity.util.loading.ShaderLoader; 18 18 import net.lerariemann.infinity.util.teleport.WarpLogic; 19 19 import net.minecraft.block.Block; 20 20 import net.minecraft.entity.EntityType; ··· 72 72 return stack.isIn(ModTags.IRIDESCENT_ITEMS); 73 73 } 74 74 75 - public static boolean isUnderEffect(LivingEntity entity) { 75 + static boolean isUnderEffect(LivingEntity entity) { 76 76 return entity.hasStatusEffect(ModStatusEffects.IRIDESCENT_EFFECT.value()); 77 77 } 78 78 ··· 112 112 StatusEffectInstance cooldown = entity.getStatusEffect(ModStatusEffects.IRIDESCENT_COOLDOWN.value()); 113 113 if (cooldown == null) return original; 114 114 else if (cooldown.getAmplifier() < 1) { 115 - if (original > 0) return 0; 115 + if (original > 0) return original / 2; 116 116 } 117 117 return -1; 118 118 } 119 119 120 120 static int getFullEffectLength(int amplifier) { 121 - return getOnsetLength() + getEffectLength(amplifier); 121 + return getOnsetLength(amplifier) + getEffectLength(amplifier); 122 122 } 123 123 static int getEffectLength(int amplifier) { //amplifier is 0 to 4 124 - return getComeupLength() + getPeakLength(amplifier) + getOffsetLength(); //8 to 12 minutes 124 + return getComeupLength() + getPeakLength(amplifier) + getOffsetLength(amplifier); 125 125 } 126 - static int getOnsetLength() { 127 - return ticksInHour * RandomProvider.ruleInt("iridescenceInitialDuration") / 60; //default is 30 seconds 126 + static int getOnsetLength(int amplifier) { 127 + return ticksInHour * Math.max(20, 60 - 5*amplifier) / 120; 128 128 } 129 129 static int getComeupLength() { 130 130 return ticksInHour; ··· 132 132 static int getPeakLength(int amplifier) { 133 133 return ticksInHour * (4 + amplifier); 134 134 } 135 - static int getOffsetLength() { 136 - return ticksInHour * 3; 135 + static int getOffsetLength(int amplifier) { 136 + return ticksInHour * (4 + amplifier) / 2; 137 137 } 138 138 static int getAfterglowDuration() { 139 - return ticksInHour * RandomProvider.ruleInt("afterglowDuration"); //default is 24 minutes 139 + int minDuration = ticksInHour * 20; 140 + return (int)Math.floor(minDuration * Math.pow(2, InfinityMod.random.nextDouble(-1, 1))); 140 141 } 141 142 static int getCooldownDuration() { 142 - return ticksInHour * RandomProvider.ruleInt("iridescenceCooldownDuration"); //default is 7*24 minutes 143 + return ticksInHour * 7 * 20; 143 144 } 144 145 145 146 enum Phase { ··· 149 150 DOWNWARDS 150 151 } 151 152 152 - public static Phase getPhase(LivingEntity entity) { 153 + static void updateAtomics(int duration, int amplifier) { 154 + ShaderLoader.iridLevel.set(amplifier); 155 + ShaderLoader.iridProgress.set(switch (getPhase(duration, amplifier)) { 156 + case INITIAL -> 0.0; 157 + case UPWARDS -> (getEffectLength(amplifier) - duration) / (1.0 * getComeupLength()); 158 + case PLATEAU -> 1.0; 159 + case DOWNWARDS -> duration / (1.0 * getOffsetLength(amplifier)); 160 + }); 161 + } 162 + 163 + static Phase getPhase(LivingEntity entity) { 153 164 StatusEffectInstance effect = entity.getStatusEffect(ModStatusEffects.IRIDESCENT_EFFECT.value()); 154 165 if (effect == null) return Phase.INITIAL; 155 166 return getPhase(effect.getDuration(), effect.getAmplifier()); ··· 157 168 static Phase getPhase(int duration, int amplifier) { 158 169 int time_passed = getEffectLength(amplifier) - duration; 159 170 if (time_passed < 0) return Phase.INITIAL; 160 - return (time_passed < getComeupLength()) ? Phase.UPWARDS : (duration <= getOffsetLength() || amplifier == 0) ? Phase.DOWNWARDS : Phase.PLATEAU; 171 + return (time_passed < getComeupLength()) ? Phase.UPWARDS : (duration <= getOffsetLength(amplifier) || amplifier == 0) ? Phase.DOWNWARDS : Phase.PLATEAU; 161 172 } 162 173 163 174 static boolean shouldWarp(int duration, int amplifier) { 164 175 return (Iridescence.getPhase(duration, amplifier) == Iridescence.Phase.PLATEAU) && (duration % ticksInHour == 0); 165 176 } 166 177 static boolean shouldReturn(int duration, int amplifier) { 167 - return (amplifier > 0) && (duration == getOffsetLength()); 178 + return (amplifier > 0) && (duration == getOffsetLength(amplifier)); 168 179 } 169 180 static boolean shouldRequestShaderLoad(int duration, int amplifier) { 170 181 int time_passed = getEffectLength(amplifier) - duration; 171 182 return (time_passed == 0); 172 183 } 173 184 174 - public static void loadShader(ServerPlayerEntity player) { 185 + static void loadShader(ServerPlayerEntity player) { 175 186 ServerPlayNetworking.send(player, ModPayloads.SHADER_RELOAD, ModPayloads.buildPacket(player.getServerWorld(), true)); 176 187 } 177 - public static void unloadShader(ServerPlayerEntity player) { 188 + static void unloadShader(ServerPlayerEntity player) { 178 189 ServerPlayNetworking.send(player, ModPayloads.SHADER_RELOAD, ModPayloads.buildPacket(player.getServerWorld(), false)); 179 190 } 180 191 ··· 212 223 } 213 224 214 225 static void endJourney(ServerPlayerEntity player, boolean isEarlyCancel, int amplifier) { 215 - player.setInvulnerable(false); 216 226 if (!isEarlyCancel) { 217 227 player.increaseStat(ModStats.IRIDESCENCE, 1); 218 228 if (amplifier != 0) ··· 248 258 return (convertibles.containsKey(entity.getType()) || (entity instanceof ChaosPawn pawn && pawn.isBlackOrWhite())); 249 259 } 250 260 251 - public static void tryApplyEffect(MobEntity ent) { 261 + static void tryApplyEffect(MobEntity ent) { 252 262 if (!ent.hasStatusEffect(ModStatusEffects.IRIDESCENT_EFFECT.value())) { 253 263 if (ent instanceof FishEntity) 254 264 ent.addStatusEffect(new StatusEffectInstance(ModStatusEffects.IRIDESCENT_EFFECT.value(), ticksInHour, 0,
+21 -7
common/src/main/java/net/lerariemann/infinity/iridescence/IridescentEffect.java
··· 1 1 package net.lerariemann.infinity.iridescence; 2 2 3 + import net.lerariemann.infinity.InfinityMod; 3 4 import net.lerariemann.infinity.entity.custom.ChaosPawn; 5 + import net.lerariemann.infinity.util.core.RandomProvider; 6 + import net.lerariemann.infinity.util.loading.ShaderLoader; 4 7 import net.lerariemann.infinity.util.teleport.WarpLogic; 5 8 import net.lerariemann.infinity.registry.core.ModStatusEffects; 6 9 import net.minecraft.entity.LivingEntity; ··· 12 15 import net.minecraft.entity.mob.Angerable; 13 16 import net.minecraft.entity.mob.MobEntity; 14 17 import net.minecraft.entity.player.PlayerEntity; 15 - import net.minecraft.particle.ParticleEffect; 16 18 import net.minecraft.server.network.ServerPlayerEntity; 17 19 import net.minecraft.sound.SoundEvents; 18 20 import net.minecraft.util.Identifier; ··· 42 44 if (Objects.requireNonNull(entity) instanceof PlayerEntity player) { 43 45 if (player instanceof ServerPlayerEntity serverPlayer) { 44 46 unloadShader(serverPlayer); 45 - if (player.isInvulnerable()) endJourney(serverPlayer, true, 0); 47 + player.setInvulnerable(false); 48 + if (Iridescence.getPhase(entity) == Iridescence.Phase.PLATEAU) endJourney(serverPlayer, true, 0); 46 49 } 47 50 } else if (entity instanceof ChaosPawn pawn) { 48 51 if (pawn.getRandom().nextBoolean()) { ··· 60 63 if (entity instanceof PlayerEntity player) { 61 64 if (player instanceof ServerPlayerEntity serverPlayer) { 62 65 if (shouldWarp(duration, amplifier)) { 63 - if (!player.isInvulnerable()) { 64 - player.setInvulnerable(true); 66 + if (Iridescence.getPhase(duration + ticksInHour, amplifier) != Iridescence.Phase.PLATEAU) { //the first warp 67 + if (RandomProvider.rule("iridSafeMode")) player.setInvulnerable(true); 65 68 saveCookie(serverPlayer); 66 69 } 67 70 Identifier id = getIdForWarp(serverPlayer); 68 71 WarpLogic.requestWarp(serverPlayer, id, false); 69 72 } 70 73 if (shouldReturn(duration, amplifier)) { 74 + player.setInvulnerable(false); 71 75 endJourney(serverPlayer, false, amplifier); 72 76 } 73 77 if (shouldRequestShaderLoad(duration, amplifier)) 74 78 loadShader(serverPlayer); 79 + 80 + if (amplifier == 0 && duration == 2) { 81 + player.addStatusEffect(new StatusEffectInstance(ModStatusEffects.AFTERGLOW.value(), 82 + getAfterglowDuration() / 2, 0, true, true)); 83 + } 75 84 } 76 - if (amplifier == 0 && duration == 2) { 77 - player.addStatusEffect(new StatusEffectInstance(ModStatusEffects.AFTERGLOW.value(), 78 - getAfterglowDuration() / 2, 0, true, true)); 85 + else { 86 + Iridescence.updateAtomics(duration, amplifier); 87 + if (amplifier == 0) return; 88 + double prog = ShaderLoader.iridProgress.get(); 89 + if (prog > 0.5) { 90 + if (InfinityMod.random.nextDouble() < 0.015*(2*prog - 1)*amplifier) 91 + entity.playSound(SoundEvents.BLOCK_AMETHYST_BLOCK_CHIME, 1.0f, 1f + InfinityMod.random.nextFloat()); 92 + } 79 93 } 80 94 } 81 95 }
+6 -3
common/src/main/java/net/lerariemann/infinity/item/IridescentPotionItem.java
··· 28 28 import java.util.List; 29 29 30 30 public class IridescentPotionItem extends Item { 31 - public IridescentPotionItem(Settings settings) { 31 + int level; 32 + 33 + public IridescentPotionItem(Settings settings, int level) { 32 34 super(settings); 35 + this.level = level; 33 36 } 34 37 35 38 @Override ··· 39 42 40 43 @Override 41 44 public ItemStack finishUsing(ItemStack stack, World world, LivingEntity user) { 42 - int level = BackportMethods.getOrDefaultInt(stack, ModComponentTypes.F4_CHARGE, 0); 45 + int level = BackportMethods.getOrDefaultInt(stack, ModComponentTypes.F4_CHARGE, -1); 46 + if (level < 0) level = this.level; 43 47 if (!world.isClient) Iridescence.tryBeginJourney(user, level, true); 44 48 if (user instanceof PlayerEntity player) { 45 49 if (user instanceof ServerPlayerEntity spe) { ··· 51 55 stack.decrement(1); 52 56 player.getInventory().insertStack(new ItemStack(Items.GLASS_BOTTLE)); 53 57 } 54 - 55 58 } 56 59 else if (stack.isEmpty()) { 57 60 return new ItemStack(Items.GLASS_BOTTLE);
+15
common/src/main/java/net/lerariemann/infinity/mixin/iridescence/PostEffectProcessorMixin.java
··· 1 1 package net.lerariemann.infinity.mixin.iridescence; 2 2 3 + import net.lerariemann.infinity.util.loading.ShaderLoader; 4 + import net.minecraft.client.MinecraftClient; 3 5 import net.minecraft.client.gl.PostEffectPass; 4 6 import net.minecraft.client.gl.PostEffectProcessor; 5 7 import org.spongepowered.asm.mixin.Final; 6 8 import org.spongepowered.asm.mixin.Mixin; 7 9 import org.spongepowered.asm.mixin.Shadow; 10 + import org.spongepowered.asm.mixin.Unique; 8 11 import org.spongepowered.asm.mixin.injection.At; 9 12 import org.spongepowered.asm.mixin.injection.Inject; 10 13 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 14 15 + import java.time.LocalTime; 12 16 import java.util.List; 13 17 14 18 @Mixin(PostEffectProcessor.class) ··· 24 28 @Shadow 25 29 private float lastTickDelta; 26 30 31 + @Unique 32 + public void infinity$setUniforms(String name, float value) { 33 + for (PostEffectPass postEffectPass : this.passes) { 34 + postEffectPass.getProgram().getUniformByNameOrDummy(name).set(value); 35 + } 36 + } 37 + 27 38 /* Hook for the iridescence shader to receive the time uniform */ 28 39 @Inject(method="render", at = @At("HEAD"), cancellable = true) 29 40 void inj(float tickDelta, CallbackInfo ci) { 30 41 if (name.contains("infinity")) { 42 + infinity$setUniforms("IridTimeSec", ((int)(LocalTime.now().toNanoOfDay() / 1000000)) / 1000.0f); 43 + infinity$setUniforms("IridLevel", ShaderLoader.iridLevel.get()); 44 + infinity$setUniforms("IridProgress", (float)ShaderLoader.iridProgress.get()); 45 + infinity$setUniforms("IridDistortion", MinecraftClient.getInstance().options.getDistortionEffectScale().getValue().floatValue()); 31 46 if (tickDelta < this.lastTickDelta) { 32 47 this.time += 1.0F - this.lastTickDelta; 33 48 this.time += tickDelta;
+2 -2
common/src/main/java/net/lerariemann/infinity/registry/core/ModItems.java
··· 106 106 registerItemAfter("f4", ItemGroups.TOOLS, Items.WRITABLE_BOOK, F4Item::new, 107 107 new Item.Settings().rarity(Rarity.UNCOMMON)); 108 108 public static final RegistrySupplier<Item> IRIDESCENT_POTION = 109 - registerItemAfter("iridescent_potion", ItemGroups.FOOD_AND_DRINK, Items.HONEY_BOTTLE, IridescentPotionItem::new, 109 + registerItemAfter("iridescent_potion", ItemGroups.FOOD_AND_DRINK, Items.HONEY_BOTTLE, (s) -> new IridescentPotionItem(s, 4), 110 110 new Item.Settings()); 111 111 public static final RegistrySupplier<Item> CHROMATIC_POTION = 112 - registerItemAfter("chromatic_potion", ItemGroups.FOOD_AND_DRINK, Items.HONEY_BOTTLE, IridescentPotionItem::new, 112 + registerItemAfter("chromatic_potion", ItemGroups.FOOD_AND_DRINK, Items.HONEY_BOTTLE, (s) -> new IridescentPotionItem(s, 0), 113 113 new Item.Settings()); 114 114 115 115 public static <T extends Item> RegistrySupplier<T> register(String item, Item.Settings settings, Function<Item.Settings, T> constructor) {
+9 -2
common/src/main/java/net/lerariemann/infinity/util/loading/ShaderLoader.java
··· 1 1 package net.lerariemann.infinity.util.loading; 2 2 3 + import com.google.common.util.concurrent.AtomicDouble; 3 4 import net.fabricmc.api.EnvType; 4 5 import net.fabricmc.api.Environment; 5 6 import net.lerariemann.infinity.access.GameRendererAccess; ··· 13 14 import java.io.IOException; 14 15 import java.nio.file.Files; 15 16 import java.nio.file.Path; 17 + import java.util.concurrent.atomic.AtomicInteger; 16 18 17 19 @Environment(EnvType.CLIENT) 18 20 public interface ShaderLoader { 19 21 String FILENAME = "current.json"; 22 + AtomicInteger iridLevel = new AtomicInteger(-1); 23 + AtomicDouble iridProgress = new AtomicDouble(0.0); 24 + 20 25 static Path shaderDir(MinecraftClient client) { 21 26 return client.getResourcePackDir().resolve("infinity/assets/infinity/shaders"); 22 27 } ··· 31 36 ((GameRendererAccess)(client.gameRenderer)).infinity$loadPP(InfinityMethods.getId("shaders/post/iridescence.json")); 32 37 return; 33 38 } 39 + iridLevel.set(-1); 40 + iridProgress.set(0.0); 34 41 try { 35 - load(client); 42 + updateWorldShaderFromDisk(client); 36 43 } catch (IOException e) { 37 44 throw new RuntimeException(e); 38 45 } ··· 43 50 client.gameRenderer.disablePostProcessor(); 44 51 } 45 52 46 - static void load(MinecraftClient client) throws IOException { 53 + static void updateWorldShaderFromDisk(MinecraftClient client) throws IOException { 47 54 ResourcePackManager m = client.getResourcePackManager(); 48 55 Path path = client.getResourcePackDir().resolve("infinity"); 49 56 String name = "file/" + path.getFileName().toString();
+36 -15
common/src/main/resources/assets/infinity/shaders/program/color_wheel.fsh
··· 1 1 #version 150 2 2 precision mediump float; 3 3 uniform float Time; //0 to 1 4 + uniform float IridTimeSec; 5 + uniform float IridLevel; 6 + uniform float IridProgress; 7 + uniform float IridDistortion; 4 8 uniform sampler2D DiffuseSampler; 5 9 6 10 in vec2 texCoord; ··· 11 15 12 16 float random (in vec3 st) { 13 17 return fract(sin(dot(st, 14 - vec3(12.9898,78.233,4.1414)))* 15 - 43758.5453123); 18 + vec3(12.9898,78.233,4.1414)))* 19 + 43758.5453123); 16 20 } 17 21 float noise (in vec3 st) { 18 22 vec3 i = floor(st); ··· 29 33 30 34 vec3 u = f * f * (3.0 - 2.0 * f); 31 35 return mix( 32 - mix( 33 - mix(a, b, u.x), 34 - mix(c, d, u.x), 35 - u.y), 36 - mix( 37 - mix(a1, b1, u.x), 38 - mix(c1, d1, u.x), 39 - u.y), 40 - u.z); 36 + mix( 37 + mix(a, b, u.x), 38 + mix(c, d, u.x), 39 + u.y), 40 + mix( 41 + mix(a1, b1, u.x), 42 + mix(c1, d1, u.x), 43 + u.y), 44 + u.z); 41 45 } 42 46 43 47 void main() { 44 - vec4 InTexel = texture(DiffuseSampler, texCoord); 45 - float time = 2*Time*3.1415f; 46 - float iTime = 10*time + 1.5*noise(vec3(1.5*screenCoords, 3*(time > 0.5 ? 1 - time : time))); 48 + float noiseScale1 = 1.0f + IridLevel/2.0f; //1 to 3 49 + float noiseScale2 = 1.5f + IridLevel/4.0f; //1.5 to 2.5 50 + 51 + float twopi = 6.2832f; 52 + float time = twopi*(IridTimeSec / 10.0f); 53 + float alpha = IridProgress > 0.5 ? 1 : 2*IridProgress; 54 + 55 + float primaryColor = 2*fract(IridTimeSec / 20.0f); 56 + primaryColor = twopi*alpha*((primaryColor > 1) ? 2 - primaryColor : primaryColor); 57 + if (fract(IridTimeSec / 40.0f) > 0.5) primaryColor = -primaryColor; 58 + 59 + float iTime = primaryColor + IridProgress*noiseScale2*noise(vec3(noiseScale1*screenCoords, 0.2*noiseScale2*time)); 60 + 47 61 float a = (1.0f - cos(iTime))/3.0f + cos(iTime); 48 62 float b = (1.0f - cos(iTime))/3.0f - sin(iTime) / sqrt(3); 49 63 float c = (1.0f - cos(iTime))/3.0f + sin(iTime) / sqrt(3); 50 64 65 + float warpScale = 0.1 * IridDistortion * IridProgress * IridLevel / 12; 66 + float edgeFactor = 1 - 2*min(min(texCoord.x, 1 - texCoord.x), min(texCoord.y, 1 - texCoord.y)); 67 + float texOffsetX = noise(vec3(3*screenCoords, 0.5*(time + 10000))) - 0.5; 68 + float texOffsetY = noise(vec3(3*screenCoords, 0.5*(time - 10000))) - 0.5; 69 + vec2 finalCoord = texCoord + warpScale*(1 - edgeFactor*edgeFactor)*vec2(texOffsetX, texOffsetY); 70 + vec4 InTexel = texture(DiffuseSampler, finalCoord); 71 + 51 72 float RedValue = dot(InTexel.rgb, vec3(a, b, c)); 52 73 float GreenValue = dot(InTexel.rgb, vec3(c, a, b)); 53 74 float BlueValue = dot(InTexel.rgb, vec3(b, c, a)); ··· 56 77 57 78 float Luma = dot(OutColor, vec3(0.3, 0.59, 0.11)); 58 79 vec3 Chroma = OutColor - Luma; 59 - OutColor = (Chroma * 1.8) + Luma; 80 + OutColor = Chroma * (1 + alpha*(0.5 + 0.1*IridLevel)) + Luma; 60 81 61 82 fragColor = vec4(OutColor, 1.0); 62 83 }
+5 -1
common/src/main/resources/assets/infinity/shaders/program/color_wheel.json
··· 14 14 { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, 15 15 { "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, 16 16 { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, 17 - { "name": "Time", "type": "float", "count": 1, "values": [ 0.01 ]} 17 + { "name": "Time", "type": "float", "count": 1, "values": [ 0.01 ]}, 18 + { "name": "IridTimeSec", "type": "float", "count": 1, "values": [ 0.0 ]}, 19 + { "name": "IridLevel", "type": "float", "count": 1, "values": [ 0.0 ]}, 20 + { "name": "IridProgress", "type": "float", "count": 1, "values": [ 0.0 ]}, 21 + { "name": "IridDistortion", "type": "float", "count": 1, "values": [ 0.0 ]} 18 22 ] 19 23 }
+2 -4
common/src/main/resources/config/infinity.json
··· 1 1 { 2 - "infinity_version": 2004003, 2 + "infinity_version": 2004007, 3 3 "gameRules": { 4 4 "runtimeGenerationEnabled": true, 5 5 "longArithmeticEnabled": false, ··· 10 10 "pawnsCanDropIllegalItems": false, 11 11 "useSoundSyncPackets": true, 12 12 "enforceModLoadedChecks": true, 13 + "iridSafeMode": false, 13 14 "maxBiomeCount": 6, 14 15 "maxDimensionScale": 0, 15 16 "avgDimensionHeight": 256, 16 - "iridescenceInitialDuration": 30, 17 - "iridescenceCooldownDuration": 168, 18 - "afterglowDuration": 24, 19 17 "resetChargeCooldown": 6000 20 18 }, 21 19 "disabledDimensions": ["ant", "bash", "checkerboard",
+1 -1
gradle.properties
··· 3 3 org.gradle.parallel=true 4 4 5 5 # Mod properties 6 - mod_version = 2.4.6 6 + mod_version = 2.4.7 7 7 maven_group = net.lerariemann 8 8 archives_name = infinity 9 9 enabled_platforms = fabric,forge