@@ -35,6 +35,7 @@ public final class BakedGeomeConfig {
3535 private final Map <Biome , double []> biomeWeights ;
3636 private final Map <ResourceLocation , double []> biomeWeightsById ;
3737 private final double [] fallbackWeights ;
38+ private final RockEntry [] rocks ;
3839 private final BlockState [] rockStates ;
3940 private final Set <Block > sedimentaryBlocks ;
4041 private final Set <Block > oreReplaceableBlocks ;
@@ -45,6 +46,9 @@ public final class BakedGeomeConfig {
4546 private WeightedBlockPicker [][][] legacyRockPickers ;
4647 private byte [] stableFamilyChoices ;
4748 private int [] stableRockChoices ;
49+ private int [][] familyRockIndexes ;
50+ private double [][][] stableRockLogWeights ;
51+ private double [][][] stableRockPriorities ;
4852
4953 BakedGeomeConfig (GeomeDefinition [] geomes , double geomeScale , double biomeInfluence ,
5054 double regionalNoiseInfluence , double boundaryNoiseInfluence , Map <Biome , double []> biomeWeights ,
@@ -72,6 +76,7 @@ public final class BakedGeomeConfig {
7276 noiseOffsetZ [i ] = -((i + 1 ) * 6151 );
7377 }
7478
79+ this .rocks = rocks .clone ();
7580 rockStates = new BlockState [rocks .length ];
7681 for (int i = 0 ; i < rocks .length ; i ++) {
7782 rockStates [i ] = rocks [i ].state ;
@@ -152,15 +157,69 @@ RockFamily pickFamily(int geomeIndex, int y, int formationValue, int diversitySl
152157 return RockFamily .SEDIMENTARY ;
153158 }
154159
160+ RockFamily pickStableFamilyAtWorldY (int geomeIndex , int worldY , int formationY ,
161+ int formationValue , int diversitySlot ) {
162+ RockFamily preferred = pickFamily (geomeIndex , formationY , formationValue , diversitySlot );
163+ if (hasEligibleStableRock (geomeIndex , preferred , worldY , formationY )) {
164+ return preferred ;
165+ }
166+
167+ int bucket = formationValue & 0xFF ;
168+ int boundedFormationY = clampStableValue (formationY );
169+ double bestScore = Double .NEGATIVE_INFINITY ;
170+ RockFamily bestFamily = preferred ;
171+ for (RockFamily family : RockFamily .values ()) {
172+ if (!hasEligibleStableRock (geomeIndex , family , worldY , formationY )) {
173+ continue ;
174+ }
175+ double weight = Math .pow (geomes [geomeIndex ].familyWeights [family .ordinal ()], 2.5D )
176+ * familyDepthWeight (family , boundedFormationY );
177+ if (weight <= 0.0D ) {
178+ continue ;
179+ }
180+ double score = Math .log (weight ) + gumbelPriority (bucket , geomeIndex , family .ordinal (),
181+ isStableBucket (bucket , -1 ), 0x6A09E667F3BCC909L );
182+ if (score > bestScore ) {
183+ bestScore = score ;
184+ bestFamily = family ;
185+ }
186+ }
187+ return bestFamily ;
188+ }
189+
155190 public BlockState pickRock (int geomeIndex , RockFamily family , int y , int formationValue ) {
156191 if (formations .usesStableLayers ()) {
157- int index = stableRockIndex (geomeIndex , family .ordinal (), clampStableY (y ), formationValue & 0xFF );
158- int rockIndex = stableRockChoices [index ];
159- return rockIndex < 0 ? FALLBACK : rockStates [rockIndex ];
192+ return pickStableRockAtWorldY (geomeIndex , family , y , y , formationValue );
160193 }
161194 return legacyRockPickers [geomeIndex ][family .ordinal ()][clampLegacyY (y )].pick (formationValue );
162195 }
163196
197+ BlockState pickStableRockAtWorldY (int geomeIndex , RockFamily family , int worldY ,
198+ int formationY , int formationValue ) {
199+ int yIndex = clampStableY (formationY );
200+ int bucket = formationValue & 0xFF ;
201+ int choiceIndex = stableRockIndex (geomeIndex , family .ordinal (), yIndex , bucket );
202+ int selectedRock = stableRockChoices [choiceIndex ];
203+ if (isEligibleStableRock (geomeIndex , selectedRock , worldY , yIndex )) {
204+ return rockStates [selectedRock ];
205+ }
206+
207+ double bestScore = Double .NEGATIVE_INFINITY ;
208+ int bestRock = -1 ;
209+ for (int rockIndex : familyRockIndexes [family .ordinal ()]) {
210+ if (!isEligibleStableRock (geomeIndex , rockIndex , worldY , yIndex )) {
211+ continue ;
212+ }
213+ double score = stableRockLogWeights [geomeIndex ][rockIndex ][yIndex ]
214+ + stableRockPriorities [geomeIndex ][rockIndex ][bucket ];
215+ if (score > bestScore ) {
216+ bestScore = score ;
217+ bestRock = rockIndex ;
218+ }
219+ }
220+ return bestRock < 0 ? FALLBACK : rockStates [bestRock ];
221+ }
222+
164223 public String geomeName (int geomeIndex ) {
165224 return geomes [geomeIndex ].name ;
166225 }
@@ -283,9 +342,9 @@ private void buildStablePickers(RockEntry[] rocks) {
283342 stableRockChoices = new int [geomes .length * RockFamily .values ().length * HEIGHT * FORMATION_BUCKETS ];
284343 Arrays .fill (stableRockChoices , -1 );
285344 int familyCount = RockFamily .values ().length ;
286- int [][] familyRockIndexes = groupRockIndexes (rocks );
287- double [][][] rockLogWeights = new double [geomes .length ][rocks .length ][HEIGHT ];
288- double [][][] rockPriorities = new double [geomes .length ][rocks .length ][FORMATION_BUCKETS ];
345+ familyRockIndexes = groupRockIndexes (rocks );
346+ stableRockLogWeights = new double [geomes .length ][rocks .length ][HEIGHT ];
347+ stableRockPriorities = new double [geomes .length ][rocks .length ][FORMATION_BUCKETS ];
289348 double [][][] familyLogWeights = new double [geomes .length ][familyCount ][HEIGHT ];
290349 double [][][] familyWeights = new double [geomes .length ][familyCount ][HEIGHT ];
291350 double [][][] familyPriorities = new double [geomes .length ][familyCount ][FORMATION_BUCKETS ];
@@ -294,14 +353,13 @@ private void buildStablePickers(RockEntry[] rocks) {
294353 for (int rockIndex = 0 ; rockIndex < rocks .length ; rockIndex ++) {
295354 RockEntry rock = rocks [rockIndex ];
296355 for (int y = MIN_Y ; y <= MAX_Y ; y ++) {
297- double rawWeight = y < rock .minY || y > rock .maxY ? 0.0D
298- : rock .weight * rock .geomeWeights [geome ]
299- * depthWeight (y , rock .depthPeak , rock .depthSpread );
300- rockLogWeights [geome ][rockIndex ][y - MIN_Y ] = rawWeight > 0.0D
356+ double rawWeight = rock .weight * rock .geomeWeights [geome ]
357+ * depthWeight (y , rock .depthPeak , rock .depthSpread );
358+ stableRockLogWeights [geome ][rockIndex ][y - MIN_Y ] = rawWeight > 0.0D
301359 ? Math .log (rawWeight ) : Double .NEGATIVE_INFINITY ;
302360 }
303361 for (int bucket = 0 ; bucket < FORMATION_BUCKETS ; bucket ++) {
304- rockPriorities [geome ][rockIndex ][bucket ] = gumbelPriority (bucket , geome , rockIndex ,
362+ stableRockPriorities [geome ][rockIndex ][bucket ] = gumbelPriority (bucket , geome , rockIndex ,
305363 isStableBucket (bucket , rock .family .ordinal ()),
306364 0xBB67AE8584CAA73BL ^ ((long ) rock .family .ordinal () << 32 ));
307365 }
@@ -313,7 +371,9 @@ private void buildStablePickers(RockEntry[] rocks) {
313371 int yIndex = y - MIN_Y ;
314372 boolean available = false ;
315373 for (int rockIndex : familyRockIndexes [familyIndex ]) {
316- if (rockLogWeights [geome ][rockIndex ][yIndex ] != Double .NEGATIVE_INFINITY ) {
374+ RockEntry rock = rocks [rockIndex ];
375+ if (y >= rock .minY && y <= rock .maxY
376+ && stableRockLogWeights [geome ][rockIndex ][yIndex ] != Double .NEGATIVE_INFINITY ) {
317377 available = true ;
318378 break ;
319379 }
@@ -363,8 +423,12 @@ private void buildStablePickers(RockEntry[] rocks) {
363423 double bestRockScore = Double .NEGATIVE_INFINITY ;
364424 int bestRock = -1 ;
365425 for (int rockIndex : familyRockIndexes [familyIndex ]) {
366- double rockScore = rockLogWeights [geome ][rockIndex ][yIndex ]
367- + rockPriorities [geome ][rockIndex ][bucket ];
426+ RockEntry rock = rocks [rockIndex ];
427+ if (y < rock .minY || y > rock .maxY ) {
428+ continue ;
429+ }
430+ double rockScore = stableRockLogWeights [geome ][rockIndex ][yIndex ]
431+ + stableRockPriorities [geome ][rockIndex ][bucket ];
368432 if (rockScore > bestRockScore ) {
369433 bestRockScore = rockScore ;
370434 bestRock = rockIndex ;
@@ -377,6 +441,25 @@ private void buildStablePickers(RockEntry[] rocks) {
377441 }
378442 }
379443
444+ private boolean hasEligibleStableRock (int geomeIndex , RockFamily family , int worldY , int formationY ) {
445+ int yIndex = clampStableY (formationY );
446+ for (int rockIndex : familyRockIndexes [family .ordinal ()]) {
447+ if (isEligibleStableRock (geomeIndex , rockIndex , worldY , yIndex )) {
448+ return true ;
449+ }
450+ }
451+ return false ;
452+ }
453+
454+ private boolean isEligibleStableRock (int geomeIndex , int rockIndex , int worldY , int formationYIndex ) {
455+ if (rockIndex < 0 ) {
456+ return false ;
457+ }
458+ RockEntry rock = rocks [rockIndex ];
459+ return worldY >= rock .minY && worldY <= rock .maxY
460+ && stableRockLogWeights [geomeIndex ][rockIndex ][formationYIndex ] != Double .NEGATIVE_INFINITY ;
461+ }
462+
380463 private void fillBalancedFamilyCycle (int geome , int yIndex , int bucket ,
381464 double [][][] familyWeights , double [][][] familyPriorities ,
382465 int [] quotas , int [] remaining , double [] remainders , boolean [] bonusAwarded ) {
@@ -631,6 +714,10 @@ private static int clampStableY(int y) {
631714 return Math .max (MIN_Y , Math .min (MAX_Y , y )) - MIN_Y ;
632715 }
633716
717+ private static int clampStableValue (int y ) {
718+ return Math .max (MIN_Y , Math .min (MAX_Y , y ));
719+ }
720+
634721 private static int clampLegacyY (int y ) {
635722 return Math .max (0 , Math .min (LEGACY_MAX_Y , y ));
636723 }
0 commit comments