返回提交历史
Modified
build.gradle
+16
-2
Modified
src/main/java/com/xfestudio/mydimension/item/RiftItem.java
+17
-29
Modified
src/main/java/com/xfestudio/mydimension/world/SoaringMindChunkGenerator.java
+359
-68
Modified
src/main/resources/data/mydimension/dimension/soaring_mind.json
+16
-2
XFEstudio/MyDimension
完善空岛算法
f7d38aa
代码差异
4 个文件
+408
-101
@@ -125,8 +125,22 @@ tasks.register('generatePlayerMindDimensions') {
125
125
generator: [
126
126
type : 'mydimension:soaring_islands',
127
127
biome_source: [
128
type : 'minecraft:multi_noise',
129
preset: 'minecraft:overworld'
128
type : 'minecraft:checkerboard',
129
biomes : [
130
'minecraft:plains',
131
'minecraft:forest',
132
'minecraft:flower_forest',
133
'minecraft:birch_forest',
134
'minecraft:meadow',
135
'minecraft:cherry_grove',
136
'minecraft:snowy_plains',
137
'minecraft:grove',
138
'minecraft:desert',
139
'minecraft:savanna',
140
'minecraft:jungle',
141
'minecraft:windswept_hills'
142
],
143
scale : 3
130
144
]
131
145
]
132
146
]
@@ -3,6 +3,7 @@ package com.xfestudio.mydimension.item;
3
3
import com.xfestudio.mydimension.client.RiftClient;
4
4
import com.xfestudio.mydimension.world.MindInstances;
5
5
import com.xfestudio.mydimension.world.ModDimensions;
6
import com.xfestudio.mydimension.world.SoaringMindChunkGenerator;
6
7
import net.minecraft.core.BlockPos;
7
8
import net.minecraft.core.registries.Registries;
8
9
import net.minecraft.nbt.CompoundTag;
@@ -195,6 +196,13 @@ public class RiftItem extends Item {
195
196
yRot = mindPoint.yRot();
196
197
xRot = mindPoint.xRot();
197
198
}
199
200
if (ModDimensions.SOARING_MIND.equals(ModDimensions.baseMindDimension(actualTargetDimension))) {
201
EntryPoint safe = safeEntryPoint(targetLevel, actualTargetDimension, x, z);
202
x = safe.x();
203
y = safe.y();
204
z = safe.z();
205
}
198
206
}
199
207
200
208
if (returningFromSelectedMind) {
@@ -217,12 +225,13 @@ public class RiftItem extends Item {
217
225
private static EntryPoint safeEntryPoint(ServerLevel level, ResourceKey<Level> dimension, double x, double z) {
218
226
int blockX = (int) Math.floor(x);
219
227
int blockZ = (int) Math.floor(z);
228
boolean soaringMind = ModDimensions.SOARING_MIND.equals(ModDimensions.baseMindDimension(dimension));
220
229
int height = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, blockX, blockZ);
221
230
if (height > level.getMinBuildHeight()) {
222
return new EntryPoint(x, height + 1.0D, z);
231
return new EntryPoint(x, soaringMind ? height : height + 1.0D, z);
223
232
}
224
233
225
if (ModDimensions.SOARING_MIND.equals(ModDimensions.baseMindDimension(dimension))) {
234
if (soaringMind) {
226
235
EntryPoint nearby = findNearbySurface(level, blockX, blockZ);
227
236
if (nearby != null) {
228
237
return nearby;
@@ -233,35 +242,14 @@ public class RiftItem extends Item {
233
242
}
234
243
235
244
private static EntryPoint findNearbySurface(ServerLevel level, int centerX, int centerZ) {
236
for (int radius = 8; radius <= 128; radius += 8) {
237
EntryPoint best = null;
238
int bestDistance = Integer.MAX_VALUE;
239
for (int dx = -radius; dx <= radius; dx += 8) {
240
for (int dz = -radius; dz <= radius; dz += 8) {
241
if (Math.abs(dx) != radius && Math.abs(dz) != radius) {
242
continue;
243
}
244
245
int x = centerX + dx;
246
int z = centerZ + dz;
247
int height = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z);
248
if (height <= level.getMinBuildHeight()) {
249
continue;
250
}
251
252
int distance = dx * dx + dz * dz;
253
if (distance < bestDistance) {
254
bestDistance = distance;
255
best = new EntryPoint(x + 0.5D, height + 1.0D, z + 0.5D);
256
}
257
}
258
}
259
if (best != null) {
260
return best;
261
}
245
BlockPos surface = SoaringMindChunkGenerator.findNearestSurface(centerX, centerZ, 768);
246
if (surface == null) {
247
return null;
262
248
}
263
249
264
return null;
250
int height = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, surface.getX(), surface.getZ());
251
double y = height > level.getMinBuildHeight() ? height : surface.getY();
252
return new EntryPoint(surface.getX() + 0.5D, y, surface.getZ() + 0.5D);
265
253
}
266
254
267
255
public static boolean sendToMind(ServerPlayer player, LivingEntity target, ItemStack stack, RiftAction action) {
@@ -33,13 +33,23 @@ public class SoaringMindChunkGenerator extends ChunkGenerator {
33
33
34
34
private static final int MIN_Y = 0;
35
35
private static final int HEIGHT = 256;
36
private static final int CELL_SIZE = 144;
37
private static final int CELL_MARGIN = 48;
36
private static final int CELL_SIZE = 384;
37
private static final int CELL_MARGIN = 150;
38
38
private static final int NEIGHBOR_RADIUS = 2;
39
private static final double TWO_PI = Math.PI * 2.0D;
39
40
private static final BlockState AIR = Blocks.AIR.defaultBlockState();
40
41
private static final BlockState GRASS = Blocks.GRASS_BLOCK.defaultBlockState();
41
42
private static final BlockState DIRT = Blocks.DIRT.defaultBlockState();
42
43
private static final BlockState STONE = Blocks.STONE.defaultBlockState();
44
private static final BlockState WATER = Blocks.WATER.defaultBlockState();
45
private static final BlockState SAND = Blocks.SAND.defaultBlockState();
46
private static final BlockState SANDSTONE = Blocks.SANDSTONE.defaultBlockState();
47
private static final BlockState GRAVEL = Blocks.GRAVEL.defaultBlockState();
48
private static final BlockState SNOW_BLOCK = Blocks.SNOW_BLOCK.defaultBlockState();
49
private static final BlockState MOSS = Blocks.MOSS_BLOCK.defaultBlockState();
50
private static final BlockState PODZOL = Blocks.PODZOL.defaultBlockState();
51
private static final BlockState COARSE_DIRT = Blocks.COARSE_DIRT.defaultBlockState();
52
private static final BlockState CLAY = Blocks.CLAY.defaultBlockState();
43
53
44
54
public SoaringMindChunkGenerator(BiomeSource biomeSource) {
45
55
super(biomeSource, Util.memoize(holder -> holder.value().getGenerationSettings()));
@@ -81,13 +91,15 @@ public class SoaringMindChunkGenerator extends ChunkGenerator {
81
91
int x = minX + localX;
82
92
for (int localZ = 0; localZ < 16; localZ++) {
83
93
int z = minZ + localZ;
84
int topY = topIslandY(x, z);
85
if (topY < MIN_Y) {
94
IslandSlice slice = sliceAt(x, z);
95
if (slice == null) {
86
96
continue;
87
97
}
88
98
89
for (int y = MIN_Y; y <= topY; y++) {
90
BlockState state = blockStateAt(x, y, z, topY);
99
int minY = Math.max(slice.bottomY(), chunk.getMinBuildHeight());
100
int maxY = Math.min(slice.topY(), chunk.getMaxBuildHeight() - 1);
101
for (int y = minY; y <= maxY; y++) {
102
BlockState state = stateForY(x, y, z, slice);
91
103
if (state.isAir()) {
92
104
continue;
93
105
}
@@ -103,9 +115,15 @@ public class SoaringMindChunkGenerator extends ChunkGenerator {
103
115
104
116
@Override
105
117
public int getBaseHeight(int x, int z, Heightmap.Types heightmapType, LevelHeightAccessor heightAccessor, RandomState randomState) {
106
int topY = Math.min(topIslandY(x, z), heightAccessor.getMaxBuildHeight() - 1);
107
for (int y = topY; y >= heightAccessor.getMinBuildHeight(); y--) {
108
BlockState state = blockStateAt(x, y, z, topY);
118
IslandSlice slice = sliceAt(x, z);
119
if (slice == null) {
120
return heightAccessor.getMinBuildHeight();
121
}
122
123
int topY = Math.min(slice.topY(), heightAccessor.getMaxBuildHeight() - 1);
124
int bottomY = Math.max(slice.bottomY(), heightAccessor.getMinBuildHeight());
125
for (int y = topY; y >= bottomY; y--) {
126
BlockState state = stateForY(x, y, z, slice);
109
127
if (heightmapType.isOpaque().test(state)) {
110
128
return y + 1;
111
129
}
@@ -116,10 +134,10 @@ public class SoaringMindChunkGenerator extends ChunkGenerator {
116
134
@Override
117
135
public NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor heightAccessor, RandomState randomState) {
118
136
BlockState[] states = new BlockState[heightAccessor.getHeight()];
119
int topY = topIslandY(x, z);
137
IslandSlice slice = sliceAt(x, z);
120
138
for (int index = 0; index < states.length; index++) {
121
139
int y = heightAccessor.getMinBuildHeight() + index;
122
states[index] = blockStateAt(x, y, z, topY);
140
states[index] = stateForY(x, y, z, slice);
123
141
}
124
142
return new NoiseColumn(heightAccessor.getMinBuildHeight(), states);
125
143
}
@@ -144,108 +162,311 @@ public class SoaringMindChunkGenerator extends ChunkGenerator {
144
162
info.add("Soaring Mind islands");
145
163
}
146
164
147
private static int topIslandY(int x, int z) {
148
int topY = -1;
149
int baseCellX = Math.floorDiv(x, CELL_SIZE);
150
int baseCellZ = Math.floorDiv(z, CELL_SIZE);
165
public static BlockPos findNearestSurface(int centerX, int centerZ, int maxRadius) {
166
BlockPos exact = surfaceAt(centerX, centerZ);
167
if (exact != null) {
168
return exact;
169
}
151
170
152
for (int cellX = baseCellX - NEIGHBOR_RADIUS; cellX <= baseCellX + NEIGHBOR_RADIUS; cellX++) {
153
for (int cellZ = baseCellZ - NEIGHBOR_RADIUS; cellZ <= baseCellZ + NEIGHBOR_RADIUS; cellZ++) {
154
Island island = islandFor(cellX, cellZ);
155
if (island == null) {
156
continue;
171
for (int radius = 4; radius <= maxRadius; radius += 4) {
172
BlockPos best = null;
173
int bestDistance = Integer.MAX_VALUE;
174
for (int offset = -radius; offset <= radius; offset += 4) {
175
best = closerSurface(centerX, centerZ, centerX + offset, centerZ - radius, best, bestDistance);
176
if (best != null) {
177
bestDistance = distanceSquared(centerX, centerZ, best.getX(), best.getZ());
157
178
}
158
159
double dx = (double) (x - island.x()) / island.radiusX();
160
double dz = (double) (z - island.z()) / island.radiusZ();
161
double horizontal = dx * dx + dz * dz;
162
if (horizontal > 1.0D) {
163
continue;
179
best = closerSurface(centerX, centerZ, centerX + offset, centerZ + radius, best, bestDistance);
180
if (best != null) {
181
bestDistance = distanceSquared(centerX, centerZ, best.getX(), best.getZ());
182
}
183
best = closerSurface(centerX, centerZ, centerX - radius, centerZ + offset, best, bestDistance);
184
if (best != null) {
185
bestDistance = distanceSquared(centerX, centerZ, best.getX(), best.getZ());
186
}
187
best = closerSurface(centerX, centerZ, centerX + radius, centerZ + offset, best, bestDistance);
188
if (best != null) {
189
bestDistance = distanceSquared(centerX, centerZ, best.getX(), best.getZ());
164
190
}
191
}
165
192
166
double edge = 1.0D - horizontal;
167
int surface = island.y() + (int) Math.round(Math.sqrt(edge) * island.height() * 0.42D);
168
surface += surfaceNoise(x, z, island.seed());
169
topY = Math.max(topY, surface);
193
if (best != null) {
194
return best;
170
195
}
171
196
}
172
197
173
return Math.min(topY, HEIGHT - 16);
198
return null;
174
199
}
175
200
176
private static BlockState blockStateAt(int x, int y, int z, int topY) {
177
if (topY < MIN_Y || y > topY || y < MIN_Y) {
178
return AIR;
201
private static BlockPos closerSurface(int centerX, int centerZ, int x, int z, BlockPos current, int currentDistance) {
202
BlockPos candidate = surfaceAt(x, z);
203
if (candidate == null) {
204
return current;
179
205
}
180
206
207
int distance = distanceSquared(centerX, centerZ, x, z);
208
return distance < currentDistance ? candidate : current;
209
}
210
211
private static int distanceSquared(int centerX, int centerZ, int x, int z) {
212
int dx = x - centerX;
213
int dz = z - centerZ;
214
return dx * dx + dz * dz;
215
}
216
217
private static BlockPos surfaceAt(int x, int z) {
218
IslandSlice slice = sliceAt(x, z);
219
if (slice == null || slice.hasWater()) {
220
return null;
221
}
222
return new BlockPos(x, slice.topY() + 1, z);
223
}
224
225
private static int topIslandY(int x, int z) {
226
IslandSlice slice = sliceAt(x, z);
227
return slice == null ? -1 : slice.topY();
228
}
229
230
private static IslandSlice sliceAt(int x, int z) {
231
IslandSlice best = null;
232
int topY = -1;
181
233
int baseCellX = Math.floorDiv(x, CELL_SIZE);
182
234
int baseCellZ = Math.floorDiv(z, CELL_SIZE);
183
boolean insideIsland = false;
184
235
185
for (int cellX = baseCellX - NEIGHBOR_RADIUS; cellX <= baseCellX + NEIGHBOR_RADIUS && !insideIsland; cellX++) {
236
for (int cellX = baseCellX - NEIGHBOR_RADIUS; cellX <= baseCellX + NEIGHBOR_RADIUS; cellX++) {
186
237
for (int cellZ = baseCellZ - NEIGHBOR_RADIUS; cellZ <= baseCellZ + NEIGHBOR_RADIUS; cellZ++) {
187
238
Island island = islandFor(cellX, cellZ);
188
239
if (island == null) {
189
240
continue;
190
241
}
191
242
192
int localTop = islandTopAt(x, z, island);
193
if (localTop < MIN_Y || y > localTop) {
243
double shape = islandShape(x, z, island);
244
if (shape > 1.0D) {
194
245
continue;
195
246
}
196
247
197
double dx = (double) (x - island.x()) / island.radiusX();
198
double dz = (double) (z - island.z()) / island.radiusZ();
199
double dy = (double) (y - island.y()) / island.height();
200
double taper = dx * dx + dz * dz + dy * dy * 1.35D;
201
if (taper <= 1.0D || y >= island.y() - 3) {
202
insideIsland = true;
203
break;
248
IslandSlice slice = islandSliceAt(x, z, island, shape);
249
if (slice.topY() > topY) {
250
topY = slice.topY();
251
best = slice;
204
252
}
205
253
}
206
254
}
207
255
208
if (!insideIsland) {
256
return best;
257
}
258
259
private static IslandSlice islandSliceAt(int x, int z, Island island, double shape) {
260
int landTop = islandTopAt(x, z, island, shape);
261
int solidTop = landTop;
262
int waterTop = -1;
263
double lakeShape = lakeShape(x, z, island, shape);
264
265
if (lakeShape < 1.0D) {
266
int depression = 2 + (int) Math.round((1.0D - lakeShape) * 4.0D);
267
waterTop = Math.min(island.waterY(), landTop - 1);
268
solidTop = Math.min(waterTop - 1, landTop - depression);
269
}
270
271
int bottomY = islandBottomAt(x, z, island, shape, landTop);
272
return new IslandSlice(waterTop >= 0 ? waterTop : landTop, bottomY, solidTop, waterTop, island);
273
}
274
275
private static BlockState stateForY(int x, int y, int z, IslandSlice slice) {
276
if (slice == null || y < slice.bottomY() || y > slice.topY()) {
209
277
return AIR;
210
278
}
211
if (y == topY) {
212
return GRASS;
279
if (slice.hasWater() && y > slice.solidTopY() && y <= slice.waterTopY()) {
280
return WATER;
281
}
282
if (y == slice.solidTopY()) {
283
return slice.hasWater() ? lakeBedState(slice.island().theme()) : surfaceState(x, z, slice.island());
213
284
}
214
if (y >= topY - 4) {
215
return DIRT;
285
if (y >= slice.solidTopY() - 4) {
286
return subsurfaceState(slice.island().theme());
216
287
}
217
return STONE;
288
return fillerState(slice.island().theme());
289
}
290
291
private static double islandShape(int x, int z, Island island) {
292
double rawX = x - island.x();
293
double rawZ = z - island.z();
294
double cos = Math.cos(island.angle());
295
double sin = Math.sin(island.angle());
296
double dx = (rawX * cos + rawZ * sin) / island.radiusX();
297
double dz = (-rawX * sin + rawZ * cos) / island.radiusZ();
298
double angle = Math.atan2(dz, dx);
299
double distance = Math.sqrt(dx * dx + dz * dz);
300
double boundary = 1.0D;
301
boundary += 0.18D * Math.sin(angle * 2.0D + phase(island.seed(), 10));
302
boundary += 0.13D * Math.sin(angle * 4.0D + phase(island.seed(), 11));
303
boundary += 0.08D * Math.sin(angle * 7.0D + phase(island.seed(), 12));
304
boundary += 0.05D * Math.sin(angle * 11.0D + phase(island.seed(), 13));
305
boundary += smoothNoise(x, z, island.seed() ^ 0x31C5E0DADDL, 42) * 0.12D;
306
boundary += smoothNoise(x, z, island.seed() ^ 0x6A09E667F3BCC909L, 22) * 0.06D;
307
return distance / Math.max(0.62D, boundary);
308
}
309
310
private static int islandTopAt(int x, int z, Island island, double shape) {
311
double edgeDrop = smoothStep(0.94D, 1.0D, shape);
312
int surface = island.y() - (int) Math.round(edgeDrop * island.edgeDrop());
313
surface += surfaceNoise(x, z, island.seed());
314
return Math.min(Math.max(surface, MIN_Y + 8), HEIGHT - 16);
218
315
}
219
316
220
private static int islandTopAt(int x, int z, Island island) {
221
double dx = (double) (x - island.x()) / island.radiusX();
222
double dz = (double) (z - island.z()) / island.radiusZ();
223
double horizontal = dx * dx + dz * dz;
224
if (horizontal > 1.0D) {
225
return -1;
317
private static int islandBottomAt(int x, int z, Island island, double shape, int topY) {
318
double cone = Math.max(0.0D, 1.0D - shape);
319
double tip = 1.0D - smoothStep(0.0D, 0.20D, shape);
320
int thickness = island.edgeThickness() + (int) Math.round(island.height() * cone + island.tipDepth() * tip);
321
int underside = topY - thickness + undersideNoise(x, z, island.seed());
322
return Math.max(MIN_Y, underside);
323
}
324
325
private static double lakeShape(int x, int z, Island island, double islandShape) {
326
if (!island.hasLake() || islandShape > 0.66D) {
327
return 2.0D;
226
328
}
227
double edge = 1.0D - horizontal;
228
return island.y() + (int) Math.round(Math.sqrt(edge) * island.height() * 0.42D) + surfaceNoise(x, z, island.seed());
329
330
double dx = (double) (x - island.lakeX()) / island.lakeRadiusX();
331
double dz = (double) (z - island.lakeZ()) / island.lakeRadiusZ();
332
return dx * dx + dz * dz;
229
333
}
230
334
231
335
private static Island islandFor(int cellX, int cellZ) {
232
336
long seed = mix(cellX, cellZ);
233
if (randomUnit(seed) > 0.72D) {
337
if (randomUnit(seed) > 0.86D) {
234
338
return null;
235
339
}
236
340
341
IslandTheme theme = IslandTheme.values()[randomInt(seed, 14, IslandTheme.values().length)];
237
342
int centerX = cellX * CELL_SIZE + CELL_MARGIN + randomInt(seed, 0, CELL_SIZE - CELL_MARGIN * 2);
238
343
int centerZ = cellZ * CELL_SIZE + CELL_MARGIN + randomInt(seed, 1, CELL_SIZE - CELL_MARGIN * 2);
239
int centerY = 78 + randomInt(seed, 2, 76);
240
int radiusX = 16 + randomInt(seed, 3, 32);
241
int radiusZ = 16 + randomInt(seed, 4, 32);
242
int height = 10 + randomInt(seed, 5, 24);
243
return new Island(centerX, centerY, centerZ, radiusX, radiusZ, height, seed);
344
IslandSize size = islandSize(seed);
345
int centerY = 82 + randomInt(seed, 2, 72);
346
int radiusX = size.minRadius() + randomInt(seed, 3, size.radiusRange());
347
int radiusZ = size.minRadius() + randomInt(seed, 4, size.radiusRange());
348
if (randomUnit(seed + 17) > 0.52D) {
349
radiusX += size.stretch() + randomInt(seed, 18, Math.max(1, size.stretch() + 1));
350
} else if (randomUnit(seed + 19) > 0.52D) {
351
radiusZ += size.stretch() + randomInt(seed, 20, Math.max(1, size.stretch() + 1));
352
}
353
int height = size.minHeight() + randomInt(seed, 5, size.heightRange());
354
int edgeDrop = randomInt(seed, 6, 3);
355
int edgeThickness = 2 + randomInt(seed, 7, 2);
356
double angle = phase(seed, 9);
357
int tipDepth = size.tipDepth() + randomInt(seed, 8, Math.max(1, size.tipDepth() / 2));
358
boolean hasLake = size.allowsLake() && theme != IslandTheme.ROCKY && randomUnit(seed + 21) < lakeChance(theme);
359
int lakeX = centerX + randomInt(seed, 22, Math.max(1, radiusX)) - radiusX / 2;
360
int lakeZ = centerZ + randomInt(seed, 23, Math.max(1, radiusZ)) - radiusZ / 2;
361
int lakeRadiusX = Math.max(4, radiusX / 8) + randomInt(seed, 24, Math.max(1, Math.min(18, radiusX / 4)));
362
int lakeRadiusZ = Math.max(4, radiusZ / 8) + randomInt(seed, 25, Math.max(1, Math.min(18, radiusZ / 4)));
363
int waterY = centerY - 1 + randomInt(seed, 26, 3) - 1;
364
return new Island(centerX, centerY, centerZ, radiusX, radiusZ, height, edgeDrop, edgeThickness,
365
tipDepth, angle, theme, hasLake, lakeX, lakeZ, lakeRadiusX, lakeRadiusZ, waterY, seed);
366
}
367
368
private static IslandSize islandSize(long seed) {
369
int roll = randomInt(seed, 27, 100);
370
if (roll < 18) {
371
return IslandSize.TINY;
372
}
373
if (roll < 46) {
374
return IslandSize.SMALL;
375
}
376
if (roll < 80) {
377
return IslandSize.MEDIUM;
378
}
379
return IslandSize.LARGE;
380
}
381
382
private static double lakeChance(IslandTheme theme) {
383
return switch (theme) {
384
case LUSH -> 0.72D;
385
case PLAINS, FOREST -> 0.48D;
386
case SNOWY -> 0.34D;
387
case DESERT -> 0.20D;
388
case ROCKY -> 0.0D;
389
};
390
}
391
392
private static BlockState surfaceState(int x, int z, Island island) {
393
return switch (island.theme()) {
394
case LUSH -> smoothNoise(x, z, island.seed() ^ 0x94D049BB133111EBL, 18) > 0.18D ? MOSS : GRASS;
395
case FOREST -> smoothNoise(x, z, island.seed() ^ 0x2545F4914F6CDD1DL, 20) > 0.25D ? PODZOL : GRASS;
396
case DESERT -> SAND;
397
case SNOWY -> SNOW_BLOCK;
398
case ROCKY -> smoothNoise(x, z, island.seed() ^ 0xD6E8FEB86659FD93L, 16) > 0.10D ? GRAVEL : STONE;
399
case PLAINS -> smoothNoise(x, z, island.seed() ^ 0xBF58476D1CE4E5B9L, 24) > 0.42D ? COARSE_DIRT : GRASS;
400
};
401
}
402
403
private static BlockState lakeBedState(IslandTheme theme) {
404
return switch (theme) {
405
case DESERT -> SAND;
406
case ROCKY -> GRAVEL;
407
case SNOWY -> CLAY;
408
case LUSH, FOREST, PLAINS -> CLAY;
409
};
410
}
411
412
private static BlockState subsurfaceState(IslandTheme theme) {
413
return switch (theme) {
414
case DESERT -> SANDSTONE;
415
case ROCKY -> STONE;
416
case SNOWY, LUSH, FOREST, PLAINS -> DIRT;
417
};
418
}
419
420
private static BlockState fillerState(IslandTheme theme) {
421
return switch (theme) {
422
case DESERT -> SANDSTONE;
423
default -> STONE;
424
};
244
425
}
245
426
246
427
private static int surfaceNoise(int x, int z, long seed) {
247
long mixed = mix(x + (int) seed, z - (int) (seed >>> 32));
248
return randomInt(mixed, 0, 5) - 2;
428
return (int) Math.round(smoothNoise(x, z, seed ^ 0xA24BAED4963EE407L, 48) * 1.2D
429
+ smoothNoise(x, z, seed ^ 0x9FB21C651E98DF25L, 96) * 1.4D);
430
}
431
432
private static int undersideNoise(int x, int z, long seed) {
433
return (int) Math.round(smoothNoise(x, z, seed ^ 0xC2B2AE3D27D4EB4FL, 42) * 1.4D);
434
}
435
436
private static double smoothNoise(int x, int z, long seed, int scale) {
437
int cellX = Math.floorDiv(x, scale);
438
int cellZ = Math.floorDiv(z, scale);
439
double localX = (double) (x - cellX * scale) / scale;
440
double localZ = (double) (z - cellZ * scale) / scale;
441
double sx = fade(localX);
442
double sz = fade(localZ);
443
444
double v00 = randomSigned(seed, cellX, cellZ);
445
double v10 = randomSigned(seed, cellX + 1, cellZ);
446
double v01 = randomSigned(seed, cellX, cellZ + 1);
447
double v11 = randomSigned(seed, cellX + 1, cellZ + 1);
448
return lerp(lerp(v00, v10, sx), lerp(v01, v11, sx), sz);
449
}
450
451
private static double randomSigned(long seed, int x, int z) {
452
return randomUnit(seed + mix(x, z)) * 2.0D - 1.0D;
453
}
454
455
private static double smoothStep(double edge0, double edge1, double value) {
456
double t = Math.max(0.0D, Math.min(1.0D, (value - edge0) / (edge1 - edge0)));
457
return t * t * (3.0D - 2.0D * t);
458
}
459
460
private static double fade(double value) {
461
return value * value * value * (value * (value * 6.0D - 15.0D) + 10.0D);
462
}
463
464
private static double lerp(double a, double b, double t) {
465
return a + (b - a) * t;
466
}
467
468
private static double phase(long seed, int salt) {
469
return randomUnit(seed + salt * 0x632BE59BD9B4E019L) * TWO_PI;
249
470
}
250
471
251
472
private static int randomInt(long seed, int salt, int bound) {
@@ -269,6 +490,76 @@ public class SoaringMindChunkGenerator extends ChunkGenerator {
269
490
return value;
270
491
}
271
492
272
private record Island(int x, int y, int z, int radiusX, int radiusZ, int height, long seed) {
493
private enum IslandTheme {
494
PLAINS,
495
FOREST,
496
LUSH,
497
DESERT,
498
SNOWY,
499
ROCKY
500
}
501
502
private enum IslandSize {
503
TINY(4, 8, 8, 10, 4, 5, false),
504
SMALL(11, 15, 14, 16, 8, 8, true),
505
MEDIUM(28, 34, 34, 28, 16, 18, true),
506
LARGE(58, 60, 58, 42, 30, 34, true);
507
508
private final int minRadius;
509
private final int radiusRange;
510
private final int minHeight;
511
private final int heightRange;
512
private final int stretch;
513
private final int tipDepth;
514
private final boolean allowsLake;
515
516
IslandSize(int minRadius, int radiusRange, int minHeight, int heightRange, int stretch, int tipDepth, boolean allowsLake) {
517
this.minRadius = minRadius;
518
this.radiusRange = radiusRange;
519
this.minHeight = minHeight;
520
this.heightRange = heightRange;
521
this.stretch = stretch;
522
this.tipDepth = tipDepth;
523
this.allowsLake = allowsLake;
524
}
525
526
private int minRadius() {
527
return minRadius;
528
}
529
530
private int radiusRange() {
531
return radiusRange;
532
}
533
534
private int minHeight() {
535
return minHeight;
536
}
537
538
private int heightRange() {
539
return heightRange;
540
}
541
542
private int stretch() {
543
return stretch;
544
}
545
546
private int tipDepth() {
547
return tipDepth;
548
}
549
550
private boolean allowsLake() {
551
return allowsLake;
552
}
553
}
554
555
private record Island(int x, int y, int z, int radiusX, int radiusZ, int height, int edgeDrop,
556
int edgeThickness, int tipDepth, double angle, IslandTheme theme, boolean hasLake,
557
int lakeX, int lakeZ, int lakeRadiusX, int lakeRadiusZ, int waterY, long seed) {
558
}
559
560
private record IslandSlice(int topY, int bottomY, int solidTopY, int waterTopY, Island island) {
561
private boolean hasWater() {
562
return waterTopY >= 0;
563
}
273
564
}
274
565
}
@@ -3,8 +3,22 @@
3
3
"generator": {
4
4
"type": "mydimension:soaring_islands",
5
5
"biome_source": {
6
"type": "minecraft:multi_noise",
7
"preset": "minecraft:overworld"
6
"type": "minecraft:checkerboard",
7
"biomes": [
8
"minecraft:plains",
9
"minecraft:forest",
10
"minecraft:flower_forest",
11
"minecraft:birch_forest",
12
"minecraft:meadow",
13
"minecraft:cherry_grove",
14
"minecraft:snowy_plains",
15
"minecraft:grove",
16
"minecraft:desert",
17
"minecraft:savanna",
18
"minecraft:jungle",
19
"minecraft:windswept_hills"
20
],
21
"scale": 3
8
22
}
9
23
}
10
24
}