Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
at create-6.0 289 lines 11 kB view raw
1package net.lerariemann.infinity.util; 2 3import com.google.common.hash.HashCode; 4import com.google.common.hash.Hashing; 5import dev.architectury.platform.Platform; 6import net.lerariemann.infinity.InfinityMod; 7import net.lerariemann.infinity.access.Timebombable; 8import net.lerariemann.infinity.block.entity.BiomeBottleBlockEntity; 9import net.lerariemann.infinity.block.entity.InfinityPortalBlockEntity; 10import net.lerariemann.infinity.block.entity.TintableBlockEntity; 11import net.lerariemann.infinity.registry.core.ModComponentTypes; 12import net.lerariemann.infinity.registry.core.ModItems; 13import net.lerariemann.infinity.util.core.RandomProvider; 14import net.minecraft.block.BlockState; 15import net.minecraft.block.entity.BlockEntity; 16import net.minecraft.item.ItemStack; 17import net.minecraft.registry.RegistryKey; 18import net.minecraft.registry.entry.RegistryEntry; 19import net.minecraft.server.network.ServerPlayerEntity; 20import net.minecraft.server.world.ServerWorld; 21import net.minecraft.text.MutableText; 22import net.minecraft.text.Text; 23import net.minecraft.util.DyeColor; 24import net.minecraft.util.Identifier; 25import net.minecraft.util.Util; 26import net.minecraft.util.math.BlockPos; 27import net.minecraft.util.math.MathHelper; 28import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; 29import net.minecraft.util.math.random.CheckedRandom; 30import net.minecraft.util.math.random.Random; 31import net.minecraft.world.BlockRenderView; 32import net.minecraft.world.BlockView; 33import net.minecraft.world.World; 34import net.minecraft.world.WorldAccess; 35import net.minecraft.world.biome.Biome; 36 37import java.nio.charset.StandardCharsets; 38import java.util.Arrays; 39import java.util.concurrent.atomic.AtomicBoolean; 40 41/** Common mod methods that work identically on Fabric and NeoForge. 42 * @see PlatformMethods */ 43public interface InfinityMethods { 44 String ofRandomDim = "infinity:random"; 45 DoublePerlinNoiseSampler sampler = 46 DoublePerlinNoiseSampler.create(new CheckedRandom(0L), -5, genOctaves(2)); 47 48 static double[] genOctaves(int octaves){ 49 double[] a = new double[octaves]; 50 Arrays.fill(a, 1); 51 return a; 52 } 53 static double sample(BlockPos pos) { 54 return sampler.sample(pos.getX(), pos.getY(), pos.getZ()); 55 } 56 57 /** 58 * Converts a string to an identifier in the Infinite Dimensions namespace. 59 */ 60 static Identifier getId(String value){ 61 return Identifier.of(InfinityMod.MOD_ID, value); 62 } 63 64 /** 65 * Converts a dimension's long value to an identifier in the Infinite Dimensions namespace. 66 */ 67 static Identifier getDimId(long value){ 68 return getId("generated_" + value); 69 } 70 71 /** 72 * Checks if a dimension is an Infinite Dimension. 73 */ 74 static boolean isInfinity(World w) { 75 return isInfinity(w.getRegistryKey()); 76 } 77 static boolean isInfinity(RegistryKey<World> key) { 78 return key.getValue().getNamespace().equals(InfinityMod.MOD_ID); 79 } 80 static boolean isBiomeInfinity(WorldAccess world, BlockPos pos) { 81 AtomicBoolean bl = new AtomicBoolean(false); 82 world.getBiome(pos).getKey().ifPresent(key -> 83 bl.set(key.getValue().getNamespace().equals("infinity"))); 84 return bl.get(); 85 } 86 static boolean isBiomeInfinity(RegistryEntry<Biome> b) { 87 return b.getKey().get().getValue().getNamespace().equals("infinity"); 88 } 89 static boolean isBiomeInfinity(BlockView world, BlockPos pos) { 90 if (world instanceof WorldAccess acc) { 91 return InfinityMethods.isBiomeInfinity(acc, pos); 92 } 93 else return Platform.isFabric() 94 && world.hasBiomes() 95 && world.getBiomeFabric(pos) instanceof RegistryEntry<Biome> 96 && InfinityMethods.isBiomeInfinity(world.getBiomeFabric(pos)); 97 } 98 99 /** 100 * Checks if a mod designed for Fabric (using - instead of _) is loaded. 101 * This is most commonly used for FFAPI modules, but also applies to mods 102 * like Item Descriptions or Cloth Config. 103 */ 104 static boolean isFabricApiLoaded(String modID) { 105 if (Platform.isFabric()) return Platform.isModLoaded(modID.replace("_", "-")); 106 else return Platform.isModLoaded(modID.replace("-", "_")); 107 } 108 109 static double sample(int x, int y, int z) { 110 return sampler.sample(x, y, z); 111 } 112 113 static int properMod(int a, int b) { 114 int res = a%b; 115 return (res >= 0) ? res : b + res; 116 } 117 118 static void sendUnexpectedError(ServerPlayerEntity player, String type) { 119 player.sendMessage(Text.translatable("error.infinity." + type + ".unexpected")); 120 } 121 122 /** 123 * Convert a provided string into a dimension ID. 124 * This also checks if it matches an Easter Egg dimension. 125 */ 126 static Identifier dimTextToId(String text) { 127 if (text.equals("abatised redivides")) 128 return World.END.getValue(); 129 if (text.isEmpty()) 130 return InfinityMethods.getId("missingno"); 131 String easterId = InfinityMod.provider.easterizer.getAsEaster(text); 132 if (easterId != null) 133 return InfinityMethods.getId(easterId); 134 return InfinityMethods.getDimId(getDimensionSeed(text)); 135 } 136 137 static boolean isTimebombed(ServerWorld world) { 138 return ((Timebombable)world).infinity$isTimebombed(); 139 } 140 141 /** 142 * Check if a dimension exists and has not been timebombed. 143 */ 144 static boolean dimExists(ServerWorld world) { 145 return (world != null && !isTimebombed(world)); 146 } 147 148 /** 149 * Hashes text into dimension ID. 150 */ 151 static long getDimensionSeed(String text) { 152 HashCode f = Hashing.sha256().hashString(text + InfinityMod.provider.salt, StandardCharsets.UTF_8); 153 return InfinityMethods.longArithmeticEnabled() ? f.asLong() & Long.MAX_VALUE : f.asInt() & Integer.MAX_VALUE; 154 } 155 156 static long getNumericFromId(Identifier id) { 157 String dimensionName = id.getPath(); 158 String numericId = dimensionName.substring(dimensionName.lastIndexOf("_") + 1); 159 long i; 160 try { 161 i = Long.parseLong(numericId); 162 } catch (Exception e) { 163 /* Simply hash the name if it isn't of "generated_..." format. */ 164 i = getDimensionSeed(numericId); 165 } 166 return i; 167 } 168 169 private static float bookBoxSample(BlockPos pos, int offset) { 170 return MathHelper.clamp(0.5f * (1f + (float)sampler.sample(4*pos.getX(), 4*(pos.getY() + offset), 4*pos.getZ())), 0f, 1f); 171 } 172 static int getBookBoxColor(BlockState state, BlockRenderView world, BlockPos pos, int tintIndex) { 173 if (pos != null) { 174 float r = bookBoxSample(pos, -1000); 175 float g = bookBoxSample(pos, 0); 176 float b = bookBoxSample(pos, 1000); 177 return MathHelper.packRgb(r, g, b); 178 } 179 return 16777215; 180 } 181 182 static int getOverlayColorFromComponents(ItemStack stack, int layer) { 183 if (stack.getNbt() != null) { 184 if (layer == 1) { 185 if (stack.isOf(ModItems.TRANSFINITE_KEY.get())) 186 return stack.getNbt().getInt(ModComponentTypes.COLOR); 187 else if (stack.isOf(ModItems.BIOME_BOTTLE_ITEM.get())) { 188 return stack.getNbt().getCompound("BlockEntityTag").getInt("Color"); 189 } 190 else if (stack.isOf(ModItems.F4.get())) { 191 return BackportMethods.getOrDefaultInt(stack, ModComponentTypes.COLOR, 10879231); 192 } 193 } 194 else if (stack.isOf(ModItems.CHROMATIC_MATTER.get()) || stack.isOf(ModItems.CHROMATIC_WOOL.get()) || stack.isOf(ModItems.CHROMATIC_CARPET.get())) 195 return stack.getNbt().getInt(ModComponentTypes.COLOR); 196 } 197 return 0xFFFFFF; 198 } 199 200 static int getPortalItemColor(ItemStack stack, int layer) { 201 return 0x00FFFF; 202 } 203 204 /** 205 * For use in color providers with blocks which the block entity sets color for. 206 */ 207 static int getBlockEntityColor(BlockState state, BlockRenderView world, BlockPos pos, int tintIndex) { 208 if (world != null && pos != null) { 209 BlockEntity blockEntity = world.getBlockEntity(pos); 210 if (blockEntity instanceof TintableBlockEntity be) { 211 Object j = be.getTint(); 212 return (int)j & 0xFFFFFF; 213 } 214 } 215 return 0xFFFFFF; 216 } 217 218 static int getKeyColorFromId(Identifier id) { 219 if(id.getNamespace().equals(InfinityMod.MOD_ID) && id.getPath().contains("generated_")) 220 return Math.toIntExact(getNumericFromId(id)); 221 return 0; 222 } 223 224 static long getRandomSeed(java.util.Random random) { 225 return longArithmeticEnabled() ? random.nextLong() : random.nextInt(); 226 } 227 228 static long getRandomSeed(Random random) { 229 return longArithmeticEnabled() ? random.nextLong() : random.nextInt(); 230 } 231 232 static Identifier getRandomId(java.util.Random random) { 233 return getDimId(getRandomSeed(random)); 234 } 235 static Identifier getRandomId(Random random) { 236 return getDimId(getRandomSeed(random)); 237 } 238 239 static MutableText getDimensionNameAsText(Identifier dimension) { 240 String name = dimension.toString(); 241 // Randomly generated dimensions. 242 if (name.contains("infinity:generated_")) 243 return Text.translatable("tooltip.infinity.key.generated") 244 .append(name.replace("infinity:generated_", "")); 245 if (name.equals(InfinityMethods.ofRandomDim)) 246 return Text.translatable("tooltip.infinity.key.randomise"); 247 // All other dimensions. 248 return Text.translatableWithFallback( 249 Util.createTranslationKey("dimension", dimension), 250 InfinityMethods.formatAsTitleCase(dimension.getPath())); 251 } 252 253 /** 254 * Creates a fallback for texts without translation by replacing underscores 255 * with spaces and formatting the text as Title Case. 256 */ 257 static String formatAsTitleCase(String text) { 258 text = text.replaceAll("[_./]", " "); 259 //i am sure java has a smarter way to do title case, but this works too 260 StringBuilder newText = new StringBuilder(); 261 int i = 0; 262 for (Character c : text.toCharArray()) { 263 if (i == 0) { 264 c = c.toString().toUpperCase().charAt(0); 265 } 266 newText.append(c); 267 i++; 268 if (c == ' ') { 269 i = 0; 270 } 271 } 272 return newText.toString(); 273 } 274 275 static boolean chaosMobsEnabled() { 276 return RandomProvider.rule("chaosMobsEnabled"); 277 } 278 279 static boolean longArithmeticEnabled() { 280 return RandomProvider.rule("longArithmeticEnabled"); 281 } 282 283 static boolean isCreateLoaded() { 284 if (Platform.isModLoaded("create")) { 285 return Platform.getMod("create").getVersion().charAt(0) != '5'; 286 } 287 return false; 288 } 289}