Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
1package net.lerariemann.infinity.dimensions;
2
3import net.lerariemann.infinity.InfinityMod;
4import net.lerariemann.infinity.util.VersionMethods;
5import net.lerariemann.infinity.util.core.*;
6import net.lerariemann.infinity.util.core.NbtUtils;
7import net.minecraft.nbt.*;
8
9import java.util.*;
10
11public class RandomBiome {
12 public RandomDimension parent;
13 public final RandomProvider PROVIDER;
14 public long id;
15 public String name;
16 public String fullname;
17 public final Random random;
18 public Set<String> mobs;
19 public CompoundTag data;
20 public CompoundTag colors;
21
22 RandomBiome(long i, RandomDimension dim) {
23 id = i;
24 parent = dim;
25 random = new Random(i);
26 PROVIDER = dim.PROVIDER;
27 name = "biome_" +i;
28 fullname = InfinityMod.MOD_ID + ":" + name;
29 mobs = new HashSet<>();
30 data = new CompoundTag();
31 data.putDouble("temperature", -1 + random.nextFloat()*3);
32 data.putBoolean("has_precipitation", PROVIDER.roll(random, "has_precipitation"));
33 data.putString("temperature_modifier", roll("temperature_modifier_frozen") ? "frozen" : "none");
34 data.putDouble("downfall", random.nextDouble());
35 data.put("effects", randomEffects());
36 data.put("spawners", (new RandomMobsList(this)).asData());
37 data.put("spawn_costs", spawnCosts());
38 data.put("features", (new RandomFeaturesList(this)).data);
39 data.put("carvers", carvers());
40 CommonIO.write(data, dim.getStoragePath() + "/worldgen/biome", name + ".json");
41 }
42
43 boolean roll(String key) {
44 return PROVIDER.roll(random, key);
45 }
46
47 void rollAndPutSafe(CompoundTag res, String key, Tag randomSound) {
48 if (roll(key)) {
49 if (randomSound != null && !NbtUtils.getAsString(randomSound).isBlank())
50 res.put(key, randomSound);
51 }
52 }
53
54 public IntTag randomColor() {
55 return IntTag.valueOf(random.nextInt(16777216));
56 }
57 public ListTag randomDustColor() {
58 ListTag res = new ListTag();
59 res.add(DoubleTag.valueOf(random.nextDouble()));
60 res.add(DoubleTag.valueOf(random.nextDouble()));
61 res.add(DoubleTag.valueOf(random.nextDouble()));
62 return res;
63 }
64 public ListTag randomEntityEffectColor() {
65 ListTag res = randomDustColor();
66 res.add(DoubleTag.valueOf(random.nextDouble()));
67 return res;
68 }
69
70 private ListTag zeroBlockPos() {
71 ListTag nbtElements = new ListTag();
72 nbtElements.add(FloatTag.valueOf(0));
73 nbtElements.add(FloatTag.valueOf(0));
74 nbtElements.add(FloatTag.valueOf(0));
75 return nbtElements;
76 }
77
78 private Tag randomBlockState() {
79 return InfinityMod.provider.randomBlockProvider(new Random(), ConfigType.ALL_BLOCKS);
80 }
81
82 StringTag randomSound(){
83 return StringTag.valueOf(PROVIDER.randomName(random, ConfigType.SOUNDS));
84 }
85
86 CompoundTag randomEffects() {
87 CompoundTag res = new CompoundTag();
88 res.put("fog_color", randomColor());
89 res.put("sky_color", randomColor());
90 res.put("water_color", randomColor());
91 res.put("water_fog_color", randomColor());
92 if (random.nextBoolean()) res.put("foliage_color", randomColor());
93 if (random.nextBoolean()) res.put("grass_color", randomColor());
94 colors = res.copy();
95 if (random.nextBoolean()) res.put("grass_color_modifier", StringTag.valueOf(random.nextBoolean() ? "dark_forest" : "swamp"));
96 if (roll("use_particles")) res.put("particle", randomParticle());
97 rollAndPutSafe(res, "ambient_sound", randomSound());
98 rollAndPutSafe(res, "mood_sound", randomMoodSound());
99 rollAndPutSafe(res, "additions_sound", randomAdditionSound());
100 if (roll("music")) res.put("music", randomMusic());
101 return res;
102 }
103
104 CompoundTag randomMoodSound() {
105 CompoundTag res = new CompoundTag();
106 var sound = randomSound();
107 if (NbtUtils.getAsString(sound).isEmpty()) {
108 return null;
109 }
110 res.put("sound", sound);
111 res.putInt("tick_delay", random.nextInt(6000));
112 res.putInt("block_search_extent", random.nextInt(32));
113 res.putDouble("offset", random.nextDouble()*8);
114 return res;
115 }
116
117 CompoundTag randomAdditionSound(){
118 CompoundTag res = new CompoundTag();
119 var sound = randomSound();
120 if (NbtUtils.getAsString(sound).isEmpty()) {
121 return null;
122 }
123 res.put("sound", sound);
124 res.putDouble("tick_chance", random.nextExponential()*0.01);
125 return res;
126 }
127
128 Tag randomMusic(){
129 CompoundTag data = new CompoundTag();
130 data.put("sound", StringTag.valueOf(PROVIDER.randomName(random, ConfigType.MUSIC)));
131 int a = random.nextInt(0, 12000);
132 int b = random.nextInt(0, 24000);
133 data.putInt("min_delay", Math.min(a,b));
134 data.putInt("max_delay", Math.max(a,b));
135 data.putBoolean("replace_current_music", random.nextBoolean());
136 // todo - multiple music entries per biome?
137 //? if >1.21.6 {
138 ListTag musicList = new ListTag();
139 CompoundTag res = new CompoundTag();
140 res.putInt("weight", 1);
141 res.put("data", data);
142 musicList.add(res);
143 return musicList;
144 //?} else {
145 /*return data;
146 *///?}
147 }
148
149 CompoundTag randomParticle(){
150 CompoundTag res = new CompoundTag();
151 res.putFloat("probability", (float)(random.nextExponential()*0.01));
152 res.put("options", particleOptions());
153 return res;
154 }
155
156 float randomDustScale() {
157 return random.nextBoolean() ? random.nextFloat() * 0.99f + 0.01f : random.nextFloat() * 3f + 1f;
158 }
159
160 CompoundTag particleOptions() {
161 CompoundTag res = new CompoundTag();
162 String particle = PROVIDER.randomName(random, ConfigType.PARTICLES);
163 res.putString("type", particle);
164 switch(particle) {
165 case "minecraft:block", "minecraft:block_marker", "minecraft:dust_pillar", "minecraft:falling_dust" -> {
166 CompoundTag value = new CompoundTag();
167 value.putString("Name", PROVIDER.randomName(random, ConfigType.ALL_BLOCKS));
168 res.put("block_state", value);
169 return res;
170 }
171 case "minecraft:item" -> {
172 CompoundTag value = new CompoundTag();
173 value.putString("id", PROVIDER.randomName(random, ConfigType.ITEMS));
174 res.put("item", value);
175 return res;
176 }
177 case "minecraft:dust" -> {
178 res.put("color", randomDustColor());
179 res.putFloat("scale", randomDustScale());
180 return res;
181 }
182 case "minecraft:dust_color_transition" -> {
183 res.put("from_color", randomDustColor());
184 res.put("to_color", randomDustColor());
185 res.putFloat("scale", randomDustScale());
186 return res;
187 }
188 case "minecraft:entity_effect" -> {
189 res.put("color", randomEntityEffectColor());
190 return res;
191 }
192 case "minecraft:sculk_charge" -> {
193 res.putFloat("roll", (float)(random.nextFloat()*Math.PI));
194 return res;
195 }
196 case "minecraft:shriek" -> {
197 res.putInt("delay", random.nextInt(500));
198 return res;
199 }
200 case "minecraft:vibration" -> {
201 CompoundTag destination = new CompoundTag();
202 destination.putString("type", "block");
203 ListTag pos = new ListTag();
204 for (int ii = 0; ii < 3; ii+=1) pos.add(IntTag.valueOf(random.nextInt(20000)));
205 destination.put("pos", pos);
206 res.put("destination", destination);
207 res.putInt("arrival_in_ticks", random.nextInt(20000));
208 return res;
209 }
210 //? if >1.21.4 {
211 case "minecraft:trail" -> {
212 res.put("color", randomColor());
213 res.put("target", zeroBlockPos());
214 res.putInt("duration", random.nextInt(500));
215 return res;
216 }
217 case "minecraft:block_crumble" -> {
218 res.put("block_state", randomBlockState());
219 return res;
220 }
221 case "minecraft:tinted_leaves" -> {
222 res.put("color", randomColor());
223 return res;
224 }
225 //?}
226 }
227 return res;
228 }
229
230 CompoundTag addMob(String category, boolean add) {
231 CompoundTag mob = new CompoundTag();
232 String mobname = PROVIDER.randomName(random, ConfigType.byName(category));
233 mob.putString("type", mobname);
234 if (add) mobs.add(mobname);
235 mob.putInt("weight", 1 + random.nextInt(20));
236 int a = 1 + random.nextInt(6);
237 int b = 1 + random.nextInt(6);
238 mob.putInt("minCount", Math.min(a, b));
239 mob.putInt("maxCount", Math.max(a, b));
240 return mob;
241 }
242
243 CompoundTag spawnCosts() {
244 CompoundTag res = new CompoundTag();
245 for (String mob: mobs) {
246 CompoundTag mobData = new CompoundTag();
247 mobData.putDouble("energy_budget", random.nextDouble()*0.6);
248 mobData.putDouble("charge", 0.5 + random.nextDouble()*0.4);
249 res.put(mob, mobData);
250 }
251 return res;
252 }
253
254 //? if <1.21.5 {
255 /*CompoundTag carvers() {
256 CompoundTag res = new CompoundTag();
257 ListTag air = new ListTag();
258 if (PROVIDER.roll(random, "use_random_cave")) air.add(StringTag.valueOf((new RandomCarver(this, true)).fullname));
259 if (PROVIDER.roll(random, "use_random_canyon")) air.add(StringTag.valueOf((new RandomCarver(this, false)).fullname));
260 PROVIDER.registry.get(ConfigType.CARVERS).getAllNames(random::nextDouble).forEach(s -> air.add(StringTag.valueOf(s)));
261 res.put("air", air);
262 return res;
263 }
264 *///?} else {
265 ListTag carvers() {
266 ListTag air = new ListTag();
267 if (PROVIDER.roll(random, "use_random_cave")) air.add(StringTag.valueOf((new RandomCarver(this, true)).fullname));
268 if (PROVIDER.roll(random, "use_random_canyon")) air.add(StringTag.valueOf((new RandomCarver(this, false)).fullname));
269 PROVIDER.registry.get(ConfigType.CARVERS).getAllNames(random::nextDouble).forEach(s -> air.add(StringTag.valueOf(s)));
270 return air;
271 }
272 //?}
273
274}