Skip to content

Commit

Permalink
Merge branch '1.20.4' into 1.20.6
Browse files Browse the repository at this point in the history
  • Loading branch information
rfresh2 committed Jul 13, 2024
2 parents 61fe824 + d2b9715 commit 6d91f4b
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 55 deletions.
2 changes: 1 addition & 1 deletion common/src/main/java/xaeroplus/module/ModuleManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static void init() {
asList(
new BaritoneGoalSync(),
new FpsLimiter(),
new NewChunks(),
new LiquidNewChunks(),
new OldChunks(),
new PaletteNewChunks(),
new Portals(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import static xaeroplus.feature.render.ColorHelper.getColor;
import static xaeroplus.util.ChunkUtils.getActualDimension;

public class NewChunks extends Module {
public class LiquidNewChunks extends Module {
// chunks where liquid started flowing from source blocks after we loaded it
private ChunkHighlightCache newChunksCache = new ChunkHighlightLocalCache();
// chunks where liquid was already flowing or flowed when we loaded it
Expand Down Expand Up @@ -238,11 +238,11 @@ private int getInverseColor() {
}

public void setRgbColor(final int color) {
newChunksColor = ColorHelper.getColorWithAlpha(color, (int) XaeroPlusSettingRegistry.newChunksAlphaSetting.getValue());
newChunksColor = ColorHelper.getColorWithAlpha(color, (int) XaeroPlusSettingRegistry.liquidNewChunksAlphaSetting.getValue());
}

public void setInverseRgbColor(final int color) {
inverseColor = ColorHelper.getColorWithAlpha(color, (int) XaeroPlusSettingRegistry.newChunksAlphaSetting.getValue());
inverseColor = ColorHelper.getColorWithAlpha(color, (int) XaeroPlusSettingRegistry.liquidNewChunksAlphaSetting.getValue());
}

public void setAlpha(final float a) {
Expand Down
19 changes: 7 additions & 12 deletions common/src/main/java/xaeroplus/module/impl/OldChunks.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,20 @@ private void searchChunkAsync(final ChunkAccess chunk) {
});
}

private boolean searchChunk(final ChunkAccess chunk) throws InterruptedException {
private boolean searchChunk(final ChunkAccess chunk) {
ResourceKey<Level> actualDimension = ChunkUtils.getActualDimension();
var x = chunk.getPos().x;
var z = chunk.getPos().z;
if (actualDimension == OVERWORLD || actualDimension == NETHER) {
if (ChunkScanner.chunkContainsBlocks(chunk, actualDimension == OVERWORLD ? OVERWORLD_BLOCKS : NETHER_BLOCKS, 5)) {
return modernChunksCache.addHighlight(x, z);
} else {
return oldChunksCache.addHighlight(x, z);
}
return ChunkScanner.chunkContainsBlocks(chunk, actualDimension == OVERWORLD ? OVERWORLD_BLOCKS : NETHER_BLOCKS, 5)
? modernChunksCache.addHighlight(x, z)
: oldChunksCache.addHighlight(x, z);
} else if (actualDimension == END) {
Holder<Biome> biome = mc.level.getBiome(new BlockPos(ChunkUtils.chunkCoordToCoord(x) + 8, 64, ChunkUtils.chunkCoordToCoord(z) + 8));
var biomeKey = biome.unwrapKey().get();
if (biomeKey == Biomes.PLAINS) return false; // mitigate race condition where biomes aren't loaded yet for some reason
if (biomeKey == Biomes.THE_END) {
return oldChunksCache.addHighlight(x, z);
} else {
return modernChunksCache.addHighlight(x, z);
}
return biomeKey == Biomes.THE_END
? oldChunksCache.addHighlight(x, z)
: modernChunksCache.addHighlight(x, z);
}
return true;
}
Expand Down
75 changes: 49 additions & 26 deletions common/src/main/java/xaeroplus/module/impl/PaletteNewChunks.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package xaeroplus.module.impl;

import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.longs.Long2LongMap;
import net.lenni0451.lambdaevents.EventHandler;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.BitStorage;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
Expand Down Expand Up @@ -31,6 +34,7 @@ public class PaletteNewChunks extends Module {
private ChunkHighlightCache newChunksCache = new ChunkHighlightLocalCache();
private int newChunksColor = getColor(255, 0, 0, 100);
private static final String DATABASE_NAME = "XaeroPlusPaletteNewChunks";
private final IntSet presentStateIdsBuf = new IntOpenHashSet();

public void setNewChunksCache(final boolean disk) {
try {
Expand Down Expand Up @@ -71,45 +75,53 @@ public void onChunkData(ChunkDataEvent event) {

/**
* MC generates chunks in multiple steps where each step progressively mutates the chunk data
* For more info see this explanation by Henrik Kniberg: https://youtu.be/ob3VwY4JyzE&t=453
*
* when generation is complete there can be block palette entries that no longer
* have corresponding blockstates present in the chunk data
* When a chunk is first generated it is populated first by air, then by additional block types like stone, water, etc
* By the end of these steps, the chunk's blockstate palette will still contain references to all states that were ever present
* For more info on what chunk palettes are see: https://wiki.vg/Chunk_Format#Paletted_Container_structure
*
* when the MC server writes + reads the chunks to region files it also compacts the palette to save disk space
* the key is that this compaction occurs _after_ the chunk data is sent to players
* When the MC server writes + reads the chunks to region files it compacts the palette to save disk space
* the key is that this compaction occurs _after_ newly generated chunk data is sent to players
*
* compacting has 2 effects:
* 1. palette entries without blockstates present in the chunk are removed
* 2. the order of ids in the palette changes
* 2. the order of ids in the palette can change as it is rebuilt in order of the actual blockstates present in the chunk
*
* so we can simply check if the first entry of the lowest section's block palette is air.
* if the chunk has been generated before it will be removed entirely or its position in the palette changed
* So we are simply checking if the first entry of the lowest section's block palette is air
* The lowest section should always have bedrock as the first entry at the bottom section after compacting
*
* there is a chance for false negatives depending on features like mineshafts, geodes, etc that generate on the bottom section.
* but it should be possible to repeat similar checks on other sections to get more accurate results
* However, there is a chance for false negatives if the chunk's palette generates with more than 16 different blockstates
* The palette gets resized to a HashMapPalette which does not retain the original entry ordering
* Usually this happens when features like mineshafts or the deep dark generates
* To catch these we fall back to checking if the palette has more entries than what is actually present in the chunk data
*/
private boolean checkNewChunkOverworldOrNether(LevelChunk chunk) {
var sections = chunk.getSections();
if (sections.length == 0) return false;
var firstSection = sections[0];
Palette<BlockState> firstPalette = firstSection.getStates().data.palette();
if (firstPalette.getSize() < 1
|| firstPalette instanceof SingleValuePalette<BlockState>
|| firstPalette instanceof GlobalPalette<BlockState>)
return false;
try {
if (isNotLinearOrHashMapPalette(firstPalette)) return false;
if (firstPalette instanceof LinearPalette<BlockState>) {
return firstPalette.valueFor(0).getBlock() == Blocks.AIR;
} catch (final MissingPaletteEntryException e) {
// fall through
} else { // HashMapPalette
// we could iterate through more sections but this is good enough in most cases
// checking every blockstate is relatively expensive
for (int i = 0; i < Math.min(sections.length, 3); i++) {
var section = sections[i];
var paletteContainerData = section.getStates().data;
var palette = paletteContainerData.palette();
if (isNotLinearOrHashMapPalette(palette)) continue;
if (checkForExtraPaletteEntries(paletteContainerData)) return true;
}
}
return false;
}

/**
* Similar concept to Overworld/Nether but here we check the biome palette
* Similar to Overworld/Nether but we check the biome palette instead
*
* for some reason end generation sets the first palette entry to plains before compaction
* so we check if the first entry is the correct void biome
* New chunks generated in the end will set the first biome palette entry to plains before compaction
*/
private boolean checkNewChunkEnd(LevelChunk chunk) {
var sections = chunk.getSections();
Expand All @@ -118,18 +130,29 @@ private boolean checkNewChunkEnd(LevelChunk chunk) {
var biomes = firstSection.getBiomes();
if (biomes instanceof PalettedContainer<Holder<Biome>> biomesPaletteContainer) {
Palette<Holder<Biome>> firstPalette = biomesPaletteContainer.data.palette();
// singleton palette will never have more than 1 value
// and we should never have enough entries for a hashmap or global palette
// so we only care about linear palettes
if (firstPalette instanceof LinearPalette<Holder<Biome>> linearPalette
&& linearPalette.getSize() > 0) {
Holder<Biome> firstId = linearPalette.valueFor(0);
return firstId.unwrapKey().filter(k -> k.equals(Biomes.THE_VOID)).isEmpty();
// chunks already generated in the end will not have more than 1 biome present (stored in SingleValuePalette)
// so just checking the palette size is sufficient
// but we also check if the first entry is plains to be extra sure
if (firstPalette.getSize() > 1) {
Holder<Biome> firstBiome = firstPalette.valueFor(0);
return firstBiome.unwrapKey().filter(k -> k.equals(Biomes.PLAINS)).isPresent();
}
}
return false;
}

private boolean isNotLinearOrHashMapPalette(Palette palette) {
return palette.getSize() <= 0 || !(palette instanceof LinearPalette || palette instanceof HashMapPalette);
}

private synchronized boolean checkForExtraPaletteEntries(PalettedContainer.Data<BlockState> paletteContainer) {
presentStateIdsBuf.clear(); // reusing to reduce gc pressure
var palette = paletteContainer.palette();
BitStorage storage = paletteContainer.storage();
storage.getAll(presentStateIdsBuf::add);
return palette.getSize() > presentStateIdsBuf.size();
}

@EventHandler
public void onXaeroWorldChangeEvent(final XaeroWorldChangeEvent event) {
newChunksCache.handleWorldChange();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ private boolean isNewishChunk(final int chunkPosX, final int chunkPosZ, final Re
}

private boolean isNewChunk(final int chunkPosX, final int chunkPosZ, final ResourceKey<Level> currentlyViewedDimension) {
if (XaeroPlusSettingRegistry.newChunksEnabledSetting.getValue() && newChunksModule != null)
if (XaeroPlusSettingRegistry.paletteNewChunksSaveLoadToDisk.getValue() && newChunksModule != null)
return newChunksModule.isNewChunk(chunkPosX, chunkPosZ, currentlyViewedDimension);
else
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,48 +216,48 @@ public final class XaeroPlusSettingRegistry {
ColorHelper.HighlightColor.values(),
ColorHelper.HighlightColor.RED,
SettingLocation.CHUNK_HIGHLIGHTS);
public static final XaeroPlusBooleanSetting newChunksEnabledSetting = XaeroPlusBooleanSetting.create(
public static final XaeroPlusBooleanSetting liquidNewChunksEnabledSetting = XaeroPlusBooleanSetting.create(
"NewChunks Highlighting",
"setting.world_map.new_chunks_highlighting",
"setting.world_map.new_chunks_highlighting.tooltip",
(b) -> ModuleManager.getModule(NewChunks.class).setEnabled(b),
(b) -> ModuleManager.getModule(LiquidNewChunks.class).setEnabled(b),
false,
SettingLocation.CHUNK_HIGHLIGHTS);
public static final XaeroPlusBooleanSetting newChunksSaveLoadToDisk = XaeroPlusBooleanSetting.create(
public static final XaeroPlusBooleanSetting liquidNewChunksSaveLoadToDisk = XaeroPlusBooleanSetting.create(
"Save/Load NewChunks to Disk",
"setting.world_map.new_chunks_save_load_to_disk",
"setting.world_map.new_chunks_save_load_to_disk.tooltip",
(b) -> ModuleManager.getModule(NewChunks.class).setNewChunksCache(b),
(b) -> ModuleManager.getModule(LiquidNewChunks.class).setNewChunksCache(b),
true,
SettingLocation.CHUNK_HIGHLIGHTS);
public static final XaeroPlusFloatSetting newChunksAlphaSetting = XaeroPlusFloatSetting.create(
public static final XaeroPlusFloatSetting liquidNewChunksAlphaSetting = XaeroPlusFloatSetting.create(
"New Chunks Opacity",
"setting.world_map.new_chunks_opacity",
0f, 255f, 10f,
"setting.world_map.new_chunks_opacity.tooltip",
(b) -> ModuleManager.getModule(NewChunks.class).setAlpha(b),
(b) -> ModuleManager.getModule(LiquidNewChunks.class).setAlpha(b),
100,
SettingLocation.CHUNK_HIGHLIGHTS);
public static final XaeroPlusEnumSetting<ColorHelper.HighlightColor> newChunksColorSetting = XaeroPlusEnumSetting.create(
public static final XaeroPlusEnumSetting<ColorHelper.HighlightColor> liquidNewChunksColorSetting = XaeroPlusEnumSetting.create(
"New Chunks Color",
"setting.world_map.new_chunks_color",
"setting.world_map.new_chunks_color.tooltip",
(b) -> ModuleManager.getModule(NewChunks.class).setRgbColor(b.getColor()),
(b) -> ModuleManager.getModule(LiquidNewChunks.class).setRgbColor(b.getColor()),
ColorHelper.HighlightColor.values(),
ColorHelper.HighlightColor.RED,
SettingLocation.CHUNK_HIGHLIGHTS);
public static final XaeroPlusBooleanSetting newChunksInverseHighlightsSetting = XaeroPlusBooleanSetting.create(
public static final XaeroPlusBooleanSetting liquidNewChunksInverseHighlightsSetting = XaeroPlusBooleanSetting.create(
"New Chunks Render Inverse",
"setting.world_map.new_chunks_inverse_enabled",
"setting.world_map.new_chunks_inverse_enabled.tooltip",
(b) -> ModuleManager.getModule(NewChunks.class).setInverseRenderEnabled(b),
(b) -> ModuleManager.getModule(LiquidNewChunks.class).setInverseRenderEnabled(b),
false,
SettingLocation.CHUNK_HIGHLIGHTS);
public static final XaeroPlusEnumSetting<ColorHelper.HighlightColor> newChunksInverseColorSetting = XaeroPlusEnumSetting.create(
public static final XaeroPlusEnumSetting<ColorHelper.HighlightColor> liquidNewChunksInverseColorSetting = XaeroPlusEnumSetting.create(
"New Chunks Inverse Color",
"setting.world_map.new_chunks_inverse_color",
"setting.world_map.new_chunks_inverse_color.tooltip",
(b) -> ModuleManager.getModule(NewChunks.class).setInverseRgbColor(b.getColor()),
(b) -> ModuleManager.getModule(LiquidNewChunks.class).setInverseRgbColor(b.getColor()),
ColorHelper.HighlightColor.values(),
ColorHelper.HighlightColor.GREEN,
SettingLocation.CHUNK_HIGHLIGHTS);
Expand Down

0 comments on commit 6d91f4b

Please sign in to comment.