diff --git a/src/main/java/net/gensokyoreimagined/nitori/common/world/blockentity/SupportCache.java b/src/main/java/net/gensokyoreimagined/nitori/common/world/blockentity/SupportCache.java new file mode 100644 index 0000000..9c68885 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/common/world/blockentity/SupportCache.java @@ -0,0 +1,5 @@ +package net.gensokyoreimagined.nitori.common.world.blockentity; + +public interface SupportCache { + boolean lithium$isSupported(); +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/common/world/chunk/LithiumHashPalette.java b/src/main/java/net/gensokyoreimagined/nitori/common/world/chunk/LithiumHashPalette.java new file mode 100644 index 0000000..8d9d575 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/common/world/chunk/LithiumHashPalette.java @@ -0,0 +1,197 @@ +package net.gensokyoreimagined.nitori.common.world.chunk; + +//import com.google.common.collect.ImmutableList; +//import it.unimi.dsi.fastutil.HashCommon; +//import it.unimi.dsi.fastutil.objects.Reference2IntMap; +//import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +//import net.minecraft.network.FriendlyByteBuf; +//import net.minecraft.network.VarInt; +//import net.minecraft.core.IdMap; +//import net.minecraft.world.level.chunk.MissingPaletteEntryException; +//import net.minecraft.world.level.chunk.Palette; +//import net.minecraft.world.level.chunk.PaletteResize; +// +//import java.util.Arrays; +//import java.util.List; +//import java.util.function.Predicate; +// +//import static it.unimi.dsi.fastutil.Hash.FAST_LOAD_FACTOR; +// +///** +// * Generally provides better performance over the vanilla {@link net.minecraft.world.chunk.BiMapPalette} when calling +// * {@link LithiumHashPalette#index(Object)} through using a faster backing map and reducing pointer chasing. +// */ +//public class LithiumHashPalette implements Palette { +// private static final int ABSENT_VALUE = -1; +// +// private final IdMap idList; +// private final PaletteResize resizeHandler; +// private final int indexBits; +// +// private final Reference2IntMap table; +// private T[] entries; +// private int size = 0; +// +// public LithiumHashPalette(IdMap idList, PaletteResize resizeHandler, int indexBits, T[] entries, Reference2IntMap table, int size) { +// this.idList = idList; +// this.resizeHandler = resizeHandler; +// this.indexBits = indexBits; +// this.entries = entries; +// this.table = table; +// this.size = size; +// } +// +// public LithiumHashPalette(IdMap idList, int bits, PaletteResizeListener resizeHandler, List list) { +// this(idList, bits, resizeHandler); +// +// for (T t : list) { +// this.addEntry(t); +// } +// } +// +// @SuppressWarnings("unchecked") +// public LithiumHashPalette(IdMap idList, int bits, PaletteResizeListener resizeHandler) { +// this.idList = idList; +// this.indexBits = bits; +// this.resizeHandler = resizeHandler; +// +// int capacity = 1 << bits; +// +// this.entries = (T[]) new Object[capacity]; +// this.table = new Reference2IntOpenHashMap<>(capacity, FAST_LOAD_FACTOR); +// this.table.defaultReturnValue(ABSENT_VALUE); +// } +// +// @Override +// public int index(T obj) { +// int id = this.table.getInt(obj); +// +// if (id == ABSENT_VALUE) { +// id = this.computeEntry(obj); +// } +// +// return id; +// } +// +// @Override +// public boolean hasAny(Predicate predicate) { +// for (int i = 0; i < this.size; ++i) { +// if (predicate.test(this.entries[i])) { +// return true; +// } +// } +// +// return false; +// } +// +// private int computeEntry(T obj) { +// int id = this.addEntry(obj); +// +// if (id >= 1 << this.indexBits) { +// if (this.resizeHandler == null) { +// throw new IllegalStateException("Cannot grow"); +// } else { +// id = this.resizeHandler.onResize(this.indexBits + 1, obj); +// } +// } +// +// return id; +// } +// +// private int addEntry(T obj) { +// int nextId = this.size; +// +// if (nextId >= this.entries.length) { +// this.resize(this.size); +// } +// +// this.table.put(obj, nextId); +// this.entries[nextId] = obj; +// +// this.size++; +// +// return nextId; +// } +// +// private void resize(int neededCapacity) { +// this.entries = Arrays.copyOf(this.entries, HashCommon.nextPowerOfTwo(neededCapacity + 1)); +// } +// +// @Override +// public T get(int id) { +// T[] entries = this.entries; +// +// T entry = null; +// if (id >= 0 && id < entries.length) { +// entry = entries[id]; +// } +// +// if (entry != null) { +// return entry; +// } else { +// throw new MissingPaletteEntryException(id); +// } +// } +// +// @Override +// public void readPacket(FriendlyByteBuf buf) { +// this.clear(); +// +// int entryCount = buf.readVarInt(); +// +// for (int i = 0; i < entryCount; ++i) { +// this.addEntry(this.idList.get(buf.readVarInt())); +// } +// } +// +// @Override +// public void writePacket(FriendlyByteBuf buf) { +// int size = this.size; +// buf.writeVarInt(size); +// +// for (int i = 0; i < size; ++i) { +// buf.writeVarInt(this.idList.getRawId(this.get(i))); +// } +// } +// +// @Override +// public int getPacketSize() { +// int size = VarInt.getSizeInBytes(this.size); +// +// for (int i = 0; i < this.size; ++i) { +// size += VarInt.getSizeInBytes(this.idList.getRawId(this.get(i))); +// } +// +// return size; +// } +// +// @Override +// public int getSize() { +// return this.size; +// } +// +// @Override +// public Palette copy() { +// return new LithiumHashPalette<>(this.idList, this.resizeHandler, this.indexBits, this.entries.clone(), new Reference2IntOpenHashMap<>(this.table), this.size); +// } +// +// private void clear() { +// Arrays.fill(this.entries, null); +// this.table.clear(); +// this.size = 0; +// } +// +// public List getElements() { +// ImmutableList.Builder builder = new ImmutableList.Builder<>(); +// for (T entry : this.entries) { +// if (entry != null) { +// builder.add(entry); +// } +// } +// return builder.build(); +// } +// +// public static Palette create(int bits, IdMap idList, PaletteResizeListener listener, List list) { +// return new LithiumHashPalette<>(idList, bits, listener, list); +// } +//} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/chunk/palette/PalettedContainerMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/chunk/palette/PalettedContainerMixin.java new file mode 100644 index 0000000..4f4f52f --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/chunk/palette/PalettedContainerMixin.java @@ -0,0 +1,197 @@ +package net.gensokyoreimagined.nitori.mixin.chunk.palette; + +//import com.google.common.collect.ImmutableList; +//import it.unimi.dsi.fastutil.HashCommon; +//import it.unimi.dsi.fastutil.objects.Reference2IntMap; +//import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +//import net.minecraft.network.PacketByteBuf; +//import net.minecraft.network.encoding.VarInts; +//import net.minecraft.util.collection.IndexedIterable; +//import net.minecraft.world.chunk.EntryMissingException; +//import net.minecraft.world.chunk.Palette; +//import net.minecraft.world.chunk.PaletteResizeListener; +// +//import java.util.Arrays; +//import java.util.List; +//import java.util.function.Predicate; +// +//import static it.unimi.dsi.fastutil.Hash.FAST_LOAD_FACTOR; +// +///** +// * Generally provides better performance over the vanilla {@link net.minecraft.world.chunk.BiMapPalette} when calling +// * {@link LithiumHashPalette#index(Object)} through using a faster backing map and reducing pointer chasing. +// */ +//public class LithiumHashPalette implements Palette { +// private static final int ABSENT_VALUE = -1; +// +// private final IndexedIterable idList; +// private final PaletteResizeListener resizeHandler; +// private final int indexBits; +// +// private final Reference2IntMap table; +// private T[] entries; +// private int size = 0; +// +// public LithiumHashPalette(IndexedIterable idList, PaletteResizeListener resizeHandler, int indexBits, T[] entries, Reference2IntMap table, int size) { +// this.idList = idList; +// this.resizeHandler = resizeHandler; +// this.indexBits = indexBits; +// this.entries = entries; +// this.table = table; +// this.size = size; +// } +// +// public LithiumHashPalette(IndexedIterable idList, int bits, PaletteResizeListener resizeHandler, List list) { +// this(idList, bits, resizeHandler); +// +// for (T t : list) { +// this.addEntry(t); +// } +// } +// +// @SuppressWarnings("unchecked") +// public LithiumHashPalette(IndexedIterable idList, int bits, PaletteResizeListener resizeHandler) { +// this.idList = idList; +// this.indexBits = bits; +// this.resizeHandler = resizeHandler; +// +// int capacity = 1 << bits; +// +// this.entries = (T[]) new Object[capacity]; +// this.table = new Reference2IntOpenHashMap<>(capacity, FAST_LOAD_FACTOR); +// this.table.defaultReturnValue(ABSENT_VALUE); +// } +// +// @Override +// public int index(T obj) { +// int id = this.table.getInt(obj); +// +// if (id == ABSENT_VALUE) { +// id = this.computeEntry(obj); +// } +// +// return id; +// } +// +// @Override +// public boolean hasAny(Predicate predicate) { +// for (int i = 0; i < this.size; ++i) { +// if (predicate.test(this.entries[i])) { +// return true; +// } +// } +// +// return false; +// } +// +// private int computeEntry(T obj) { +// int id = this.addEntry(obj); +// +// if (id >= 1 << this.indexBits) { +// if (this.resizeHandler == null) { +// throw new IllegalStateException("Cannot grow"); +// } else { +// id = this.resizeHandler.onResize(this.indexBits + 1, obj); +// } +// } +// +// return id; +// } +// +// private int addEntry(T obj) { +// int nextId = this.size; +// +// if (nextId >= this.entries.length) { +// this.resize(this.size); +// } +// +// this.table.put(obj, nextId); +// this.entries[nextId] = obj; +// +// this.size++; +// +// return nextId; +// } +// +// private void resize(int neededCapacity) { +// this.entries = Arrays.copyOf(this.entries, HashCommon.nextPowerOfTwo(neededCapacity + 1)); +// } +// +// @Override +// public T get(int id) { +// T[] entries = this.entries; +// +// T entry = null; +// if (id >= 0 && id < entries.length) { +// entry = entries[id]; +// } +// +// if (entry != null) { +// return entry; +// } else { +// throw new EntryMissingException(id); +// } +// } +// +// @Override +// public void readPacket(PacketByteBuf buf) { +// this.clear(); +// +// int entryCount = buf.readVarInt(); +// +// for (int i = 0; i < entryCount; ++i) { +// this.addEntry(this.idList.get(buf.readVarInt())); +// } +// } +// +// @Override +// public void writePacket(PacketByteBuf buf) { +// int size = this.size; +// buf.writeVarInt(size); +// +// for (int i = 0; i < size; ++i) { +// buf.writeVarInt(this.idList.getRawId(this.get(i))); +// } +// } +// +// @Override +// public int getPacketSize() { +// int size = VarInts.getSizeInBytes(this.size); +// +// for (int i = 0; i < this.size; ++i) { +// size += VarInts.getSizeInBytes(this.idList.getRawId(this.get(i))); +// } +// +// return size; +// } +// +// @Override +// public int getSize() { +// return this.size; +// } +// +// @Override +// public Palette copy() { +// return new LithiumHashPalette<>(this.idList, this.resizeHandler, this.indexBits, this.entries.clone(), new Reference2IntOpenHashMap<>(this.table), this.size); +// } +// +// private void clear() { +// Arrays.fill(this.entries, null); +// this.table.clear(); +// this.size = 0; +// } +// +// public List getElements() { +// ImmutableList.Builder builder = new ImmutableList.Builder<>(); +// for (T entry : this.entries) { +// if (entry != null) { +// builder.add(entry); +// } +// } +// return builder.build(); +// } +// +// public static Palette create(int bits, IndexedIterable idList, PaletteResizeListener listener, List list) { +// return new LithiumHashPalette<>(idList, bits, listener, list); +// } +//} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/collections/mob_spawning/SpawnSettingsMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/collections/mob_spawning/SpawnSettingsMixin.java new file mode 100644 index 0000000..54e6d58 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/collections/mob_spawning/SpawnSettingsMixin.java @@ -0,0 +1,36 @@ +package net.gensokyoreimagined.nitori.mixin.collections.mob_spawning; + +import com.google.common.collect.Maps; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.level.biome.MobSpawnSettings; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +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; + +import java.util.Map; + +@Mixin(MobSpawnSettings.class) +public class SpawnSettingsMixin { + @Mutable + @Shadow + @Final + private Map> spawners; + + + @Inject(method = "(FLjava/util/Map;Ljava/util/Map;)V", at = @At("RETURN")) + private void reinit(float creatureSpawnProbability, Map> spawners, Map, MobSpawnSettings.MobSpawnCost> spawnCosts, CallbackInfo ci) { + Map> spawns = Maps.newEnumMap(MobCategory.class); + + for (Map.Entry> entry : this.spawners.entrySet()) { + spawns.put(entry.getKey(), entry.getValue()); + } + + this.spawners = spawns; + } +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/BlockEntityMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/BlockEntityMixin.java new file mode 100644 index 0000000..c34d426 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/BlockEntityMixin.java @@ -0,0 +1,37 @@ +package net.gensokyoreimagined.nitori.mixin.world.block_entity_ticking.support_cache; + +import net.gensokyoreimagined.nitori.common.world.blockentity.SupportCache; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.core.BlockPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(BlockEntity.class) +public abstract class BlockEntityMixin implements SupportCache { + @Shadow + public abstract BlockEntityType getType(); + + @Unique + private boolean supportTestResult; + + @Inject(method = "(Lnet/minecraft/world/level/block/entity/BlockEntityType;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V", at = @At("RETURN")) + private void initSupportCache(BlockEntityType type, BlockPos pos, BlockState cachedState, CallbackInfo ci) { + this.supportTestResult = this.getType().isValid(cachedState); + } + + @Inject(method = "setBlockState", at = @At("RETURN")) + private void updateSupportCache(BlockState cachedState, CallbackInfo ci) { + this.supportTestResult = this.getType().isValid(cachedState); + } + + @Override + public boolean lithium$isSupported() { + return this.supportTestResult; + } +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/DirectBlockEntityTickInvokerMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/DirectBlockEntityTickInvokerMixin.java new file mode 100644 index 0000000..747b6f4 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/DirectBlockEntityTickInvokerMixin.java @@ -0,0 +1,53 @@ +package net.gensokyoreimagined.nitori.mixin.world.block_entity_ticking.support_cache; + +import net.gensokyoreimagined.nitori.common.world.blockentity.SupportCache; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.chunk.LevelChunk; +import org.spongepowered.asm.mixin.Final; +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.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; + +@Mixin(targets = "net.minecraft.world.level.chunk.LevelChunk$BoundTickingBlockEntity") +public class DirectBlockEntityTickInvokerMixin { + + @Shadow + @Final + private T blockEntity; + + @Redirect( + method = "tick", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/chunk/LevelChunk;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;" + ), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;push(Ljava/util/function/Supplier;)V"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BlockEntityTicker;tick(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/entity/BlockEntity;)V") + ) + ) + private BlockState getCachedState(LevelChunk chunk, BlockPos pos) { + return this.blockEntity.getBlockState(); + } + + @Redirect( + method = "tick()V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/block/entity/BlockEntityType;isValid(Lnet/minecraft/world/level/block/state/BlockState;)Z" + ), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;push(Ljava/util/function/Supplier;)V"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BlockEntityTicker;tick(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/entity/BlockEntity;)V") + ) + ) + private boolean cachedIsSupported(BlockEntityType blockEntityType, BlockState block) { + return ((SupportCache) this.blockEntity).lithium$isSupported(); + } + +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/WorldChunkMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/WorldChunkMixin.java new file mode 100644 index 0000000..528caf1 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/world/block_entity_ticking/support_cache/WorldChunkMixin.java @@ -0,0 +1,49 @@ +package net.gensokyoreimagined.nitori.mixin.world.block_entity_ticking.support_cache; + +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.chunk.LevelChunk; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + + +@Mixin(LevelChunk.class) +public abstract class WorldChunkMixin { + + @Shadow + public abstract BlockState getBlockState(BlockPos pos); + + @Redirect( + method = "setBlockState(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;ZZ)Lnet/minecraft/world/level/block/state/BlockState;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/block/EntityBlock;newBlockEntity(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/world/level/block/entity/BlockEntity;" + ) + ) + private BlockEntity createBlockEntityWithCachedStateFix(EntityBlock EntityBlock, BlockPos pos, BlockState state) { + return EntityBlock.newBlockEntity(pos, this.getBlockState(pos)); + } + + @Inject( + method = "setBlockState(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;ZZ)Lnet/minecraft/world/level/block/state/BlockState;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/block/entity/BlockEntity;setBlockState(Lnet/minecraft/world/level/block/state/BlockState;)V", + shift = At.Shift.AFTER + ) + ) + private void fixCachedState(BlockPos pos, BlockState state, boolean flag, boolean doPlace, CallbackInfoReturnable cir, @Local BlockEntity blockEntity) { + BlockState updatedBlockState = this.getBlockState(pos); + if (updatedBlockState != state) { + //noinspection deprecation + blockEntity.setBlockState(updatedBlockState); + } + } +} \ No newline at end of file diff --git a/src/main/resources/mixins.core.json b/src/main/resources/mixins.core.json index e219f15..98efe52 100755 --- a/src/main/resources/mixins.core.json +++ b/src/main/resources/mixins.core.json @@ -53,11 +53,15 @@ "collections.chunk_tickets.SortedArraySetMixin", "collections.block_entity_tickers.WorldChunkMixin", "collections.goals.GoalSelectorMixin", + "collections.mob_spawning.SpawnSettingsMixin", "world.block_entity_ticking.sleeping.WrappedBlockEntityTickInvokerAccessor", "world.block_entity_ticking.sleeping.campfire.CampfireBlockEntityMixin", "world.block_entity_ticking.sleeping.campfire.unlit.CampfireBlockEntityMixin", "world.block_entity_ticking.sleeping.campfire.lit.CampfireBlockEntityMixin", "world.block_entity_ticking.sleeping.furnace.AbstractFurnaceBlockEntityMixin", + "world.block_entity_ticking.support_cache.DirectBlockEntityTickInvokerMixin", + "world.block_entity_ticking.support_cache.BlockEntityMixin", + "world.block_entity_ticking.support_cache.WorldChunkMixin", "util.accessors.ClientEntityManagerAccessor", "util.accessors.EntityTrackingSectionAccessor", "util.accessors.ServerEntityManagerAccessor",