Skip to content

Commit

Permalink
Merge branch 'develop' into add-track-block-state-change-method
Browse files Browse the repository at this point in the history
  • Loading branch information
2No2Name authored Apr 9, 2024
2 parents 7799e2a + e2bf990 commit 8cbc379
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static boolean isSectionSafeAsNeighbor(ChunkSection section) {
}

if (BlockStateFlags.ENABLED) {
return !((BlockCountingSection) section).mayContainAny(BlockStateFlags.PATH_NOT_OPEN);
return !((BlockCountingSection) section).lithium$mayContainAny(BlockStateFlags.PATH_NOT_OPEN);
}
return !isChunkSectionDangerousNeighbor(section);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import net.minecraft.block.BlockState;

public interface BlockCountingSection {
boolean mayContainAny(TrackedBlockStatePredicate trackedBlockStatePredicate);
boolean lithium$mayContainAny(TrackedBlockStatePredicate trackedBlockStatePredicate);

void lithium$trackBlockStateChange(BlockState newState, BlockState oldState);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package me.jellysquid.mods.lithium.common.block;

import me.jellysquid.mods.lithium.common.entity.block_tracking.SectionedBlockChangeTracker;
import net.minecraft.util.math.ChunkSectionPos;

public interface BlockListeningSection {

void addToCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker);
void removeFromCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker);
void lithium$addToCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker);

void lithium$removeFromCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker);

void lithium$invalidateListeningSection(ChunkSectionPos sectionPos);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import me.jellysquid.mods.lithium.common.block.BlockListeningSection;
import me.jellysquid.mods.lithium.common.block.BlockStateFlags;
import me.jellysquid.mods.lithium.common.block.ListeningBlockStatePredicate;
import net.minecraft.util.math.ChunkSectionPos;

import java.util.ArrayList;

Expand All @@ -23,7 +24,7 @@ public short onBlockChange(int flagIndex, BlockListeningSection section) {
for (int i = 0; i < sectionedBlockChangeTrackers.size(); i++) {
sectionedBlockChangeTrackers.get(i).setChanged(section);
}
this.listeningMask &= ~(1 << flagIndex);
this.listeningMask &= (short) ~(1 << flagIndex);

return this.listeningMask;
}
Expand All @@ -36,7 +37,7 @@ public short addTracker(SectionedBlockChangeTracker tracker, ListeningBlockState
}
sectionedBlockChangeTrackers.add(tracker);

this.listeningMask |= (1 << blockGroupIndex);
this.listeningMask |= (short) (1 << blockGroupIndex);
return this.listeningMask;
}

Expand All @@ -46,9 +47,23 @@ public short removeTracker(SectionedBlockChangeTracker tracker, ListeningBlockSt
if (sectionedBlockChangeTrackers != null) {
sectionedBlockChangeTrackers.remove(tracker);
if (sectionedBlockChangeTrackers.isEmpty()) {
this.listeningMask &= ~(1 << blockGroup.getIndex());
this.listeningMask &= (short) ~(1 << blockGroup.getIndex());
}
}
return this.listeningMask;
}

public void onChunkSectionInvalidated(ChunkSectionPos sectionPos) {
for (int flagIndex = 0; flagIndex < this.trackers.length; flagIndex++) {
ArrayList<SectionedBlockChangeTracker> sectionedBlockChangeTrackers = this.trackers[flagIndex];
this.trackers[flagIndex] = null;
if (sectionedBlockChangeTrackers != null) {
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < sectionedBlockChangeTrackers.size(); i++) {
sectionedBlockChangeTrackers.get(i).onChunkSectionInvalidated(sectionPos);
}
}
}
this.listeningMask = 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ public void register() {
ChunkSection section = sectionArray[Pos.SectionYIndex.fromSectionCoord(trackedSections.world(), y)];

BlockListeningSection blockListeningSection = (BlockListeningSection) section;
blockListeningSection.addToCallback(this.blockGroup, this);
blockListeningSection.lithium$addToCallback(this.blockGroup, this);
}
}
}
this.isListeningToAll = (this.sectionsNotListeningTo == null || this.sectionsNotListeningTo.isEmpty())
&& (this.sectionsUnsubscribed == null || this.sectionsUnsubscribed.isEmpty());
this.setChanged(this.getWorldTime());
}
this.timesRegistered++;
Expand All @@ -103,7 +105,7 @@ public void unregister() {
ChunkSection section = sectionArray[Pos.SectionYIndex.fromSectionCoord(world, y)];

BlockListeningSection blockListeningSection = (BlockListeningSection) section;
blockListeningSection.removeFromCallback(this.blockGroup, this);
blockListeningSection.lithium$removeFromCallback(this.blockGroup, this);
}
}
}
Expand All @@ -128,15 +130,15 @@ public void listenToAllSections() {
}
ChunkSection section = chunk.getSectionArray()[Pos.SectionYIndex.fromSectionCoord(this.trackedWorldSections.world(), chunkSectionPos.getY())];
BlockListeningSection blockListeningSection = (BlockListeningSection) section;
blockListeningSection.addToCallback(this.blockGroup, this);
blockListeningSection.lithium$addToCallback(this.blockGroup, this);
}
}
if (this.sectionsUnsubscribed != null) {
ArrayList<BlockListeningSection> unsubscribed = this.sectionsUnsubscribed;
for (int i = unsubscribed.size() - 1; i >= 0; i--) {
changed = true;
BlockListeningSection blockListeningSection = unsubscribed.remove(i);
blockListeningSection.addToCallback(this.blockGroup, this);
blockListeningSection.lithium$addToCallback(this.blockGroup, this);
}
}
this.isListeningToAll = true;
Expand Down Expand Up @@ -192,4 +194,13 @@ public boolean equals(Object obj) {
public int hashCode() {
return this.getClass().hashCode() ^ this.trackedWorldSections.hashCode() ^ this.blockGroup.hashCode();
}

public void onChunkSectionInvalidated(ChunkSectionPos sectionPos) {
if (this.sectionsNotListeningTo == null) {
this.sectionsNotListeningTo = new ArrayList<>();
}
this.sectionsNotListeningTo.add(sectionPos);
this.setChanged(this.getWorldTime());
this.isListeningToAll = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ private static int expandMax(int coord) {
private static boolean hasChunkSectionOversizedBlocks(Chunk chunk, int chunkY) {
if (BlockStateFlags.ENABLED) {
ChunkSection section = chunk.getSectionArray()[chunkY];
return section != null && ((BlockCountingSection) section).mayContainAny(BlockStateFlags.OVERSIZED_SHAPE);
return section != null && ((BlockCountingSection) section).lithium$mayContainAny(BlockStateFlags.OVERSIZED_SHAPE);
}
return true; //like vanilla, assume that a chunk section has oversized blocks, when the section mixin isn't loaded
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ public class PoolMixin<E extends Weighted> {
@Final
private ImmutableList<E> entries;
//Need a separate variable due to entries being type ImmutableList
@Unique
private List<E> entryHashList;

@Inject(method = "<init>(Ljava/util/List;)V", at = @At("RETURN"))
private void init(List<? extends E> entries, CallbackInfo ci) {
//We are using reference equality here, because all vanilla implementations of Weighted use reference equality
this.entryHashList = this.entries.size() > 4 ? this.entries : Collections.unmodifiableList(new HashedReferenceList<>(this.entries));
this.entryHashList = this.entries.size() > 4 ? Collections.unmodifiableList(new HashedReferenceList<>(this.entries)) : this.entries;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public abstract class EntityMixin implements FluidCachingEntity {
public abstract Box getBoundingBox();

@Shadow
public World world;
private World world;

@Shadow
protected Object2DoubleMap<TagKey<Fluid>> fluidHeight;
Expand Down Expand Up @@ -63,7 +63,7 @@ public void tryShortcutFluidPushing(TagKey<Fluid> tag, double speed, CallbackInf
Chunk chunk = this.world.getChunk(chunkX, chunkZ);
for (int chunkYIndex = chunkYIndex1; chunkYIndex <= chunkYIndex2; chunkYIndex++) {
ChunkSection section = chunk.getSectionArray()[chunkYIndex];
if (((BlockCountingSection) section).mayContainAny(blockStateFlag)) {
if (((BlockCountingSection) section).lithium$mayContainAny(blockStateFlag)) {
//fluid found, cannot skip code
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import me.jellysquid.mods.lithium.common.entity.block_tracking.SectionedBlockChangeTracker;
import net.minecraft.block.BlockState;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.chunk.PalettedContainer;
import org.spongepowered.asm.mixin.Final;
Expand Down Expand Up @@ -33,17 +34,31 @@ public abstract class ChunkSectionMixin implements BlockCountingSection, BlockLi

@Unique
private short[] countsByFlag = null;
@Unique
private ChunkSectionChangeCallback changeListener;
@Unique
private short listeningMask;

@Unique
private static void addToFlagCount(short[] countsByFlag, BlockState state, short change) {
int flags = ((BlockStateFlagHolder) state).lithium$getAllFlags();
int i;
while ((i = Integer.numberOfTrailingZeros(flags)) < 32 && i < countsByFlag.length) {
//either count up by one (prevFlag not set) or down by one (prevFlag set)
countsByFlag[i] += change;
flags &= ~(1 << i);
}
}

@Override
public boolean mayContainAny(TrackedBlockStatePredicate trackedBlockStatePredicate) {
public boolean lithium$mayContainAny(TrackedBlockStatePredicate trackedBlockStatePredicate) {
if (this.countsByFlag == null) {
fastInitClientCounts();
}
return this.countsByFlag[trackedBlockStatePredicate.getIndex()] != (short) 0;
}

@Unique
private void fastInitClientCounts() {
this.countsByFlag = new short[BlockStateFlags.NUM_TRACKED_FLAGS];
for (TrackedBlockStatePredicate trackedBlockStatePredicate : BlockStateFlags.TRACKED_FLAGS) {
Expand All @@ -65,20 +80,10 @@ private void fastInitClientCounts() {
private void initFlagCounters(PalettedContainer<BlockState> palettedContainer, PalettedContainer.Counter<BlockState> consumer) {
palettedContainer.count((state, count) -> {
consumer.accept(state, count);
addToFlagCount(this.countsByFlag, state, count);
addToFlagCount(this.countsByFlag, state, (short) count);
});
}

private static void addToFlagCount(short[] countsByFlag, BlockState state, int change) {
int flags = ((BlockStateFlagHolder) state).lithium$getAllFlags();
int i;
while ((i = Integer.numberOfTrailingZeros(flags)) < 32 && i < countsByFlag.length) {
//either count up by one (prevFlag not set) or down by one (prevFlag set)
countsByFlag[i] += change;
flags &= ~(1 << i);
}
}

@Inject(method = "calculateCounts()V", at = @At("HEAD"))
private void createFlagCounters(CallbackInfo ci) {
this.countsByFlag = new short[BlockStateFlags.NUM_TRACKED_FLAGS];
Expand Down Expand Up @@ -128,7 +133,7 @@ private void updateFlagCounters(int x, int y, int z, BlockState newState, boolea
int flagBit = 1 << flagIndex;
//either count up by one (prevFlag not set) or down by one (prevFlag set)
if ((flagsXOR & flagBit) != 0) {
countsByFlag[flagIndex] += 1 - (((prevFlags >>> flagIndex) & 1) << 1);
countsByFlag[flagIndex] += (short) (1 - (((prevFlags >>> flagIndex) & 1) << 1));
}
if ((this.listeningMask & flagBit) != 0) {
this.listeningMask = this.changeListener.onBlockChange(flagIndex, this);
Expand All @@ -138,7 +143,7 @@ private void updateFlagCounters(int x, int y, int z, BlockState newState, boolea
}

@Override
public void addToCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker) {
public void lithium$addToCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker) {
if (this.changeListener == null) {
this.changeListener = new ChunkSectionChangeCallback();
}
Expand All @@ -147,17 +152,19 @@ public void addToCallback(ListeningBlockStatePredicate blockGroup, SectionedBloc
}

@Override
public void removeFromCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker) {
public void lithium$removeFromCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker) {
if (this.changeListener != null) {
this.listeningMask = this.changeListener.removeTracker(tracker, blockGroup);
}
}

private boolean isListening(ListeningBlockStatePredicate blockGroup) {
return (this.listeningMask & (1 << blockGroup.getIndex())) != 0;
}
@Override
@Unique
public void lithium$invalidateListeningSection(ChunkSectionPos sectionPos) {
//TODO call this on chunk unload. Entities should already be unloaded, but just to be safe, try to unregister too

public void invalidateSection() {
//TODO on section unload, unregister all kinds of stuff
if ((this.listeningMask) != 0) {
this.changeListener.onChunkSectionInvalidated(sectionPos);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
Expand All @@ -21,9 +20,6 @@
*/
@Mixin(World.class)
public abstract class WorldMixin implements HeightLimitView {
@Shadow
public abstract DimensionType getDimension();

private int bottomY;
private int height;
private int topYInclusive;
Expand All @@ -32,9 +28,9 @@ public abstract class WorldMixin implements HeightLimitView {
method = "<init>",
at = @At("RETURN")
)
private void initHeightCache(MutableWorldProperties properties, RegistryKey<?> registryRef, DynamicRegistryManager registryManager, RegistryEntry<?> dimensionEntry, Supplier<?> profiler, boolean isClient, boolean debugWorld, long biomeAccess, int maxChainedNeighborUpdates, CallbackInfo ci) {
this.height = this.getDimension().height();
this.bottomY = this.getDimension().minY();
private void initHeightCache(MutableWorldProperties properties, RegistryKey<?> registryRef, DynamicRegistryManager registryManager, RegistryEntry<DimensionType> dimensionEntry, Supplier<?> profiler, boolean isClient, boolean debugWorld, long biomeAccess, int maxChainedNeighborUpdates, CallbackInfo ci) {
this.height = dimensionEntry.value().height();
this.bottomY = dimensionEntry.value().minY();
this.topYInclusive = this.bottomY + this.height - 1;
}

Expand Down

0 comments on commit 8cbc379

Please sign in to comment.