Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
at master 184 lines 8.6 kB view raw
1package net.lerariemann.infinity.registry.var; 2 3import com.mojang.serialization.Codec; 4import com.mojang.serialization.MapCodec; 5import com.mojang.serialization.codecs.RecordCodecBuilder; 6import dev.architectury.registry.registries.DeferredRegister; 7import net.lerariemann.infinity.InfinityMod; 8import net.lerariemann.infinity.util.core.CommonIO; 9import net.lerariemann.infinity.util.var.TextData; 10import net.minecraft.MethodsReturnNonnullByDefault; 11import net.minecraft.core.registries.Registries; 12import net.minecraft.util.KeyDispatchDataCodec; 13import net.minecraft.world.level.levelgen.SurfaceRules; 14import net.lerariemann.infinity.mixin.core.MaterialRuleContextAccess; 15import org.apache.commons.io.FileUtils; 16 17import java.io.File; 18import java.io.IOException; 19import java.nio.charset.StandardCharsets; 20import java.util.*; 21 22import static net.lerariemann.infinity.InfinityMod.LOGGER; 23import static net.lerariemann.infinity.InfinityMod.MOD_ID; 24 25@MethodsReturnNonnullByDefault 26public class ModMaterialConditions { 27 public record LinearCondition(double k_x, double k_y, double k_z, double min, double max, int separation) implements SurfaceRules.ConditionSource 28 { 29 public static final KeyDispatchDataCodec<LinearCondition> CODEC = KeyDispatchDataCodec.of(RecordCodecBuilder.mapCodec(instance -> instance.group( 30 (Codec.DOUBLE.fieldOf("k_x").orElse(1.0).forGetter(a -> a.k_x)), 31 (Codec.DOUBLE.fieldOf("k_y").orElse(0.0).forGetter(a -> a.k_y)), 32 (Codec.DOUBLE.fieldOf("k_z").orElse(1.0).forGetter(a -> a.k_z)), 33 (Codec.DOUBLE.fieldOf("min").orElse(0.0).forGetter(a -> a.min)), 34 (Codec.DOUBLE.fieldOf("max").orElse(0.5).forGetter(a -> a.max)), 35 (Codec.INT.fieldOf("separation").orElse(16).forGetter(a -> a.separation)) 36 ).apply(instance, LinearCondition::new))); 37 38 @Override 39 public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() { 40 return CODEC; 41 } 42 43 @Override 44 public SurfaceRules.Condition apply(SurfaceRules.Context materialRuleContext) { 45 class LinearPredicate extends SurfaceRules.LazyYCondition { 46 LinearPredicate() { 47 super(materialRuleContext); 48 } 49 50 double scale() { 51 return Math.sqrt(k_x*k_x + k_y*k_y + k_z*k_z); 52 } 53 public boolean compute() { 54 int x = ((MaterialRuleContextAccess)(Object)(this.context)).getBlockX(); 55 int y = ((MaterialRuleContextAccess)(Object)(this.context)).getBlockY(); 56 int z = ((MaterialRuleContextAccess)(Object)(this.context)).getBlockZ(); 57 double res = (k_x * x + k_y * y + k_z * z)/(separation*scale()); 58 res = res - Math.floor(res); 59 return (res > min) && (res < max); 60 } 61 } 62 return new LinearPredicate(); 63 } 64 } 65 66 public record CheckerboardCondition(int size) implements SurfaceRules.ConditionSource 67 { 68 public static final KeyDispatchDataCodec<CheckerboardCondition> CODEC = KeyDispatchDataCodec.of(RecordCodecBuilder.mapCodec(instance -> instance.group( 69 (Codec.INT.fieldOf("size").orElse(1).forGetter(a -> a.size)) 70 ).apply(instance, CheckerboardCondition::new))); 71 72 @Override 73 public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() { 74 return CODEC; 75 } 76 77 @Override 78 public SurfaceRules.Condition apply(SurfaceRules.Context materialRuleContext) { 79 class CheckerboardPredicate extends SurfaceRules.LazyYCondition { 80 CheckerboardPredicate() { 81 super(materialRuleContext); 82 } 83 84 public int sign(int coord) { 85 if (coord < 0) return -sign(-1-coord); 86 return ((coord / size) % 2)*2 - 1; 87 } 88 public boolean compute() { 89 int x = sign(((MaterialRuleContextAccess)(Object)(this.context)).getBlockX()); 90 int z = sign(((MaterialRuleContextAccess)(Object)(this.context)).getBlockZ()); 91 return (x > 0) ^ (z > 0); 92 } 93 } 94 95 return new CheckerboardPredicate(); 96 } 97 } 98 99 public record TextCondition(int font_size, int char_spacing, int line_spacing, int max_width, boolean read_from_file, 100 String text, TextData data) implements SurfaceRules.ConditionSource 101 { 102 public static final KeyDispatchDataCodec<TextCondition> CODEC = KeyDispatchDataCodec.of(RecordCodecBuilder.mapCodec(instance -> instance.group( 103 (Codec.INT.fieldOf("font_size").orElse(1).forGetter(a -> a.font_size)), 104 (Codec.INT.fieldOf("char_spacing").orElse(1).forGetter(a -> a.char_spacing)), 105 (Codec.INT.fieldOf("line_spacing").orElse(1).forGetter(a -> a.line_spacing)), 106 (Codec.INT.fieldOf("max_width").orElse(Integer.MAX_VALUE).forGetter(a -> a.max_width)), 107 (Codec.BOOL.fieldOf("read_from_file").orElse(false).forGetter(a -> a.read_from_file)), 108 (Codec.STRING.fieldOf("text").forGetter(a -> a.text)) 109 ).apply(instance, TextCondition::of))); 110 111 static TextCondition of(int font_size, int char_spacing, int line_spacing, int max_width, boolean read_from_file, String text) { 112 String txt = text; 113 if (read_from_file) { 114 File file = InfinityMod.configPath.resolve(text).toFile(); 115 if (file.exists()) { 116 try { 117 txt = FileUtils.readFileToString(file, StandardCharsets.UTF_8); 118 txt = txt.replace("\n", "$n"); 119 } catch (IOException ignored) { 120 } 121 } 122 } 123 return new TextCondition(font_size, char_spacing, line_spacing, max_width, read_from_file, txt, 124 TextData.genData(char_spacing, max_width, txt)); 125 } 126 127 public int find(int x, int line_num) { 128 int char_num = Collections.binarySearch(data.offsetMap().get(line_num), x); 129 if (char_num < 0) char_num = -char_num - 2; 130 return char_num; 131 } 132 133 @Override 134 public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() { 135 return CODEC; 136 } 137 138 @Override 139 public SurfaceRules.Condition apply(SurfaceRules.Context materialRuleContext) { 140 class CheckerboardPredicate extends SurfaceRules.LazyYCondition { 141 final List<List<Integer>> textmap; 142 final List<List<Character>> charmap; 143 final int longest_line; 144 145 CheckerboardPredicate() { 146 super(materialRuleContext); 147 textmap = data.offsetMap(); 148 charmap = data.charMap(); 149 longest_line = data.longest_line(); 150 } 151 152 public boolean compute() { 153 int x = ((MaterialRuleContextAccess)(Object)(this.context)).getBlockX() / font_size; 154 int z = ((MaterialRuleContextAccess)(Object)(this.context)).getBlockZ() / font_size; 155 int factor = 8 + line_spacing; 156 if (x < 0 || z < 0 || x > longest_line || z >= factor * textmap.size()) return false; 157 int line_num = z / factor; 158 int char_num = find(x, line_num); 159 int char_z = z % factor; 160 if (char_z >= 8 || char_num < 0) return false; 161 int char_x = x - textmap.get(line_num).get(char_num); 162 return TextData.check(char_x, char_z, charmap.get(line_num).get(char_num)); 163 } 164 } 165 return new CheckerboardPredicate(); 166 } 167 } 168 169 public static final DeferredRegister< 170 //? if >1.21 { 171 MapCodec 172 //?} else { 173 /*Codec 174 *///?} 175 <? extends SurfaceRules.ConditionSource>> MATERIAL_CONDITIONS = DeferredRegister.create(MOD_ID, Registries.MATERIAL_CONDITION); 176 177 178 public static void registerConditions() { 179 MATERIAL_CONDITIONS.register("linear", LinearCondition.CODEC::codec); 180 MATERIAL_CONDITIONS.register("checkerboard", CheckerboardCondition.CODEC::codec); 181 MATERIAL_CONDITIONS.register("text", TextCondition.CODEC::codec); 182 MATERIAL_CONDITIONS.register(); 183 } 184}