1.21 "works"
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
group=net.gensokyoreimagined.nitori
|
||||
version=1.4-SNAPSHOT
|
||||
version=1.5-SNAPSHOT
|
||||
description=Converting patches into mixins, for the Ignite Framework
|
||||
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
package net.gensokyoreimagined.nitori.access;
|
||||
|
||||
public interface IMixinChunkMapAccess {
|
||||
void gensouHacks$runOnTrackerMainThread(final Runnable runnable);
|
||||
}
|
||||
//public interface IMixinChunkMapAccess {
|
||||
// void gensouHacks$runOnTrackerMainThread(final Runnable runnable);
|
||||
//}
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
package net.gensokyoreimagined.nitori.access;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IMixinChunkMap_TrackedEntityAccess {
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
Entity getEntity();
|
||||
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
void callUpdatePlayers(List<ServerPlayer> players);
|
||||
}
|
||||
//import net.minecraft.server.level.ServerPlayer;
|
||||
//import net.minecraft.world.entity.Entity;
|
||||
//
|
||||
//import java.util.List;
|
||||
//
|
||||
//public interface IMixinChunkMap_TrackedEntityAccess {
|
||||
// @SuppressWarnings("EmptyMethod")
|
||||
// Entity getEntity();
|
||||
//
|
||||
// @SuppressWarnings("EmptyMethod")
|
||||
// void callUpdatePlayers(List<ServerPlayer> players);
|
||||
//}
|
||||
|
||||
@@ -5,27 +5,7 @@ import net.minecraft.world.entity.vehicle.ContainerEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
|
||||
|
||||
/**
|
||||
* Provides the ability for mods to allow Lithium's hopper optimizations to access their inventories' for item transfers.
|
||||
* This exists because Lithium's optimized hopper logic will only interact with inventories more efficiently than
|
||||
* vanilla if the stack list can be directly accessed and replaced with Lithium's custom stack list.
|
||||
* It is not required to implement this interface, but doing so will allow the mod's inventories to benefit from
|
||||
* Lithium's optimizations.
|
||||
* <p>
|
||||
* This interface should be implemented by your {@link net.minecraft.inventory.Inventory} or
|
||||
* {@link net.minecraft.inventory.SidedInventory} type to access the stack list.
|
||||
* <p>
|
||||
* An inventory must not extend {@link net.minecraft.block.entity.BlockEntity} if it has a supporting block that
|
||||
* implements {@link net.minecraft.block.InventoryProvider}.
|
||||
* <p>
|
||||
* The hopper interaction behavior of a LithiumInventory should only change if the content of the inventory
|
||||
* stack list also changes. For example, an inventory which only accepts an item if it already contains an item of the
|
||||
* same type would work fine (changing the acceptance condition only happens when changing the inventory contents here).
|
||||
* However, an inventory which accepts an item only if a certain block is near its position will need to signal this
|
||||
* change to hoppers by calling {@link LithiumNonNullList#changedInteractionConditions()}.
|
||||
*
|
||||
* @author 2No2Name
|
||||
*/
|
||||
|
||||
public interface LithiumInventory extends ContainerEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package net.gensokyoreimagined.nitori.common.block;
|
||||
|
||||
import net.gensokyoreimagined.nitori.common.entity.block_tracking.SectionedBlockChangeTracker;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public interface BlockListeningSection {
|
||||
|
||||
void lithium$addToCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker, long sectionPos, Level world);
|
||||
|
||||
void lithium$removeFromCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker);
|
||||
|
||||
void lithium$invalidateListeningSection(SectionPos sectionPos);
|
||||
}
|
||||
//import net.gensokyoreimagined.nitori.common.entity.block_tracking.SectionedBlockChangeTracker;
|
||||
//import net.minecraft.core.SectionPos;
|
||||
//import net.minecraft.world.level.Level;
|
||||
//
|
||||
//public interface BlockListeningSection {
|
||||
//
|
||||
// void lithium$addToCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker, long sectionPos, Level world);
|
||||
//
|
||||
// void lithium$removeFromCallback(ListeningBlockStatePredicate blockGroup, SectionedBlockChangeTracker tracker);
|
||||
//
|
||||
// void lithium$invalidateListeningSection(SectionPos sectionPos);
|
||||
//}
|
||||
@@ -1,104 +1,104 @@
|
||||
package net.gensokyoreimagined.nitori.common.entity.block_tracking;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
|
||||
import net.gensokyoreimagined.nitori.common.block.BlockListeningSection;
|
||||
import net.gensokyoreimagined.nitori.common.block.BlockStateFlags;
|
||||
import net.gensokyoreimagined.nitori.common.block.ListeningBlockStatePredicate;
|
||||
import net.gensokyoreimagined.nitori.common.util.Pos;
|
||||
import net.gensokyoreimagined.nitori.common.world.LithiumData;
|
||||
import net.gensokyoreimagined.nitori.common.world.chunk.ChunkStatusTracker;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class ChunkSectionChangeCallback {
|
||||
private final ArrayList<SectionedBlockChangeTracker>[] trackers;
|
||||
private short listeningMask;
|
||||
|
||||
static {
|
||||
if (BlockListeningSection.class.isAssignableFrom(LevelChunkSection.class)) {
|
||||
ChunkStatusTracker.registerUnloadCallback((serverWorld, chunkPos) -> {
|
||||
Long2ReferenceOpenHashMap<ChunkSectionChangeCallback> changeCallbacks = ((LithiumData) serverWorld).lithium$getData().chunkSectionChangeCallbacks();
|
||||
int x = chunkPos.x;
|
||||
int z = chunkPos.z;
|
||||
for (int y = Pos.SectionYCoord.getMinYSection(serverWorld); y <= Pos.SectionYCoord.getMaxYSectionInclusive(serverWorld); y++) {
|
||||
SectionPos chunkSectionPos = SectionPos.of(x, y, z);
|
||||
ChunkSectionChangeCallback chunkSectionChangeCallback = changeCallbacks.remove(chunkSectionPos.asLong());
|
||||
if (chunkSectionChangeCallback != null) {
|
||||
chunkSectionChangeCallback.onChunkSectionInvalidated(chunkSectionPos);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSectionChangeCallback() {
|
||||
//noinspection unchecked
|
||||
this.trackers = new ArrayList[BlockStateFlags.NUM_LISTENING_FLAGS];
|
||||
this.listeningMask = 0;
|
||||
}
|
||||
|
||||
public static ChunkSectionChangeCallback create(long sectionPos, Level world) {
|
||||
ChunkSectionChangeCallback chunkSectionChangeCallback = new ChunkSectionChangeCallback();
|
||||
Long2ReferenceOpenHashMap<ChunkSectionChangeCallback> changeCallbacks = ((LithiumData) world).lithium$getData().chunkSectionChangeCallbacks();
|
||||
ChunkSectionChangeCallback previous = changeCallbacks.put(sectionPos, chunkSectionChangeCallback);
|
||||
if (previous != null) {
|
||||
previous.onChunkSectionInvalidated(SectionPos.of(sectionPos));
|
||||
}
|
||||
return chunkSectionChangeCallback;
|
||||
}
|
||||
|
||||
public short onBlockChange(int blockGroupIndex, BlockListeningSection section) {
|
||||
ArrayList<SectionedBlockChangeTracker> sectionedBlockChangeTrackers = this.trackers[blockGroupIndex];
|
||||
this.trackers[blockGroupIndex] = null;
|
||||
if (sectionedBlockChangeTrackers != null) {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < sectionedBlockChangeTrackers.size(); i++) {
|
||||
sectionedBlockChangeTrackers.get(i).setChanged(section);
|
||||
}
|
||||
}
|
||||
this.listeningMask &= (short) ~(1 << blockGroupIndex);
|
||||
|
||||
return this.listeningMask;
|
||||
}
|
||||
|
||||
public short addTracker(SectionedBlockChangeTracker tracker, ListeningBlockStatePredicate blockGroup) {
|
||||
int blockGroupIndex = blockGroup.getIndex();
|
||||
ArrayList<SectionedBlockChangeTracker> sectionedBlockChangeTrackers = this.trackers[blockGroupIndex];
|
||||
if (sectionedBlockChangeTrackers == null) {
|
||||
this.trackers[blockGroupIndex] = (sectionedBlockChangeTrackers = new ArrayList<>());
|
||||
}
|
||||
sectionedBlockChangeTrackers.add(tracker);
|
||||
|
||||
this.listeningMask |= (short) (1 << blockGroupIndex);
|
||||
return this.listeningMask;
|
||||
}
|
||||
|
||||
public short removeTracker(SectionedBlockChangeTracker tracker, ListeningBlockStatePredicate blockGroup) {
|
||||
int blockGroupIndex = blockGroup.getIndex();
|
||||
ArrayList<SectionedBlockChangeTracker> sectionedBlockChangeTrackers = this.trackers[blockGroupIndex];
|
||||
if (sectionedBlockChangeTrackers != null) {
|
||||
sectionedBlockChangeTrackers.remove(tracker);
|
||||
if (sectionedBlockChangeTrackers.isEmpty()) {
|
||||
this.listeningMask &= (short) ~(1 << blockGroup.getIndex());
|
||||
}
|
||||
}
|
||||
return this.listeningMask;
|
||||
}
|
||||
|
||||
public void onChunkSectionInvalidated(SectionPos 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;
|
||||
}
|
||||
}
|
||||
//import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
|
||||
//import net.gensokyoreimagined.nitori.common.block.BlockListeningSection;
|
||||
//import net.gensokyoreimagined.nitori.common.block.BlockStateFlags;
|
||||
//import net.gensokyoreimagined.nitori.common.block.ListeningBlockStatePredicate;
|
||||
//import net.gensokyoreimagined.nitori.common.util.Pos;
|
||||
//import net.gensokyoreimagined.nitori.common.world.LithiumData;
|
||||
//import net.gensokyoreimagined.nitori.common.world.chunk.ChunkStatusTracker;
|
||||
//import net.minecraft.core.SectionPos;
|
||||
//import net.minecraft.world.level.Level;
|
||||
//import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//
|
||||
//public final class ChunkSectionChangeCallback {
|
||||
// private final ArrayList<SectionedBlockChangeTracker>[] trackers;
|
||||
// private short listeningMask;
|
||||
//
|
||||
// static {
|
||||
// if (BlockListeningSection.class.isAssignableFrom(LevelChunkSection.class)) {
|
||||
// ChunkStatusTracker.registerUnloadCallback((serverWorld, chunkPos) -> {
|
||||
// Long2ReferenceOpenHashMap<ChunkSectionChangeCallback> changeCallbacks = ((LithiumData) serverWorld).lithium$getData().chunkSectionChangeCallbacks();
|
||||
// int x = chunkPos.x;
|
||||
// int z = chunkPos.z;
|
||||
// for (int y = Pos.SectionYCoord.getMinYSection(serverWorld); y <= Pos.SectionYCoord.getMaxYSectionInclusive(serverWorld); y++) {
|
||||
// SectionPos chunkSectionPos = SectionPos.of(x, y, z);
|
||||
// ChunkSectionChangeCallback chunkSectionChangeCallback = changeCallbacks.remove(chunkSectionPos.asLong());
|
||||
// if (chunkSectionChangeCallback != null) {
|
||||
// chunkSectionChangeCallback.onChunkSectionInvalidated(chunkSectionPos);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public ChunkSectionChangeCallback() {
|
||||
// //noinspection unchecked
|
||||
// this.trackers = new ArrayList[BlockStateFlags.NUM_LISTENING_FLAGS];
|
||||
// this.listeningMask = 0;
|
||||
// }
|
||||
//
|
||||
// public static ChunkSectionChangeCallback create(long sectionPos, Level world) {
|
||||
// ChunkSectionChangeCallback chunkSectionChangeCallback = new ChunkSectionChangeCallback();
|
||||
// Long2ReferenceOpenHashMap<ChunkSectionChangeCallback> changeCallbacks = ((LithiumData) world).lithium$getData().chunkSectionChangeCallbacks();
|
||||
// ChunkSectionChangeCallback previous = changeCallbacks.put(sectionPos, chunkSectionChangeCallback);
|
||||
// if (previous != null) {
|
||||
// previous.onChunkSectionInvalidated(SectionPos.of(sectionPos));
|
||||
// }
|
||||
// return chunkSectionChangeCallback;
|
||||
// }
|
||||
//
|
||||
// public short onBlockChange(int blockGroupIndex, BlockListeningSection section) {
|
||||
// ArrayList<SectionedBlockChangeTracker> sectionedBlockChangeTrackers = this.trackers[blockGroupIndex];
|
||||
// this.trackers[blockGroupIndex] = null;
|
||||
// if (sectionedBlockChangeTrackers != null) {
|
||||
// //noinspection ForLoopReplaceableByForEach
|
||||
// for (int i = 0; i < sectionedBlockChangeTrackers.size(); i++) {
|
||||
// sectionedBlockChangeTrackers.get(i).setChanged(section);
|
||||
// }
|
||||
// }
|
||||
// this.listeningMask &= (short) ~(1 << blockGroupIndex);
|
||||
//
|
||||
// return this.listeningMask;
|
||||
// }
|
||||
//
|
||||
// public short addTracker(SectionedBlockChangeTracker tracker, ListeningBlockStatePredicate blockGroup) {
|
||||
// int blockGroupIndex = blockGroup.getIndex();
|
||||
// ArrayList<SectionedBlockChangeTracker> sectionedBlockChangeTrackers = this.trackers[blockGroupIndex];
|
||||
// if (sectionedBlockChangeTrackers == null) {
|
||||
// this.trackers[blockGroupIndex] = (sectionedBlockChangeTrackers = new ArrayList<>());
|
||||
// }
|
||||
// sectionedBlockChangeTrackers.add(tracker);
|
||||
//
|
||||
// this.listeningMask |= (short) (1 << blockGroupIndex);
|
||||
// return this.listeningMask;
|
||||
// }
|
||||
//
|
||||
// public short removeTracker(SectionedBlockChangeTracker tracker, ListeningBlockStatePredicate blockGroup) {
|
||||
// int blockGroupIndex = blockGroup.getIndex();
|
||||
// ArrayList<SectionedBlockChangeTracker> sectionedBlockChangeTrackers = this.trackers[blockGroupIndex];
|
||||
// if (sectionedBlockChangeTrackers != null) {
|
||||
// sectionedBlockChangeTrackers.remove(tracker);
|
||||
// if (sectionedBlockChangeTrackers.isEmpty()) {
|
||||
// this.listeningMask &= (short) ~(1 << blockGroup.getIndex());
|
||||
// }
|
||||
// }
|
||||
// return this.listeningMask;
|
||||
// }
|
||||
//
|
||||
// public void onChunkSectionInvalidated(SectionPos 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;
|
||||
// }
|
||||
//}
|
||||
@@ -1,211 +1,211 @@
|
||||
package net.gensokyoreimagined.nitori.common.entity.block_tracking;
|
||||
|
||||
import net.gensokyoreimagined.nitori.common.block.BlockListeningSection;
|
||||
import net.gensokyoreimagined.nitori.common.block.ListeningBlockStatePredicate;
|
||||
import net.gensokyoreimagined.nitori.common.util.Pos;
|
||||
import net.gensokyoreimagined.nitori.common.util.deduplication.LithiumInterner;
|
||||
import net.gensokyoreimagined.nitori.common.util.tuples.WorldSectionBox;
|
||||
import net.gensokyoreimagined.nitori.common.world.LithiumData;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
public class SectionedBlockChangeTracker {
|
||||
public final WorldSectionBox trackedWorldSections;
|
||||
public final ListeningBlockStatePredicate blockGroup;
|
||||
|
||||
private long maxChangeTime;
|
||||
|
||||
private int timesRegistered;
|
||||
//Some sections may not exist / be unloaded. We have to be aware of those. //TODO Invalidation when sections / chunks unload (but the entity does not (?), not sure whether this is possible)
|
||||
boolean isListeningToAll = false;
|
||||
private ArrayList<SectionPos> sectionsNotListeningTo = null;
|
||||
private ArrayList<BlockListeningSection> sectionsUnsubscribed = null;
|
||||
|
||||
public SectionedBlockChangeTracker(WorldSectionBox trackedWorldSections, ListeningBlockStatePredicate blockGroup) {
|
||||
this.trackedWorldSections = trackedWorldSections;
|
||||
this.blockGroup = blockGroup;
|
||||
|
||||
this.maxChangeTime = 0;
|
||||
}
|
||||
|
||||
public boolean matchesMovedBox(AABB box) {
|
||||
return this.trackedWorldSections.matchesRelevantBlocksBox(box);
|
||||
}
|
||||
|
||||
public static SectionedBlockChangeTracker registerAt(Level world, AABB entityBoundingBox, ListeningBlockStatePredicate blockGroup) {
|
||||
WorldSectionBox worldSectionBox = WorldSectionBox.relevantExpandedBlocksBox(world, entityBoundingBox);
|
||||
SectionedBlockChangeTracker tracker = new SectionedBlockChangeTracker(worldSectionBox, blockGroup);
|
||||
|
||||
LithiumInterner<SectionedBlockChangeTracker> blockChangeTrackers = ((LithiumData) world).lithium$getData().blockChangeTrackers();
|
||||
tracker = blockChangeTrackers.getCanonical(tracker);
|
||||
|
||||
tracker.register();
|
||||
return tracker;
|
||||
}
|
||||
|
||||
long getWorldTime() {
|
||||
return this.trackedWorldSections.world().getGameTime();
|
||||
}
|
||||
|
||||
public void register() {
|
||||
if (this.timesRegistered == 0) {
|
||||
WorldSectionBox trackedSections = this.trackedWorldSections;
|
||||
for (int x = trackedSections.chunkX1(); x < trackedSections.chunkX2(); x++) {
|
||||
for (int z = trackedSections.chunkZ1(); z < trackedSections.chunkZ2(); z++) {
|
||||
Level world = trackedSections.world();
|
||||
ChunkAccess chunk = world.getChunk(x, z, ChunkStatus.FULL, false);
|
||||
LevelChunkSection[] sectionArray = chunk == null ? null : chunk.getSections();
|
||||
for (int y = trackedSections.chunkY1(); y < trackedSections.chunkY2(); y++) {
|
||||
if (Pos.SectionYCoord.getMinYSection(world) > y || Pos.SectionYCoord.getMaxYSectionExclusive(world) <= y) {
|
||||
continue;
|
||||
}
|
||||
SectionPos sectionPos = SectionPos.of(x, y, z);
|
||||
if (sectionArray == null) {
|
||||
if (this.sectionsNotListeningTo == null) {
|
||||
this.sectionsNotListeningTo = new ArrayList<>();
|
||||
}
|
||||
this.sectionsNotListeningTo.add(sectionPos);
|
||||
continue;
|
||||
}
|
||||
LevelChunkSection section = sectionArray[Pos.SectionYIndex.fromSectionCoord(world, y)];
|
||||
|
||||
BlockListeningSection blockListeningSection = (BlockListeningSection) section;
|
||||
blockListeningSection.lithium$addToCallback(this.blockGroup, this, SectionPos.asLong(x, y, z), world);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isListeningToAll = (this.sectionsNotListeningTo == null || this.sectionsNotListeningTo.isEmpty())
|
||||
&& (this.sectionsUnsubscribed == null || this.sectionsUnsubscribed.isEmpty());
|
||||
this.setChanged(this.getWorldTime());
|
||||
}
|
||||
this.timesRegistered++;
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
if (--this.timesRegistered > 0) {
|
||||
return;
|
||||
}
|
||||
WorldSectionBox trackedSections = this.trackedWorldSections;
|
||||
Level world = trackedSections.world();
|
||||
for (int x = trackedSections.chunkX1(); x < trackedSections.chunkX2(); x++) {
|
||||
for (int z = trackedSections.chunkZ1(); z < trackedSections.chunkZ2(); z++) {
|
||||
ChunkAccess chunk = world.getChunk(x, z, ChunkStatus.FULL, false);
|
||||
LevelChunkSection[] sectionArray = chunk == null ? null : chunk.getSections();
|
||||
for (int y = trackedSections.chunkY1(); y < trackedSections.chunkY2(); y++) {
|
||||
|
||||
if (sectionArray == null) {
|
||||
continue;
|
||||
}
|
||||
if (Pos.SectionYCoord.getMinYSection(world) > y || Pos.SectionYCoord.getMaxYSectionExclusive(world) <= y) {
|
||||
continue;
|
||||
}
|
||||
LevelChunkSection section = sectionArray[Pos.SectionYIndex.fromSectionCoord(world, y)];
|
||||
|
||||
BlockListeningSection blockListeningSection = (BlockListeningSection) section;
|
||||
blockListeningSection.lithium$removeFromCallback(this.blockGroup, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.sectionsNotListeningTo = null;
|
||||
LithiumInterner<SectionedBlockChangeTracker> blockChangeTrackers = ((LithiumData) world).lithium$getData().blockChangeTrackers();
|
||||
blockChangeTrackers.deleteCanonical(this);
|
||||
}
|
||||
|
||||
public void listenToAllSections() {
|
||||
boolean changed = false;
|
||||
ArrayList<SectionPos> notListeningTo = this.sectionsNotListeningTo;
|
||||
if (notListeningTo != null) {
|
||||
for (int i = notListeningTo.size() - 1; i >= 0; i--) {
|
||||
changed = true;
|
||||
SectionPos chunkSectionPos = notListeningTo.get(i);
|
||||
Level world = this.trackedWorldSections.world();
|
||||
ChunkAccess chunk = world.getChunk(chunkSectionPos.getX(), chunkSectionPos.getZ(), ChunkStatus.FULL, false);
|
||||
if (chunk != null) {
|
||||
notListeningTo.remove(i);
|
||||
} else {
|
||||
//Chunk not loaded, cannot listen to all sections.
|
||||
return;
|
||||
}
|
||||
LevelChunkSection section = chunk.getSections()[Pos.SectionYIndex.fromSectionCoord(world, chunkSectionPos.getY())];
|
||||
BlockListeningSection blockListeningSection = (BlockListeningSection) section;
|
||||
blockListeningSection.lithium$addToCallback(this.blockGroup, this, chunkSectionPos.asLong(), world);
|
||||
}
|
||||
}
|
||||
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.lithium$addToCallback(this.blockGroup, this, Long.MIN_VALUE, null);
|
||||
}
|
||||
}
|
||||
this.isListeningToAll = true;
|
||||
if (changed) {
|
||||
this.setChanged(this.getWorldTime());
|
||||
}
|
||||
}
|
||||
|
||||
public void setChanged(BlockListeningSection section) {
|
||||
if (this.sectionsUnsubscribed == null) {
|
||||
this.sectionsUnsubscribed = new ArrayList<>();
|
||||
}
|
||||
this.sectionsUnsubscribed.add(section);
|
||||
this.setChanged(this.getWorldTime());
|
||||
this.isListeningToAll = false;
|
||||
}
|
||||
|
||||
public void setChanged(long atTime) {
|
||||
if (atTime > this.maxChangeTime) {
|
||||
this.maxChangeTime = atTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to quickly check whether any relevant blocks changed inside the relevant chunk sections after
|
||||
* the last test.
|
||||
*
|
||||
* @param lastCheckedTime time of the last interaction attempt
|
||||
* @return whether any relevant entity moved in the tracked area
|
||||
*/
|
||||
public boolean isUnchangedSince(long lastCheckedTime) {
|
||||
if (lastCheckedTime <= this.maxChangeTime) {
|
||||
return false;
|
||||
}
|
||||
if (!this.isListeningToAll) {
|
||||
this.listenToAllSections();
|
||||
return this.isListeningToAll && lastCheckedTime > this.maxChangeTime;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//Do not modify, used for deduplication of instances
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (SectionedBlockChangeTracker) obj;
|
||||
return Objects.equals(this.trackedWorldSections, that.trackedWorldSections) &&
|
||||
Objects.equals(this.blockGroup, that.blockGroup);
|
||||
}
|
||||
//Do not modify, used for deduplication of instances
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.getClass().hashCode() ^ this.trackedWorldSections.hashCode() ^ this.blockGroup.hashCode();
|
||||
}
|
||||
|
||||
public void onChunkSectionInvalidated(SectionPos sectionPos) {
|
||||
if (this.sectionsNotListeningTo == null) {
|
||||
this.sectionsNotListeningTo = new ArrayList<>();
|
||||
}
|
||||
this.sectionsNotListeningTo.add(sectionPos);
|
||||
this.setChanged(this.getWorldTime());
|
||||
this.isListeningToAll = false;
|
||||
}
|
||||
}
|
||||
//import net.gensokyoreimagined.nitori.common.block.BlockListeningSection;
|
||||
//import net.gensokyoreimagined.nitori.common.block.ListeningBlockStatePredicate;
|
||||
//import net.gensokyoreimagined.nitori.common.util.Pos;
|
||||
//import net.gensokyoreimagined.nitori.common.util.deduplication.LithiumInterner;
|
||||
//import net.gensokyoreimagined.nitori.common.util.tuples.WorldSectionBox;
|
||||
//import net.gensokyoreimagined.nitori.common.world.LithiumData;
|
||||
//import net.minecraft.world.phys.AABB;
|
||||
//import net.minecraft.core.SectionPos;
|
||||
//import net.minecraft.world.level.Level;
|
||||
//import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
//import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
//import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Objects;
|
||||
//
|
||||
//public class SectionedBlockChangeTracker {
|
||||
// public final WorldSectionBox trackedWorldSections;
|
||||
// public final ListeningBlockStatePredicate blockGroup;
|
||||
//
|
||||
// private long maxChangeTime;
|
||||
//
|
||||
// private int timesRegistered;
|
||||
// //Some sections may not exist / be unloaded. We have to be aware of those. //TODO Invalidation when sections / chunks unload (but the entity does not (?), not sure whether this is possible)
|
||||
// boolean isListeningToAll = false;
|
||||
// private ArrayList<SectionPos> sectionsNotListeningTo = null;
|
||||
// private ArrayList<BlockListeningSection> sectionsUnsubscribed = null;
|
||||
//
|
||||
// public SectionedBlockChangeTracker(WorldSectionBox trackedWorldSections, ListeningBlockStatePredicate blockGroup) {
|
||||
// this.trackedWorldSections = trackedWorldSections;
|
||||
// this.blockGroup = blockGroup;
|
||||
//
|
||||
// this.maxChangeTime = 0;
|
||||
// }
|
||||
//
|
||||
// public boolean matchesMovedBox(AABB box) {
|
||||
// return this.trackedWorldSections.matchesRelevantBlocksBox(box);
|
||||
// }
|
||||
//
|
||||
// public static SectionedBlockChangeTracker registerAt(Level world, AABB entityBoundingBox, ListeningBlockStatePredicate blockGroup) {
|
||||
// WorldSectionBox worldSectionBox = WorldSectionBox.relevantExpandedBlocksBox(world, entityBoundingBox);
|
||||
// SectionedBlockChangeTracker tracker = new SectionedBlockChangeTracker(worldSectionBox, blockGroup);
|
||||
//
|
||||
// LithiumInterner<SectionedBlockChangeTracker> blockChangeTrackers = ((LithiumData) world).lithium$getData().blockChangeTrackers();
|
||||
// tracker = blockChangeTrackers.getCanonical(tracker);
|
||||
//
|
||||
// tracker.register();
|
||||
// return tracker;
|
||||
// }
|
||||
//
|
||||
// long getWorldTime() {
|
||||
// return this.trackedWorldSections.world().getGameTime();
|
||||
// }
|
||||
//
|
||||
// public void register() {
|
||||
// if (this.timesRegistered == 0) {
|
||||
// WorldSectionBox trackedSections = this.trackedWorldSections;
|
||||
// for (int x = trackedSections.chunkX1(); x < trackedSections.chunkX2(); x++) {
|
||||
// for (int z = trackedSections.chunkZ1(); z < trackedSections.chunkZ2(); z++) {
|
||||
// Level world = trackedSections.world();
|
||||
// ChunkAccess chunk = world.getChunk(x, z, ChunkStatus.FULL, false);
|
||||
// LevelChunkSection[] sectionArray = chunk == null ? null : chunk.getSections();
|
||||
// for (int y = trackedSections.chunkY1(); y < trackedSections.chunkY2(); y++) {
|
||||
// if (Pos.SectionYCoord.getMinYSection(world) > y || Pos.SectionYCoord.getMaxYSectionExclusive(world) <= y) {
|
||||
// continue;
|
||||
// }
|
||||
// SectionPos sectionPos = SectionPos.of(x, y, z);
|
||||
// if (sectionArray == null) {
|
||||
// if (this.sectionsNotListeningTo == null) {
|
||||
// this.sectionsNotListeningTo = new ArrayList<>();
|
||||
// }
|
||||
// this.sectionsNotListeningTo.add(sectionPos);
|
||||
// continue;
|
||||
// }
|
||||
// LevelChunkSection section = sectionArray[Pos.SectionYIndex.fromSectionCoord(world, y)];
|
||||
//
|
||||
// BlockListeningSection blockListeningSection = (BlockListeningSection) section;
|
||||
// blockListeningSection.lithium$addToCallback(this.blockGroup, this, SectionPos.asLong(x, y, z), world);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// this.isListeningToAll = (this.sectionsNotListeningTo == null || this.sectionsNotListeningTo.isEmpty())
|
||||
// && (this.sectionsUnsubscribed == null || this.sectionsUnsubscribed.isEmpty());
|
||||
// this.setChanged(this.getWorldTime());
|
||||
// }
|
||||
// this.timesRegistered++;
|
||||
// }
|
||||
//
|
||||
// public void unregister() {
|
||||
// if (--this.timesRegistered > 0) {
|
||||
// return;
|
||||
// }
|
||||
// WorldSectionBox trackedSections = this.trackedWorldSections;
|
||||
// Level world = trackedSections.world();
|
||||
// for (int x = trackedSections.chunkX1(); x < trackedSections.chunkX2(); x++) {
|
||||
// for (int z = trackedSections.chunkZ1(); z < trackedSections.chunkZ2(); z++) {
|
||||
// ChunkAccess chunk = world.getChunk(x, z, ChunkStatus.FULL, false);
|
||||
// LevelChunkSection[] sectionArray = chunk == null ? null : chunk.getSections();
|
||||
// for (int y = trackedSections.chunkY1(); y < trackedSections.chunkY2(); y++) {
|
||||
//
|
||||
// if (sectionArray == null) {
|
||||
// continue;
|
||||
// }
|
||||
// if (Pos.SectionYCoord.getMinYSection(world) > y || Pos.SectionYCoord.getMaxYSectionExclusive(world) <= y) {
|
||||
// continue;
|
||||
// }
|
||||
// LevelChunkSection section = sectionArray[Pos.SectionYIndex.fromSectionCoord(world, y)];
|
||||
//
|
||||
// BlockListeningSection blockListeningSection = (BlockListeningSection) section;
|
||||
// blockListeningSection.lithium$removeFromCallback(this.blockGroup, this);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// this.sectionsNotListeningTo = null;
|
||||
// LithiumInterner<SectionedBlockChangeTracker> blockChangeTrackers = ((LithiumData) world).lithium$getData().blockChangeTrackers();
|
||||
// blockChangeTrackers.deleteCanonical(this);
|
||||
// }
|
||||
//
|
||||
// public void listenToAllSections() {
|
||||
// boolean changed = false;
|
||||
// ArrayList<SectionPos> notListeningTo = this.sectionsNotListeningTo;
|
||||
// if (notListeningTo != null) {
|
||||
// for (int i = notListeningTo.size() - 1; i >= 0; i--) {
|
||||
// changed = true;
|
||||
// SectionPos chunkSectionPos = notListeningTo.get(i);
|
||||
// Level world = this.trackedWorldSections.world();
|
||||
// ChunkAccess chunk = world.getChunk(chunkSectionPos.getX(), chunkSectionPos.getZ(), ChunkStatus.FULL, false);
|
||||
// if (chunk != null) {
|
||||
// notListeningTo.remove(i);
|
||||
// } else {
|
||||
// //Chunk not loaded, cannot listen to all sections.
|
||||
// return;
|
||||
// }
|
||||
// LevelChunkSection section = chunk.getSections()[Pos.SectionYIndex.fromSectionCoord(world, chunkSectionPos.getY())];
|
||||
// BlockListeningSection blockListeningSection = (BlockListeningSection) section;
|
||||
// blockListeningSection.lithium$addToCallback(this.blockGroup, this, chunkSectionPos.asLong(), world);
|
||||
// }
|
||||
// }
|
||||
// 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.lithium$addToCallback(this.blockGroup, this, Long.MIN_VALUE, null);
|
||||
// }
|
||||
// }
|
||||
// this.isListeningToAll = true;
|
||||
// if (changed) {
|
||||
// this.setChanged(this.getWorldTime());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void setChanged(BlockListeningSection section) {
|
||||
// if (this.sectionsUnsubscribed == null) {
|
||||
// this.sectionsUnsubscribed = new ArrayList<>();
|
||||
// }
|
||||
// this.sectionsUnsubscribed.add(section);
|
||||
// this.setChanged(this.getWorldTime());
|
||||
// this.isListeningToAll = false;
|
||||
// }
|
||||
//
|
||||
// public void setChanged(long atTime) {
|
||||
// if (atTime > this.maxChangeTime) {
|
||||
// this.maxChangeTime = atTime;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Method to quickly check whether any relevant blocks changed inside the relevant chunk sections after
|
||||
// * the last test.
|
||||
// *
|
||||
// * @param lastCheckedTime time of the last interaction attempt
|
||||
// * @return whether any relevant entity moved in the tracked area
|
||||
// */
|
||||
// public boolean isUnchangedSince(long lastCheckedTime) {
|
||||
// if (lastCheckedTime <= this.maxChangeTime) {
|
||||
// return false;
|
||||
// }
|
||||
// if (!this.isListeningToAll) {
|
||||
// this.listenToAllSections();
|
||||
// return this.isListeningToAll && lastCheckedTime > this.maxChangeTime;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// //Do not modify, used for deduplication of instances
|
||||
// @Override
|
||||
// public boolean equals(Object obj) {
|
||||
// if (obj == this) return true;
|
||||
// if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
// var that = (SectionedBlockChangeTracker) obj;
|
||||
// return Objects.equals(this.trackedWorldSections, that.trackedWorldSections) &&
|
||||
// Objects.equals(this.blockGroup, that.blockGroup);
|
||||
// }
|
||||
// //Do not modify, used for deduplication of instances
|
||||
// @Override
|
||||
// public int hashCode() {
|
||||
// return this.getClass().hashCode() ^ this.trackedWorldSections.hashCode() ^ this.blockGroup.hashCode();
|
||||
// }
|
||||
//
|
||||
// public void onChunkSectionInvalidated(SectionPos sectionPos) {
|
||||
// if (this.sectionsNotListeningTo == null) {
|
||||
// this.sectionsNotListeningTo = new ArrayList<>();
|
||||
// }
|
||||
// this.sectionsNotListeningTo.add(sectionPos);
|
||||
// this.setChanged(this.getWorldTime());
|
||||
// this.isListeningToAll = false;
|
||||
// }
|
||||
//}
|
||||
@@ -1,18 +1,18 @@
|
||||
package net.gensokyoreimagined.nitori.common.entity.movement_tracker;
|
||||
|
||||
import net.minecraft.world.level.entity.EntityAccess;
|
||||
import net.minecraft.world.level.entity.EntitySectionStorage;
|
||||
|
||||
public interface EntityMovementTrackerSection {
|
||||
void lithium$addListener(SectionedEntityMovementTracker<?, ?> listener);
|
||||
|
||||
void lithium$removeListener(EntitySectionStorage<?> sectionedEntityCache, SectionedEntityMovementTracker<?, ?> listener);
|
||||
|
||||
void lithium$trackEntityMovement(int notificationMask, long time);
|
||||
|
||||
long lithium$getChangeTime(int trackedClass);
|
||||
|
||||
<S, E extends EntityAccess> void lithium$listenToMovementOnce(SectionedEntityMovementTracker<E, S> listener, int trackedClass);
|
||||
|
||||
<S, E extends EntityAccess> void lithium$removeListenToMovementOnce(SectionedEntityMovementTracker<E, S> listener, int trackedClass);
|
||||
}
|
||||
//import net.minecraft.world.level.entity.EntityAccess;
|
||||
//import net.minecraft.world.level.entity.EntitySectionStorage;
|
||||
//
|
||||
//public interface EntityMovementTrackerSection {
|
||||
// void lithium$addListener(SectionedEntityMovementTracker<?, ?> listener);
|
||||
//
|
||||
// void lithium$removeListener(EntitySectionStorage<?> sectionedEntityCache, SectionedEntityMovementTracker<?, ?> listener);
|
||||
//
|
||||
// void lithium$trackEntityMovement(int notificationMask, long time);
|
||||
//
|
||||
// long lithium$getChangeTime(int trackedClass);
|
||||
//
|
||||
// <S, E extends EntityAccess> void lithium$listenToMovementOnce(SectionedEntityMovementTracker<E, S> listener, int trackedClass);
|
||||
//
|
||||
// <S, E extends EntityAccess> void lithium$removeListenToMovementOnce(SectionedEntityMovementTracker<E, S> listener, int trackedClass);
|
||||
//}
|
||||
|
||||
@@ -1,197 +1,197 @@
|
||||
package net.gensokyoreimagined.nitori.common.entity.movement_tracker;
|
||||
|
||||
import it.unimi.dsi.fastutil.HashCommon;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
import net.gensokyoreimagined.nitori.common.util.tuples.WorldSectionBox;
|
||||
import net.gensokyoreimagined.nitori.common.world.LithiumData;
|
||||
import net.gensokyoreimagined.nitori.mixin.util.accessors.ServerEntityManagerAccessor;
|
||||
import net.gensokyoreimagined.nitori.mixin.util.accessors.ServerWorldAccessor;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.entity.EntityAccess;
|
||||
import net.minecraft.world.level.entity.EntitySection;
|
||||
import net.minecraft.world.level.entity.EntitySectionStorage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class SectionedEntityMovementTracker<E extends EntityAccess, S> {
|
||||
final WorldSectionBox trackedWorldSections;
|
||||
final Class<S> clazz;
|
||||
private final int trackedClass;
|
||||
ArrayList<EntitySection<E>> sortedSections;
|
||||
boolean[] sectionVisible;
|
||||
private int timesRegistered;
|
||||
private final ArrayList<EntityMovementTrackerSection> sectionsNotListeningTo;
|
||||
|
||||
private long maxChangeTime;
|
||||
|
||||
private ReferenceOpenHashSet<SectionedEntityMovementListener> sectionedEntityMovementListeners;
|
||||
|
||||
public SectionedEntityMovementTracker(WorldSectionBox interactionChunks, Class<S> clazz) {
|
||||
this.clazz = clazz;
|
||||
this.trackedWorldSections = interactionChunks;
|
||||
this.trackedClass = MovementTrackerHelper.MOVEMENT_NOTIFYING_ENTITY_CLASSES.indexOf(clazz);
|
||||
assert this.trackedClass != -1;
|
||||
this.sectionedEntityMovementListeners = null;
|
||||
this.sectionsNotListeningTo = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCommon.mix(this.trackedWorldSections.hashCode()) ^ HashCommon.mix(this.trackedClass) ^ this.getClass().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj.getClass() == this.getClass() &&
|
||||
this.clazz == ((SectionedEntityMovementTracker<?, ?>) obj).clazz &&
|
||||
this.trackedWorldSections.equals(((SectionedEntityMovementTracker<?, ?>) obj).trackedWorldSections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to quickly check whether any relevant entities moved inside the relevant entity sections after
|
||||
* the last interaction attempt.
|
||||
*
|
||||
* @param lastCheckedTime time of the last interaction attempt
|
||||
* @return whether any relevant entity moved in the tracked area
|
||||
*/
|
||||
public boolean isUnchangedSince(long lastCheckedTime) {
|
||||
if (lastCheckedTime <= this.maxChangeTime) {
|
||||
return false;
|
||||
}
|
||||
if (!this.sectionsNotListeningTo.isEmpty()) {
|
||||
this.setChanged(this.listenToAllSectionsAndGetMaxChangeTime());
|
||||
return lastCheckedTime > this.maxChangeTime;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private long listenToAllSectionsAndGetMaxChangeTime() {
|
||||
long maxChangeTime = Long.MIN_VALUE;
|
||||
ArrayList<EntityMovementTrackerSection> notListeningTo = this.sectionsNotListeningTo;
|
||||
for (int i = notListeningTo.size() - 1; i >= 0; i--) {
|
||||
EntityMovementTrackerSection entityMovementTrackerSection = notListeningTo.remove(i);
|
||||
entityMovementTrackerSection.lithium$listenToMovementOnce(this, this.trackedClass);
|
||||
maxChangeTime = Math.max(maxChangeTime, entityMovementTrackerSection.lithium$getChangeTime(this.trackedClass));
|
||||
}
|
||||
return maxChangeTime;
|
||||
}
|
||||
|
||||
public void register(ServerLevel world) {
|
||||
assert world == this.trackedWorldSections.world();
|
||||
|
||||
if (this.timesRegistered == 0) {
|
||||
//noinspection unchecked
|
||||
EntitySectionStorage<E> cache = ((ServerEntityManagerAccessor<E>) ((ServerWorldAccessor) world).getEntityManager()).getSectionStorage();
|
||||
|
||||
WorldSectionBox trackedSections = this.trackedWorldSections;
|
||||
int size = trackedSections.numSections();
|
||||
assert size > 0;
|
||||
this.sortedSections = new ArrayList<>(size);
|
||||
this.sectionVisible = new boolean[size];
|
||||
|
||||
//vanilla iteration order in EntitySectionStorage is xzy
|
||||
//WorldSectionBox upper coordinates are exclusive
|
||||
for (int x = trackedSections.chunkX1(); x < trackedSections.chunkX2(); x++) {
|
||||
for (int z = trackedSections.chunkZ1(); z < trackedSections.chunkZ2(); z++) {
|
||||
for (int y = trackedSections.chunkY1(); y < trackedSections.chunkY2(); y++) {
|
||||
EntitySection<E> section = cache.getSection(SectionPos.asLong(x, y, z));
|
||||
EntityMovementTrackerSection sectionAccess = (EntityMovementTrackerSection) section;
|
||||
this.sortedSections.add(section);
|
||||
sectionAccess.lithium$addListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setChanged(world.getGameTime());
|
||||
}
|
||||
|
||||
this.timesRegistered++;
|
||||
}
|
||||
|
||||
public void unRegister(Level world) {
|
||||
assert world == this.trackedWorldSections.world();
|
||||
if (--this.timesRegistered > 0) {
|
||||
return;
|
||||
}
|
||||
assert this.timesRegistered == 0;
|
||||
//noinspection unchecked
|
||||
EntitySectionStorage<E> cache = ((ServerEntityManagerAccessor<E>) ((ServerWorldAccessor) world).getEntityManager()).getSectionStorage();
|
||||
((LithiumData) world).lithium$getData().entityMovementTrackers().deleteCanonical(this);
|
||||
|
||||
ArrayList<EntitySection<E>> sections = this.sortedSections;
|
||||
for (int i = sections.size() - 1; i >= 0; i--) {
|
||||
EntitySection<E> section = sections.get(i);
|
||||
EntityMovementTrackerSection sectionAccess = (EntityMovementTrackerSection) section;
|
||||
sectionAccess.lithium$removeListener(cache, this);
|
||||
if (!this.sectionsNotListeningTo.remove(section)) {
|
||||
((EntityMovementTrackerSection) section).lithium$removeListenToMovementOnce(this, this.trackedClass);
|
||||
}
|
||||
}
|
||||
this.setChanged(world.getGameTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an entity section to this listener, so this listener can look for changes in the section.
|
||||
*/
|
||||
public void onSectionEnteredRange(EntityMovementTrackerSection section) {
|
||||
this.setChanged(this.trackedWorldSections.world().getGameTime());
|
||||
//noinspection SuspiciousMethodCalls
|
||||
int sectionIndex = this.sortedSections.lastIndexOf(section);
|
||||
this.sectionVisible[sectionIndex] = true;
|
||||
|
||||
this.sectionsNotListeningTo.add(section);
|
||||
this.notifyAllListeners();
|
||||
}
|
||||
|
||||
public void onSectionLeftRange(EntityMovementTrackerSection section) {
|
||||
this.setChanged(this.trackedWorldSections.world().getGameTime());
|
||||
//noinspection SuspiciousMethodCalls
|
||||
int sectionIndex = this.sortedSections.lastIndexOf(section);
|
||||
|
||||
this.sectionVisible[sectionIndex] = false;
|
||||
|
||||
if (!this.sectionsNotListeningTo.remove(section)) {
|
||||
section.lithium$removeListenToMovementOnce(this, this.trackedClass);
|
||||
this.notifyAllListeners();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that marks that new entities might have appeared or moved in the tracked chunk sections.
|
||||
*/
|
||||
private void setChanged(long atTime) {
|
||||
if (atTime > this.maxChangeTime) {
|
||||
this.maxChangeTime = atTime;
|
||||
}
|
||||
}
|
||||
|
||||
public void listenToEntityMovementOnce(SectionedEntityMovementListener listener) {
|
||||
if (this.sectionedEntityMovementListeners == null) {
|
||||
this.sectionedEntityMovementListeners = new ReferenceOpenHashSet<>();
|
||||
}
|
||||
this.sectionedEntityMovementListeners.add(listener);
|
||||
|
||||
if (!this.sectionsNotListeningTo.isEmpty()) {
|
||||
this.setChanged(this.listenToAllSectionsAndGetMaxChangeTime());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void emitEntityMovement(int classMask, EntityMovementTrackerSection section) {
|
||||
if ((classMask & (1 << this.trackedClass)) != 0) {
|
||||
this.notifyAllListeners();
|
||||
this.sectionsNotListeningTo.add(section);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyAllListeners() {
|
||||
ReferenceOpenHashSet<SectionedEntityMovementListener> listeners = this.sectionedEntityMovementListeners;
|
||||
if (listeners != null && !listeners.isEmpty()) {
|
||||
for (SectionedEntityMovementListener listener : listeners) {
|
||||
listener.lithium$handleEntityMovement(this.clazz);
|
||||
}
|
||||
listeners.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
//import it.unimi.dsi.fastutil.HashCommon;
|
||||
//import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
//import net.gensokyoreimagined.nitori.common.util.tuples.WorldSectionBox;
|
||||
//import net.gensokyoreimagined.nitori.common.world.LithiumData;
|
||||
//import net.gensokyoreimagined.nitori.mixin.util.accessors.ServerEntityManagerAccessor;
|
||||
//import net.gensokyoreimagined.nitori.mixin.util.accessors.ServerWorldAccessor;
|
||||
//import net.minecraft.server.level.ServerLevel;
|
||||
//import net.minecraft.core.SectionPos;
|
||||
//import net.minecraft.world.level.Level;
|
||||
//import net.minecraft.world.level.entity.EntityAccess;
|
||||
//import net.minecraft.world.level.entity.EntitySection;
|
||||
//import net.minecraft.world.level.entity.EntitySectionStorage;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//
|
||||
//public abstract class SectionedEntityMovementTracker<E extends EntityAccess, S> {
|
||||
// final WorldSectionBox trackedWorldSections;
|
||||
// final Class<S> clazz;
|
||||
// private final int trackedClass;
|
||||
// ArrayList<EntitySection<E>> sortedSections;
|
||||
// boolean[] sectionVisible;
|
||||
// private int timesRegistered;
|
||||
// private final ArrayList<EntityMovementTrackerSection> sectionsNotListeningTo;
|
||||
//
|
||||
// private long maxChangeTime;
|
||||
//
|
||||
// private ReferenceOpenHashSet<SectionedEntityMovementListener> sectionedEntityMovementListeners;
|
||||
//
|
||||
// public SectionedEntityMovementTracker(WorldSectionBox interactionChunks, Class<S> clazz) {
|
||||
// this.clazz = clazz;
|
||||
// this.trackedWorldSections = interactionChunks;
|
||||
// this.trackedClass = MovementTrackerHelper.MOVEMENT_NOTIFYING_ENTITY_CLASSES.indexOf(clazz);
|
||||
// assert this.trackedClass != -1;
|
||||
// this.sectionedEntityMovementListeners = null;
|
||||
// this.sectionsNotListeningTo = new ArrayList<>();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int hashCode() {
|
||||
// return HashCommon.mix(this.trackedWorldSections.hashCode()) ^ HashCommon.mix(this.trackedClass) ^ this.getClass().hashCode();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean equals(Object obj) {
|
||||
// return obj.getClass() == this.getClass() &&
|
||||
// this.clazz == ((SectionedEntityMovementTracker<?, ?>) obj).clazz &&
|
||||
// this.trackedWorldSections.equals(((SectionedEntityMovementTracker<?, ?>) obj).trackedWorldSections);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Method to quickly check whether any relevant entities moved inside the relevant entity sections after
|
||||
// * the last interaction attempt.
|
||||
// *
|
||||
// * @param lastCheckedTime time of the last interaction attempt
|
||||
// * @return whether any relevant entity moved in the tracked area
|
||||
// */
|
||||
// public boolean isUnchangedSince(long lastCheckedTime) {
|
||||
// if (lastCheckedTime <= this.maxChangeTime) {
|
||||
// return false;
|
||||
// }
|
||||
// if (!this.sectionsNotListeningTo.isEmpty()) {
|
||||
// this.setChanged(this.listenToAllSectionsAndGetMaxChangeTime());
|
||||
// return lastCheckedTime > this.maxChangeTime;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// private long listenToAllSectionsAndGetMaxChangeTime() {
|
||||
// long maxChangeTime = Long.MIN_VALUE;
|
||||
// ArrayList<EntityMovementTrackerSection> notListeningTo = this.sectionsNotListeningTo;
|
||||
// for (int i = notListeningTo.size() - 1; i >= 0; i--) {
|
||||
// EntityMovementTrackerSection entityMovementTrackerSection = notListeningTo.remove(i);
|
||||
// entityMovementTrackerSection.lithium$listenToMovementOnce(this, this.trackedClass);
|
||||
// maxChangeTime = Math.max(maxChangeTime, entityMovementTrackerSection.lithium$getChangeTime(this.trackedClass));
|
||||
// }
|
||||
// return maxChangeTime;
|
||||
// }
|
||||
//
|
||||
// public void register(ServerLevel world) {
|
||||
// assert world == this.trackedWorldSections.world();
|
||||
//
|
||||
// if (this.timesRegistered == 0) {
|
||||
// //noinspection unchecked
|
||||
// EntitySectionStorage<E> cache = ((ServerEntityManagerAccessor<E>) ((ServerWorldAccessor) world).getEntityManager()).getSectionStorage();
|
||||
//
|
||||
// WorldSectionBox trackedSections = this.trackedWorldSections;
|
||||
// int size = trackedSections.numSections();
|
||||
// assert size > 0;
|
||||
// this.sortedSections = new ArrayList<>(size);
|
||||
// this.sectionVisible = new boolean[size];
|
||||
//
|
||||
// //vanilla iteration order in EntitySectionStorage is xzy
|
||||
// //WorldSectionBox upper coordinates are exclusive
|
||||
// for (int x = trackedSections.chunkX1(); x < trackedSections.chunkX2(); x++) {
|
||||
// for (int z = trackedSections.chunkZ1(); z < trackedSections.chunkZ2(); z++) {
|
||||
// for (int y = trackedSections.chunkY1(); y < trackedSections.chunkY2(); y++) {
|
||||
// EntitySection<E> section = cache.getSection(SectionPos.asLong(x, y, z));
|
||||
// EntityMovementTrackerSection sectionAccess = (EntityMovementTrackerSection) section;
|
||||
// this.sortedSections.add(section);
|
||||
// sectionAccess.lithium$addListener(this);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// this.setChanged(world.getGameTime());
|
||||
// }
|
||||
//
|
||||
// this.timesRegistered++;
|
||||
// }
|
||||
//
|
||||
// public void unRegister(Level world) {
|
||||
// assert world == this.trackedWorldSections.world();
|
||||
// if (--this.timesRegistered > 0) {
|
||||
// return;
|
||||
// }
|
||||
// assert this.timesRegistered == 0;
|
||||
// //noinspection unchecked
|
||||
// EntitySectionStorage<E> cache = ((ServerEntityManagerAccessor<E>) ((ServerWorldAccessor) world).getEntityManager()).getSectionStorage();
|
||||
// ((LithiumData) world).lithium$getData().entityMovementTrackers().deleteCanonical(this);
|
||||
//
|
||||
// ArrayList<EntitySection<E>> sections = this.sortedSections;
|
||||
// for (int i = sections.size() - 1; i >= 0; i--) {
|
||||
// EntitySection<E> section = sections.get(i);
|
||||
// EntityMovementTrackerSection sectionAccess = (EntityMovementTrackerSection) section;
|
||||
// sectionAccess.lithium$removeListener(cache, this);
|
||||
// if (!this.sectionsNotListeningTo.remove(section)) {
|
||||
// ((EntityMovementTrackerSection) section).lithium$removeListenToMovementOnce(this, this.trackedClass);
|
||||
// }
|
||||
// }
|
||||
// this.setChanged(world.getGameTime());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Register an entity section to this listener, so this listener can look for changes in the section.
|
||||
// */
|
||||
// public void onSectionEnteredRange(EntityMovementTrackerSection section) {
|
||||
// this.setChanged(this.trackedWorldSections.world().getGameTime());
|
||||
// //noinspection SuspiciousMethodCalls
|
||||
// int sectionIndex = this.sortedSections.lastIndexOf(section);
|
||||
// this.sectionVisible[sectionIndex] = true;
|
||||
//
|
||||
// this.sectionsNotListeningTo.add(section);
|
||||
// this.notifyAllListeners();
|
||||
// }
|
||||
//
|
||||
// public void onSectionLeftRange(EntityMovementTrackerSection section) {
|
||||
// this.setChanged(this.trackedWorldSections.world().getGameTime());
|
||||
// //noinspection SuspiciousMethodCalls
|
||||
// int sectionIndex = this.sortedSections.lastIndexOf(section);
|
||||
//
|
||||
// this.sectionVisible[sectionIndex] = false;
|
||||
//
|
||||
// if (!this.sectionsNotListeningTo.remove(section)) {
|
||||
// section.lithium$removeListenToMovementOnce(this, this.trackedClass);
|
||||
// this.notifyAllListeners();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Method that marks that new entities might have appeared or moved in the tracked chunk sections.
|
||||
// */
|
||||
// private void setChanged(long atTime) {
|
||||
// if (atTime > this.maxChangeTime) {
|
||||
// this.maxChangeTime = atTime;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void listenToEntityMovementOnce(SectionedEntityMovementListener listener) {
|
||||
// if (this.sectionedEntityMovementListeners == null) {
|
||||
// this.sectionedEntityMovementListeners = new ReferenceOpenHashSet<>();
|
||||
// }
|
||||
// this.sectionedEntityMovementListeners.add(listener);
|
||||
//
|
||||
// if (!this.sectionsNotListeningTo.isEmpty()) {
|
||||
// this.setChanged(this.listenToAllSectionsAndGetMaxChangeTime());
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public void emitEntityMovement(int classMask, EntityMovementTrackerSection section) {
|
||||
// if ((classMask & (1 << this.trackedClass)) != 0) {
|
||||
// this.notifyAllListeners();
|
||||
// this.sectionsNotListeningTo.add(section);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void notifyAllListeners() {
|
||||
// ReferenceOpenHashSet<SectionedEntityMovementListener> listeners = this.sectionedEntityMovementListeners;
|
||||
// if (listeners != null && !listeners.isEmpty()) {
|
||||
// for (SectionedEntityMovementListener listener : listeners) {
|
||||
// listener.lithium$handleEntityMovement(this.clazz);
|
||||
// }
|
||||
// listeners.clear();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,55 +1,55 @@
|
||||
package net.gensokyoreimagined.nitori.common.world;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
import net.gensokyoreimagined.nitori.common.entity.block_tracking.ChunkSectionChangeCallback;
|
||||
import net.gensokyoreimagined.nitori.common.entity.block_tracking.SectionedBlockChangeTracker;
|
||||
import net.gensokyoreimagined.nitori.common.entity.movement_tracker.SectionedEntityMovementTracker;
|
||||
import net.gensokyoreimagined.nitori.common.util.deduplication.LithiumInterner;
|
||||
import net.minecraft.world.entity.ai.navigation.PathNavigation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.entity.raid.Raid;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.gameevent.GameEventDispatcher;
|
||||
import net.minecraft.world.level.gameevent.GameEventListenerRegistry;
|
||||
|
||||
public interface LithiumData {
|
||||
|
||||
record Data(
|
||||
// Map of chunk position -> y section -> game event dispatcher
|
||||
// This should be faster than the chunk lookup, since there are usually a lot more chunks than
|
||||
// chunk with game event dispatchers (we only initialize them when non-empty set of listeners)
|
||||
// All Int2ObjectMap objects are also stored in a field of the corresponding WorldChunk.
|
||||
Long2ReferenceOpenHashMap<Int2ObjectMap<GameEventDispatcher>> gameEventDispatchersByChunk,
|
||||
|
||||
// Cached ominous banner, must not be mutated.
|
||||
ItemStack ominousBanner,
|
||||
|
||||
// Set of active mob navigations (active = have a path)
|
||||
ReferenceOpenHashSet<PathNavigation> activeNavigations,
|
||||
|
||||
// Block change tracker deduplication
|
||||
LithiumInterner<SectionedBlockChangeTracker> blockChangeTrackers,
|
||||
|
||||
// Entity movement tracker deduplication
|
||||
LithiumInterner<SectionedEntityMovementTracker<?, ?>> entityMovementTrackers,
|
||||
|
||||
// Block ChunkSection listeners
|
||||
Long2ReferenceOpenHashMap<ChunkSectionChangeCallback> chunkSectionChangeCallbacks
|
||||
) {
|
||||
public Data(Level world) {
|
||||
this(
|
||||
new Long2ReferenceOpenHashMap<>(),
|
||||
world.registryAccess().lookup(Registries.BANNER_PATTERN).map(Raid::getLeaderBannerInstance).orElse(null),
|
||||
new ReferenceOpenHashSet<>(),
|
||||
new LithiumInterner<>(),
|
||||
new LithiumInterner<>(),
|
||||
new Long2ReferenceOpenHashMap<>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LithiumData.Data lithium$getData();
|
||||
}
|
||||
//import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
//import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
|
||||
//import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
//import net.gensokyoreimagined.nitori.common.entity.block_tracking.ChunkSectionChangeCallback;
|
||||
//import net.gensokyoreimagined.nitori.common.entity.block_tracking.SectionedBlockChangeTracker;
|
||||
//import net.gensokyoreimagined.nitori.common.entity.movement_tracker.SectionedEntityMovementTracker;
|
||||
//import net.gensokyoreimagined.nitori.common.util.deduplication.LithiumInterner;
|
||||
//import net.minecraft.world.entity.ai.navigation.PathNavigation;
|
||||
//import net.minecraft.world.item.ItemStack;
|
||||
//import net.minecraft.core.registries.Registries;
|
||||
//import net.minecraft.world.entity.raid.Raid;
|
||||
//import net.minecraft.world.level.Level;
|
||||
//import net.minecraft.world.level.gameevent.GameEventDispatcher;
|
||||
//import net.minecraft.world.level.gameevent.GameEventListenerRegistry;
|
||||
//
|
||||
//public interface LithiumData {
|
||||
//
|
||||
// record Data(
|
||||
// // Map of chunk position -> y section -> game event dispatcher
|
||||
// // This should be faster than the chunk lookup, since there are usually a lot more chunks than
|
||||
// // chunk with game event dispatchers (we only initialize them when non-empty set of listeners)
|
||||
// // All Int2ObjectMap objects are also stored in a field of the corresponding WorldChunk.
|
||||
// Long2ReferenceOpenHashMap<Int2ObjectMap<GameEventDispatcher>> gameEventDispatchersByChunk,
|
||||
//
|
||||
// // Cached ominous banner, must not be mutated.
|
||||
// ItemStack ominousBanner,
|
||||
//
|
||||
// // Set of active mob navigations (active = have a path)
|
||||
// ReferenceOpenHashSet<PathNavigation> activeNavigations,
|
||||
//
|
||||
// // Block change tracker deduplication
|
||||
// LithiumInterner<SectionedBlockChangeTracker> blockChangeTrackers,
|
||||
//
|
||||
// // Entity movement tracker deduplication
|
||||
// LithiumInterner<SectionedEntityMovementTracker<?, ?>> entityMovementTrackers,
|
||||
//
|
||||
// // Block ChunkSection listeners
|
||||
// Long2ReferenceOpenHashMap<ChunkSectionChangeCallback> chunkSectionChangeCallbacks
|
||||
// ) {
|
||||
// public Data(Level world) {
|
||||
// this(
|
||||
// new Long2ReferenceOpenHashMap<>(),
|
||||
// world.registryAccess().lookup(Registries.BANNER_PATTERN).map(Raid::getLeaderBannerInstance).orElse(null),
|
||||
// new ReferenceOpenHashSet<>(),
|
||||
// new LithiumInterner<>(),
|
||||
// new LithiumInterner<>(),
|
||||
// new Long2ReferenceOpenHashMap<>()
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// LithiumData.Data lithium$getData();
|
||||
//}
|
||||
@@ -1,199 +1,199 @@
|
||||
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.gensokyoreimagined.nitori.mixin.needs_testing.chunk.palette.PaletteResizeAccessor;
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
|
||||
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.level.chunk.HashMapPalette} when calling
|
||||
* {@link LithiumHashPalette#idFor(Object)} through using a faster backing map and reducing pointer chasing.
|
||||
*/
|
||||
public class LithiumHashPalette<T> implements Palette<T> {
|
||||
private static final int ABSENT_VALUE = -1;
|
||||
|
||||
private final IdMap<T> idList;
|
||||
// private final PaletteResize<T> resizeHandler;
|
||||
private final PaletteResizeAccessor<T> resizeHandler;
|
||||
private final int indexBits;
|
||||
|
||||
private final Reference2IntMap<T> table;
|
||||
private T[] entries;
|
||||
private int size = 0;
|
||||
|
||||
public LithiumHashPalette(IdMap<T> idList, PaletteResizeAccessor<T> resizeHandler, int indexBits, T[] entries, Reference2IntMap<T> table, int size) {
|
||||
this.idList = idList;
|
||||
this.resizeHandler = resizeHandler;
|
||||
this.indexBits = indexBits;
|
||||
this.entries = entries;
|
||||
this.table = table;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public LithiumHashPalette(IdMap<T> idList, int bits, PaletteResizeAccessor<T> resizeHandler, List<T> list) {
|
||||
this(idList, bits, resizeHandler);
|
||||
|
||||
for (T t : list) {
|
||||
this.addEntry(t);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public LithiumHashPalette(IdMap<T> idList, int bits, PaletteResizeAccessor<T> 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 idFor(T obj) {
|
||||
int id = this.table.getInt(obj);
|
||||
|
||||
if (id == ABSENT_VALUE) {
|
||||
id = this.computeEntry(obj);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean maybeHas(Predicate<T> 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.callOnResize(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 @NotNull T valueFor(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 read(FriendlyByteBuf buf) {
|
||||
this.clear();
|
||||
|
||||
int entryCount = buf.readVarInt();
|
||||
|
||||
for (int i = 0; i < entryCount; ++i) {
|
||||
this.addEntry(this.idList.byId(buf.readVarInt()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
int size = this.size;
|
||||
buf.writeVarInt(size);
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
buf.writeVarInt(this.idList.getId(this.valueFor(i)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSerializedSize() {
|
||||
int size = VarInt.getByteSize(this.size);
|
||||
|
||||
for (int i = 0; i < this.size; ++i) {
|
||||
size += VarInt.getByteSize(this.idList.getId(this.valueFor(i)));
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Palette<T> 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<T> getElements() {
|
||||
ImmutableList.Builder<T> builder = new ImmutableList.Builder<>();
|
||||
for (T entry : this.entries) {
|
||||
if (entry != null) {
|
||||
builder.add(entry);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static <A> Palette<A> create(int bits, IdMap<A> idList, PaletteResizeAccessor<A> listener, List<A> list) {
|
||||
return new LithiumHashPalette<>(idList, bits, listener, list);
|
||||
}
|
||||
}
|
||||
//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.gensokyoreimagined.nitori.mixin.needs_testing.chunk.palette.PaletteResizeAccessor;
|
||||
//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 org.jetbrains.annotations.NotNull;
|
||||
//
|
||||
//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.level.chunk.HashMapPalette} when calling
|
||||
//* {@link LithiumHashPalette#idFor(Object)} through using a faster backing map and reducing pointer chasing.
|
||||
//*/
|
||||
//public class LithiumHashPalette<T> implements Palette<T> {
|
||||
// private static final int ABSENT_VALUE = -1;
|
||||
//
|
||||
// private final IdMap<T> idList;
|
||||
// // private final PaletteResize<T> resizeHandler;
|
||||
// private final PaletteResizeAccessor<T> resizeHandler;
|
||||
// private final int indexBits;
|
||||
//
|
||||
// private final Reference2IntMap<T> table;
|
||||
// private T[] entries;
|
||||
// private int size = 0;
|
||||
//
|
||||
// public LithiumHashPalette(IdMap<T> idList, PaletteResizeAccessor<T> resizeHandler, int indexBits, T[] entries, Reference2IntMap<T> table, int size) {
|
||||
// this.idList = idList;
|
||||
// this.resizeHandler = resizeHandler;
|
||||
// this.indexBits = indexBits;
|
||||
// this.entries = entries;
|
||||
// this.table = table;
|
||||
// this.size = size;
|
||||
// }
|
||||
//
|
||||
// public LithiumHashPalette(IdMap<T> idList, int bits, PaletteResizeAccessor<T> resizeHandler, List<T> list) {
|
||||
// this(idList, bits, resizeHandler);
|
||||
//
|
||||
// for (T t : list) {
|
||||
// this.addEntry(t);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public LithiumHashPalette(IdMap<T> idList, int bits, PaletteResizeAccessor<T> 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 idFor(T obj) {
|
||||
// int id = this.table.getInt(obj);
|
||||
//
|
||||
// if (id == ABSENT_VALUE) {
|
||||
// id = this.computeEntry(obj);
|
||||
// }
|
||||
//
|
||||
// return id;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean maybeHas(Predicate<T> 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.callOnResize(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 @NotNull T valueFor(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 read(FriendlyByteBuf buf) {
|
||||
// this.clear();
|
||||
//
|
||||
// int entryCount = buf.readVarInt();
|
||||
//
|
||||
// for (int i = 0; i < entryCount; ++i) {
|
||||
// this.addEntry(this.idList.byId(buf.readVarInt()));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void write(FriendlyByteBuf buf) {
|
||||
// int size = this.size;
|
||||
// buf.writeVarInt(size);
|
||||
//
|
||||
// for (int i = 0; i < size; ++i) {
|
||||
// buf.writeVarInt(this.idList.getId(this.valueFor(i)));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getSerializedSize() {
|
||||
// int size = VarInt.getByteSize(this.size);
|
||||
//
|
||||
// for (int i = 0; i < this.size; ++i) {
|
||||
// size += VarInt.getByteSize(this.idList.getId(this.valueFor(i)));
|
||||
// }
|
||||
//
|
||||
// return size;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getSize() {
|
||||
// return this.size;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Palette<T> 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<T> getElements() {
|
||||
// ImmutableList.Builder<T> builder = new ImmutableList.Builder<>();
|
||||
// for (T entry : this.entries) {
|
||||
// if (entry != null) {
|
||||
// builder.add(entry);
|
||||
// }
|
||||
// }
|
||||
// return builder.build();
|
||||
// }
|
||||
//
|
||||
// public static <A> Palette<A> create(int bits, IdMap<A> idList, PaletteResizeAccessor<A> listener, List<A> list) {
|
||||
// return new LithiumHashPalette<>(idList, bits, listener, list);
|
||||
// }
|
||||
//}
|
||||
@@ -14,158 +14,158 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
package net.gensokyoreimagined.nitori.mixin;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceSets;
|
||||
//import net.gensokyoreimagined.nitori.config.NitoriConfig;
|
||||
import net.gensokyoreimagined.nitori.access.IMixinChunkMapAccess;
|
||||
import net.gensokyoreimagined.nitori.access.IMixinChunkMap_TrackedEntityAccess;
|
||||
import net.gensokyoreimagined.nitori.compatibility.PluginCompatibilityRegistry;
|
||||
import net.gensokyoreimagined.nitori.tracker.MultithreadedTracker;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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.Unique;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
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.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mixin(ChunkMap.class)
|
||||
public class ChunkMapMixin implements IMixinChunkMapAccess {
|
||||
|
||||
@Mutable
|
||||
@Shadow @Final public Int2ObjectMap<ChunkMap.TrackedEntity> entityMap;
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Final
|
||||
@Shadow
|
||||
public ServerLevel level;
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Unique
|
||||
private @Nullable MultithreadedTracker gensouHacks$multithreadedTracker;
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Final
|
||||
@Unique
|
||||
private final ConcurrentLinkedQueue<Runnable> gensouHacks$trackerMainThreadTasks = new ConcurrentLinkedQueue<>();
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Unique
|
||||
private boolean gensouHacks$tracking = false;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void reassignEntityTrackers(CallbackInfo ci) {
|
||||
this.entityMap = new Int2ObjectLinkedOpenHashMap<>();
|
||||
}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Override
|
||||
@Unique
|
||||
public void gensouHacks$runOnTrackerMainThread(final Runnable runnable) {
|
||||
if (this.gensouHacks$tracking) {
|
||||
this.gensouHacks$trackerMainThreadTasks.add(runnable);
|
||||
} else {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "newTrackerTick", at = @At("HEAD"), cancellable = true)
|
||||
private void atProcessTrackQueueHead(CallbackInfo callbackInfo) {
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
//TODO: Restore config condition
|
||||
//if (NitoriConfig.enableAsyncEntityTracker) {
|
||||
if (this.gensouHacks$multithreadedTracker == null) {
|
||||
this.gensouHacks$multithreadedTracker = new MultithreadedTracker(((ChunkSystemServerLevel) this.level).moonrise$getEntityTickingChunks(), this.gensouHacks$trackerMainThreadTasks);
|
||||
}
|
||||
|
||||
this.gensouHacks$tracking = true;
|
||||
try {
|
||||
this.gensouHacks$multithreadedTracker.tick();
|
||||
} finally {
|
||||
this.gensouHacks$tracking = false;
|
||||
}
|
||||
callbackInfo.cancel();
|
||||
//}
|
||||
// Mirai end
|
||||
}
|
||||
|
||||
@Mixin(ChunkMap.TrackedEntity.class)
|
||||
public static abstract class TrackedEntity implements IMixinChunkMap_TrackedEntityAccess {
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Override
|
||||
@Final
|
||||
@Accessor
|
||||
public abstract Entity getEntity(); // Mirai -> public
|
||||
|
||||
@Final
|
||||
@Mutable
|
||||
@Shadow
|
||||
public Set<ServerPlayerConnection> seenBy;
|
||||
|
||||
@Shadow
|
||||
public abstract void updatePlayer(ServerPlayer player);
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void reassignSeenBy(CallbackInfo ci) {
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
this.seenBy = ReferenceSets.synchronize(new ReferenceOpenHashSet<>()); // Mirai - sync
|
||||
}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Override
|
||||
@Final
|
||||
@Invoker
|
||||
public abstract void callUpdatePlayers(List<ServerPlayer> players); // Mirai -> public
|
||||
|
||||
@Redirect(method = "updatePlayers", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ChunkMap$TrackedEntity;updatePlayer(Lnet/minecraft/server/level/ServerPlayer;)V"))
|
||||
private void handleCitizensPluginTracking(ChunkMap.TrackedEntity self, ServerPlayer serverPlayer) {
|
||||
// Nitori - Citizens tracker must run on the main thread to avoid cyclic wait
|
||||
if (PluginCompatibilityRegistry.CITIZENS.shouldRedirectToMainThread(self, serverPlayer)) {
|
||||
((IMixinChunkMapAccess) (Object) ((ServerLevel) serverPlayer.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() ->
|
||||
this.updatePlayer(serverPlayer)
|
||||
);
|
||||
} else {
|
||||
this.updatePlayer(serverPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
@Redirect(method = "removePlayer", at = @At(value = "INVOKE", target = "Lorg/spigotmc/AsyncCatcher;catchOp(Ljava/lang/String;)V"))
|
||||
private void skipSpigotAsyncPlayerTrackerClear(String reason) {} // Mirai - we can remove async too
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
@Redirect(method = "updatePlayer", at = @At(value = "INVOKE", target = "Lorg/spigotmc/AsyncCatcher;catchOp(Ljava/lang/String;)V"))
|
||||
private void skipSpigotAsyncPlayerTrackerUpdate(String reason) {} // Mirai - we can update async
|
||||
|
||||
@Redirect(method = "updatePlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerEntity;addPairing(Lnet/minecraft/server/level/ServerPlayer;)V"))
|
||||
private void handleTrainCartsPluginAddPairing(ServerEntity self, ServerPlayer serverPlayer) {
|
||||
if (PluginCompatibilityRegistry.TRAIN_CARTS.shouldRedirectToMainThread((ChunkMap.TrackedEntity) (Object) this)) {
|
||||
((IMixinChunkMapAccess) (Object) ((ServerLevel) serverPlayer.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() ->
|
||||
self.addPairing(serverPlayer)
|
||||
);
|
||||
} else {
|
||||
self.addPairing(serverPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
//import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
||||
//import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
//import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
//import it.unimi.dsi.fastutil.objects.ReferenceSets;
|
||||
////import net.gensokyoreimagined.nitori.config.NitoriConfig;
|
||||
//import net.gensokyoreimagined.nitori.access.IMixinChunkMapAccess;
|
||||
//import net.gensokyoreimagined.nitori.access.IMixinChunkMap_TrackedEntityAccess;
|
||||
//import net.gensokyoreimagined.nitori.compatibility.PluginCompatibilityRegistry;
|
||||
//import net.gensokyoreimagined.nitori.tracker.MultithreadedTracker;
|
||||
//import net.minecraft.server.level.ChunkMap;
|
||||
//import net.minecraft.server.level.ServerEntity;
|
||||
//import net.minecraft.server.level.ServerLevel;
|
||||
//import net.minecraft.server.level.ServerPlayer;
|
||||
//import net.minecraft.server.network.ServerPlayerConnection;
|
||||
//import net.minecraft.world.entity.Entity;
|
||||
//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.Unique;
|
||||
//import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
//import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
//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.CallbackInfo;
|
||||
//
|
||||
//import java.util.List;
|
||||
//import java.util.Set;
|
||||
//import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
//import javax.annotation.Nullable;
|
||||
//
|
||||
//@Mixin(ChunkMap.class)
|
||||
//public class ChunkMapMixin implements IMixinChunkMapAccess {
|
||||
//
|
||||
// @Mutable
|
||||
// @Shadow @Final public Int2ObjectMap<ChunkMap.TrackedEntity> entityMap;
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Final
|
||||
// @Shadow
|
||||
// public ServerLevel level;
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Unique
|
||||
// private @Nullable MultithreadedTracker gensouHacks$multithreadedTracker;
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Final
|
||||
// @Unique
|
||||
// private final ConcurrentLinkedQueue<Runnable> gensouHacks$trackerMainThreadTasks = new ConcurrentLinkedQueue<>();
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Unique
|
||||
// private boolean gensouHacks$tracking = false;
|
||||
//
|
||||
// @Inject(method = "<init>", at = @At("RETURN"))
|
||||
// private void reassignEntityTrackers(CallbackInfo ci) {
|
||||
// this.entityMap = new Int2ObjectLinkedOpenHashMap<>();
|
||||
// }
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Override
|
||||
// @Unique
|
||||
// public void gensouHacks$runOnTrackerMainThread(final Runnable runnable) {
|
||||
// if (this.gensouHacks$tracking) {
|
||||
// this.gensouHacks$trackerMainThreadTasks.add(runnable);
|
||||
// } else {
|
||||
// runnable.run();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Inject(method = "newTrackerTick", at = @At("HEAD"), cancellable = true)
|
||||
// private void atProcessTrackQueueHead(CallbackInfo callbackInfo) {
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// //TODO: Restore config condition
|
||||
// //if (NitoriConfig.enableAsyncEntityTracker) {
|
||||
// if (this.gensouHacks$multithreadedTracker == null) {
|
||||
// this.gensouHacks$multithreadedTracker = new MultithreadedTracker(((ChunkSystemServerLevel) this.level).moonrise$getEntityTickingChunks(), this.gensouHacks$trackerMainThreadTasks);
|
||||
// }
|
||||
//
|
||||
// this.gensouHacks$tracking = true;
|
||||
// try {
|
||||
// this.gensouHacks$multithreadedTracker.tick();
|
||||
// } finally {
|
||||
// this.gensouHacks$tracking = false;
|
||||
// }
|
||||
// callbackInfo.cancel();
|
||||
// //}
|
||||
// // Mirai end
|
||||
// }
|
||||
//
|
||||
// @Mixin(ChunkMap.TrackedEntity.class)
|
||||
// public static abstract class TrackedEntity implements IMixinChunkMap_TrackedEntityAccess {
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Override
|
||||
// @Final
|
||||
// @Accessor
|
||||
// public abstract Entity getEntity(); // Mirai -> public
|
||||
//
|
||||
// @Final
|
||||
// @Mutable
|
||||
// @Shadow
|
||||
// public Set<ServerPlayerConnection> seenBy;
|
||||
//
|
||||
// @Shadow
|
||||
// public abstract void updatePlayer(ServerPlayer player);
|
||||
//
|
||||
// @Inject(method = "<init>", at = @At("RETURN"))
|
||||
// private void reassignSeenBy(CallbackInfo ci) {
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// this.seenBy = ReferenceSets.synchronize(new ReferenceOpenHashSet<>()); // Mirai - sync
|
||||
// }
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Override
|
||||
// @Final
|
||||
// @Invoker
|
||||
// public abstract void callUpdatePlayers(List<ServerPlayer> players); // Mirai -> public
|
||||
//
|
||||
// @Redirect(method = "updatePlayers", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ChunkMap$TrackedEntity;updatePlayer(Lnet/minecraft/server/level/ServerPlayer;)V"))
|
||||
// private void handleCitizensPluginTracking(ChunkMap.TrackedEntity self, ServerPlayer serverPlayer) {
|
||||
// // Nitori - Citizens tracker must run on the main thread to avoid cyclic wait
|
||||
// if (PluginCompatibilityRegistry.CITIZENS.shouldRedirectToMainThread(self, serverPlayer)) {
|
||||
// ((IMixinChunkMapAccess) (Object) ((ServerLevel) serverPlayer.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() ->
|
||||
// this.updatePlayer(serverPlayer)
|
||||
// );
|
||||
// } else {
|
||||
// this.updatePlayer(serverPlayer);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @SuppressWarnings("EmptyMethod")
|
||||
// @Redirect(method = "removePlayer", at = @At(value = "INVOKE", target = "Lorg/spigotmc/AsyncCatcher;catchOp(Ljava/lang/String;)V"))
|
||||
// private void skipSpigotAsyncPlayerTrackerClear(String reason) {} // Mirai - we can remove async too
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @SuppressWarnings("EmptyMethod")
|
||||
// @Redirect(method = "updatePlayer", at = @At(value = "INVOKE", target = "Lorg/spigotmc/AsyncCatcher;catchOp(Ljava/lang/String;)V"))
|
||||
// private void skipSpigotAsyncPlayerTrackerUpdate(String reason) {} // Mirai - we can update async
|
||||
//
|
||||
// @Redirect(method = "updatePlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerEntity;addPairing(Lnet/minecraft/server/level/ServerPlayer;)V"))
|
||||
// private void handleTrainCartsPluginAddPairing(ServerEntity self, ServerPlayer serverPlayer) {
|
||||
// if (PluginCompatibilityRegistry.TRAIN_CARTS.shouldRedirectToMainThread((ChunkMap.TrackedEntity) (Object) this)) {
|
||||
// ((IMixinChunkMapAccess) (Object) ((ServerLevel) serverPlayer.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() ->
|
||||
// self.addPairing(serverPlayer)
|
||||
// );
|
||||
// } else {
|
||||
// self.addPairing(serverPlayer);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -14,116 +14,116 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
package net.gensokyoreimagined.nitori.mixin;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.gensokyoreimagined.nitori.access.IMixinChunkMapAccess;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.network.protocol.game.ClientboundBundlePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
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.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(ServerEntity.class)
|
||||
public abstract class MixinServerEntity {
|
||||
@Final
|
||||
@Shadow
|
||||
private Entity entity;
|
||||
|
||||
@Shadow
|
||||
public void sendPairingData(ServerPlayer serverplayer, Consumer<Packet<ClientGamePacketListener>> consumer) {
|
||||
throw new AssertionError("Mixin failed to apply!");
|
||||
}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
@Redirect(method = "removePairing", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void skipSendForOriginalRemovePairing(ServerGamePacketListenerImpl self, Packet<?> packet) {}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Inject(method = "removePairing", at = @At(value = "TAIL"))
|
||||
private void invokeRemovePairingSendOnMain(ServerPlayer serverplayer, CallbackInfo callbackInfo) {
|
||||
// Mirai start - ensure main thread
|
||||
((IMixinChunkMapAccess) (Object) ((ServerLevel) this.entity.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() ->
|
||||
serverplayer.connection.send(new ClientboundRemoveEntitiesPacket(this.entity.getId()))
|
||||
);
|
||||
// Mirai end
|
||||
}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
@Redirect(method = "addPairing", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerEntity;sendPairingData(Lnet/minecraft/server/level/ServerPlayer;Ljava/util/function/Consumer;)V"))
|
||||
private void skipSendPrepForOriginalAddPairing(ServerEntity self, ServerPlayer serverplayer, Consumer<Packet<ClientGamePacketListener>> consumer) {}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
@Redirect(method = "addPairing", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void skipSendForOriginalAddPairing(ServerGamePacketListenerImpl self, Packet<?> packet) {}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Inject(method = "addPairing", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "FIELD", target = "Lnet/minecraft/server/level/ServerEntity;entity:Lnet/minecraft/world/entity/Entity;", opcode = Opcodes.GETFIELD, shift = At.Shift.BEFORE))
|
||||
private void invokeAddPairingSendOnMain(ServerPlayer serverplayer, CallbackInfo callbackInfo, @Local List<Packet<? super ClientGamePacketListener>> list) {
|
||||
((IMixinChunkMapAccess) (Object) ((ServerLevel) this.entity.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() -> { // Mirai - main thread
|
||||
this.sendPairingData(serverplayer, list::add);
|
||||
serverplayer.connection.send(new ClientboundBundlePacket(list));
|
||||
});
|
||||
}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
@Redirect(method = "sendDirtyEntityData", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerEntity;broadcastAndSend(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void skipTrasmitForNonDefault(ServerEntity self, Packet<?> packet) {}
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Inject(method = "sendDirtyEntityData", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "FIELD", target = "Lnet/minecraft/server/level/ServerEntity;entity:Lnet/minecraft/world/entity/Entity;", opcode = Opcodes.GETFIELD, ordinal = 2, shift = At.Shift.BY, by = -4))
|
||||
private void invokeSendForGenericDirtyEntityDataOnMain(CallbackInfo callbackInfo, @Local SynchedEntityData synchedentitydata, @Local List<SynchedEntityData.DataValue<?>> list) {
|
||||
// Mirai start - sync
|
||||
((IMixinChunkMapAccess) (Object) ((ServerLevel) this.entity.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() ->
|
||||
this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list))
|
||||
);
|
||||
// Mirai end
|
||||
}
|
||||
|
||||
// stubbing of broadcastAndSend in if (this.entity instanceof LivingEntity) handled in skipTrasmitForNonDefault
|
||||
|
||||
// Implementation of 0107-Multithreaded-Tracker.patch
|
||||
@Inject(method = "sendDirtyEntityData", at = @At(value = "INVOKE", target = "Ljava/util/Set;clear()V", shift = At.Shift.BY, by = -4))
|
||||
private void invokeSendForLivingDirtyEntityDataOnMain(CallbackInfo callbackInfo, @Local Set<AttributeInstance> set) {
|
||||
// Mirai start - sync
|
||||
final var copy = Lists.newArrayList(set);
|
||||
((IMixinChunkMapAccess) (Object) ((ServerLevel) this.entity.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() -> {
|
||||
// CraftBukkit start - Send scaled max health
|
||||
if (this.entity instanceof ServerPlayer) {
|
||||
((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(copy, false);
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy));
|
||||
});
|
||||
// Mirai end
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private void broadcastAndSend(Packet<?> packet) {
|
||||
throw new AssertionError("Mixin failed to apply!");
|
||||
}
|
||||
}
|
||||
//import com.google.common.collect.Lists;
|
||||
//import com.llamalad7.mixinextras.sugar.Local;
|
||||
//import net.gensokyoreimagined.nitori.access.IMixinChunkMapAccess;
|
||||
//import net.minecraft.network.protocol.Packet;
|
||||
//import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
//import net.minecraft.network.protocol.game.ClientboundBundlePacket;
|
||||
//import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
|
||||
//import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
|
||||
//import net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket;
|
||||
//import net.minecraft.network.syncher.SynchedEntityData;
|
||||
//import net.minecraft.server.level.ServerEntity;
|
||||
//import net.minecraft.server.level.ServerLevel;
|
||||
//import net.minecraft.server.level.ServerPlayer;
|
||||
//import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
//import net.minecraft.world.entity.Entity;
|
||||
//import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
//import org.objectweb.asm.Opcodes;
|
||||
//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.Inject;
|
||||
//import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
//
|
||||
//import java.util.List;
|
||||
//import java.util.Set;
|
||||
//import java.util.function.Consumer;
|
||||
//
|
||||
//@Mixin(ServerEntity.class)
|
||||
//public abstract class MixinServerEntity {
|
||||
// @Final
|
||||
// @Shadow
|
||||
// private Entity entity;
|
||||
//
|
||||
// @Shadow
|
||||
// public void sendPairingData(ServerPlayer serverplayer, Consumer<Packet<ClientGamePacketListener>> consumer) {
|
||||
// throw new AssertionError("Mixin failed to apply!");
|
||||
// }
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @SuppressWarnings("EmptyMethod")
|
||||
// @Redirect(method = "removePairing", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
// private void skipSendForOriginalRemovePairing(ServerGamePacketListenerImpl self, Packet<?> packet) {}
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Inject(method = "removePairing", at = @At(value = "TAIL"))
|
||||
// private void invokeRemovePairingSendOnMain(ServerPlayer serverplayer, CallbackInfo callbackInfo) {
|
||||
// // Mirai start - ensure main thread
|
||||
// ((IMixinChunkMapAccess) (Object) ((ServerLevel) this.entity.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() ->
|
||||
// serverplayer.connection.send(new ClientboundRemoveEntitiesPacket(this.entity.getId()))
|
||||
// );
|
||||
// // Mirai end
|
||||
// }
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @SuppressWarnings("EmptyMethod")
|
||||
// @Redirect(method = "addPairing", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerEntity;sendPairingData(Lnet/minecraft/server/level/ServerPlayer;Ljava/util/function/Consumer;)V"))
|
||||
// private void skipSendPrepForOriginalAddPairing(ServerEntity self, ServerPlayer serverplayer, Consumer<Packet<ClientGamePacketListener>> consumer) {}
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @SuppressWarnings("EmptyMethod")
|
||||
// @Redirect(method = "addPairing", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
// private void skipSendForOriginalAddPairing(ServerGamePacketListenerImpl self, Packet<?> packet) {}
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Inject(method = "addPairing", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "FIELD", target = "Lnet/minecraft/server/level/ServerEntity;entity:Lnet/minecraft/world/entity/Entity;", opcode = Opcodes.GETFIELD, shift = At.Shift.BEFORE))
|
||||
// private void invokeAddPairingSendOnMain(ServerPlayer serverplayer, CallbackInfo callbackInfo, @Local List<Packet<? super ClientGamePacketListener>> list) {
|
||||
// ((IMixinChunkMapAccess) (Object) ((ServerLevel) this.entity.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() -> { // Mirai - main thread
|
||||
// this.sendPairingData(serverplayer, list::add);
|
||||
// serverplayer.connection.send(new ClientboundBundlePacket(list));
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @SuppressWarnings("EmptyMethod")
|
||||
// @Redirect(method = "sendDirtyEntityData", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerEntity;broadcastAndSend(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
// private void skipTrasmitForNonDefault(ServerEntity self, Packet<?> packet) {}
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Inject(method = "sendDirtyEntityData", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "FIELD", target = "Lnet/minecraft/server/level/ServerEntity;entity:Lnet/minecraft/world/entity/Entity;", opcode = Opcodes.GETFIELD, ordinal = 2, shift = At.Shift.BY, by = -4))
|
||||
// private void invokeSendForGenericDirtyEntityDataOnMain(CallbackInfo callbackInfo, @Local SynchedEntityData synchedentitydata, @Local List<SynchedEntityData.DataValue<?>> list) {
|
||||
// // Mirai start - sync
|
||||
// ((IMixinChunkMapAccess) (Object) ((ServerLevel) this.entity.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() ->
|
||||
// this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list))
|
||||
// );
|
||||
// // Mirai end
|
||||
// }
|
||||
//
|
||||
// // stubbing of broadcastAndSend in if (this.entity instanceof LivingEntity) handled in skipTrasmitForNonDefault
|
||||
//
|
||||
// // Implementation of 0107-Multithreaded-Tracker.patch
|
||||
// @Inject(method = "sendDirtyEntityData", at = @At(value = "INVOKE", target = "Ljava/util/Set;clear()V", shift = At.Shift.BY, by = -4))
|
||||
// private void invokeSendForLivingDirtyEntityDataOnMain(CallbackInfo callbackInfo, @Local Set<AttributeInstance> set) {
|
||||
// // Mirai start - sync
|
||||
// final var copy = Lists.newArrayList(set);
|
||||
// ((IMixinChunkMapAccess) (Object) ((ServerLevel) this.entity.level()).chunkSource.chunkMap).gensouHacks$runOnTrackerMainThread(() -> {
|
||||
// // CraftBukkit start - Send scaled max health
|
||||
// if (this.entity instanceof ServerPlayer) {
|
||||
// ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(copy, false);
|
||||
// }
|
||||
// // CraftBukkit end
|
||||
// this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy));
|
||||
// });
|
||||
// // Mirai end
|
||||
// }
|
||||
//
|
||||
// @Shadow
|
||||
// private void broadcastAndSend(Packet<?> packet) {
|
||||
// throw new AssertionError("Mixin failed to apply!");
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -27,38 +27,38 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
// Taken from Lithium
|
||||
// https://github.com/CaffeineMC/lithium-fabric/blob/427dd75ffc922cc1858c1db4b283cc54744567e0/src/main/java/me/jellysquid/mods/lithium/mixin/alloc/chunk_random/ServerWorldMixin.java#L24
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public abstract class MixinServerWorld {
|
||||
@Unique
|
||||
private final BlockPos.MutableBlockPos nitori$randomPosInChunkCachedPos = new BlockPos.MutableBlockPos();
|
||||
|
||||
/**
|
||||
* @reason Avoid allocating BlockPos every invocation through using our allocation-free variant
|
||||
*/
|
||||
@Redirect(
|
||||
method = "tickChunk",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/level/ServerLevel;getBlockRandomPos(IIII)Lnet/minecraft/core/BlockPos;"
|
||||
)
|
||||
)
|
||||
private BlockPos redirectTickGetRandomPosInChunk(ServerLevel serverWorld, int x, int y, int z, int mask) {
|
||||
((ChunkRandomSource) serverWorld).nitori$getRandomPosInChunk(x, y, z, mask, this.nitori$randomPosInChunkCachedPos);
|
||||
|
||||
return this.nitori$randomPosInChunkCachedPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Ensure an immutable block position is passed on block tick
|
||||
*/
|
||||
@Redirect(
|
||||
method = "tickChunk",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/block/state/BlockState;randomTick(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/util/RandomSource;)V"
|
||||
)
|
||||
)
|
||||
private void redirectBlockStateTick(BlockState blockState, ServerLevel world, BlockPos pos, RandomSource rand) {
|
||||
blockState.randomTick(world, pos.immutable(), rand);
|
||||
}
|
||||
}
|
||||
//@Mixin(ServerLevel.class)
|
||||
//public abstract class MixinServerWorld {
|
||||
// @Unique
|
||||
// private final BlockPos.MutableBlockPos nitori$randomPosInChunkCachedPos = new BlockPos.MutableBlockPos();
|
||||
//
|
||||
// /**
|
||||
// * @reason Avoid allocating BlockPos every invocation through using our allocation-free variant
|
||||
// */
|
||||
// @Redirect(
|
||||
// method = "tickChunk",
|
||||
// at = @At(
|
||||
// value = "INVOKE",
|
||||
// target = "Lnet/minecraft/server/level/ServerLevel;getBlockRandomPos(IIII)Lnet/minecraft/core/BlockPos;"
|
||||
// )
|
||||
// )
|
||||
// private BlockPos redirectTickGetRandomPosInChunk(ServerLevel serverWorld, int x, int y, int z, int mask) {
|
||||
// ((ChunkRandomSource) serverWorld).nitori$getRandomPosInChunk(x, y, z, mask, this.nitori$randomPosInChunkCachedPos);
|
||||
//
|
||||
// return this.nitori$randomPosInChunkCachedPos;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @reason Ensure an immutable block position is passed on block tick
|
||||
// */
|
||||
// @Redirect(
|
||||
// method = "tickChunk",
|
||||
// at = @At(
|
||||
// value = "INVOKE",
|
||||
// target = "Lnet/minecraft/server/level/ServerLevel;optimiseRandomTick(Lnet/minecraft/world/level/chunk/LevelChunk;I)V"
|
||||
// )
|
||||
// )
|
||||
// private void redirectBlockStateTick(BlockState blockState, ServerLevel world, BlockPos pos, RandomSource rand) {
|
||||
// blockState.randomTick(world, pos.immutable(), rand);
|
||||
// }
|
||||
//}
|
||||
@@ -14,20 +14,20 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
package net.gensokyoreimagined.nitori.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(targets = "gg.pufferfish.pufferfish.simd.SIMDDetection")
|
||||
public abstract class MixinSpongeSIMD {
|
||||
@Inject(method = "getJavaVersion", at = @At("RETURN"), cancellable = true)
|
||||
private static void loadPufferfishConfig(CallbackInfoReturnable<Integer> callback) {
|
||||
// We troll the Pufferfish developers by changing the return value of the method
|
||||
// System.out.println("Thought that it was " + callback.getReturnValue() + " for java version");
|
||||
if (callback.getReturnValue() == 21) {
|
||||
System.out.println("Successfully trolled Pufferfish into thinking we're on Java 19!");
|
||||
callback.setReturnValue(19);
|
||||
}
|
||||
}
|
||||
}
|
||||
//import org.spongepowered.asm.mixin.Mixin;
|
||||
//import org.spongepowered.asm.mixin.injection.At;
|
||||
//import org.spongepowered.asm.mixin.injection.Inject;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
//
|
||||
//@Mixin(targets = "gg.pufferfish.pufferfish.simd.SIMDDetection")
|
||||
//public abstract class MixinSpongeSIMD {
|
||||
// @Inject(method = "getJavaVersion", at = @At("RETURN"), cancellable = true)
|
||||
// private static void loadPufferfishConfig(CallbackInfoReturnable<Integer> callback) {
|
||||
// // We troll the Pufferfish developers by changing the return value of the method
|
||||
// // System.out.println("Thought that it was " + callback.getReturnValue() + " for java version");
|
||||
// if (callback.getReturnValue() == 21) {
|
||||
// System.out.println("Successfully trolled Pufferfish into thinking we're on Java 19!");
|
||||
// callback.setReturnValue(19);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -33,50 +33,50 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(WorldGenRegion.class)
|
||||
public class MixinWorldGenRegion {
|
||||
@Shadow @Final private ChunkPos firstPos;
|
||||
@Shadow @Final private int size;
|
||||
|
||||
@Unique
|
||||
private ChunkAccess[] gensouHacks$chunksArr;
|
||||
@Unique
|
||||
private int gensouHacks$minChunkX;
|
||||
@Unique
|
||||
private int gensouHacks$minChunkZ;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void onInit(ServerLevel world, List<ChunkAccess> chunks, ChunkStatus status, int placementRadius, CallbackInfo ci) {
|
||||
this.gensouHacks$minChunkX = this.firstPos.x;
|
||||
this.gensouHacks$minChunkZ = this.firstPos.z;
|
||||
this.gensouHacks$chunksArr = chunks.toArray(new ChunkAccess[0]);
|
||||
}
|
||||
|
||||
@Inject(method = "getChunk(II)Lnet/minecraft/world/level/chunk/ChunkAccess;", at = @At("HEAD"), cancellable = true)
|
||||
public void getChunk(int chunkX, int chunkZ, CallbackInfoReturnable<ChunkAccess> cir) {
|
||||
int x = chunkX - this.gensouHacks$minChunkX;
|
||||
int z = chunkZ - this.gensouHacks$minChunkZ;
|
||||
int w = this.size;
|
||||
|
||||
if (x >= 0 && z >= 0 && x < w && z < w) {
|
||||
cir.setReturnValue(this.gensouHacks$chunksArr[x + z * w]);
|
||||
cir.cancel();
|
||||
} else {
|
||||
throw new NullPointerException("No chunk exists at " + new ChunkPos(chunkX, chunkZ));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "getBlockState", at = @At("HEAD"), cancellable = true)
|
||||
public void getBlockState(BlockPos pos, CallbackInfoReturnable<BlockState> cir) {
|
||||
int x = (Pos.ChunkCoord.fromBlockCoord(pos.getX())) - this.gensouHacks$minChunkX;
|
||||
int z = (Pos.ChunkCoord.fromBlockCoord(pos.getZ())) - this.gensouHacks$minChunkZ;
|
||||
int w = this.size;
|
||||
|
||||
if (x >= 0 && z >= 0 && x < w && z < w) {
|
||||
cir.setReturnValue(this.gensouHacks$chunksArr[x + z * w].getBlockState(pos));
|
||||
cir.cancel();
|
||||
} else {
|
||||
throw new NullPointerException("No chunk exists at " + new ChunkPos(pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
//@Mixin(WorldGenRegion.class)
|
||||
//public class MixinWorldGenRegion {
|
||||
// @Shadow @Final private ChunkPos firstPos;
|
||||
// @Shadow @Final private int size;
|
||||
//
|
||||
// @Unique
|
||||
// private ChunkAccess[] gensouHacks$chunksArr;
|
||||
// @Unique
|
||||
// private int gensouHacks$minChunkX;
|
||||
// @Unique
|
||||
// private int gensouHacks$minChunkZ;
|
||||
//
|
||||
// @Inject(method = "<init>", at = @At("RETURN"))
|
||||
// private void onInit(ServerLevel world, List<ChunkAccess> chunks, ChunkStatus status, int placementRadius, CallbackInfo ci) {
|
||||
// this.gensouHacks$minChunkX = this.firstPos.x;
|
||||
// this.gensouHacks$minChunkZ = this.firstPos.z;
|
||||
// this.gensouHacks$chunksArr = chunks.toArray(new ChunkAccess[0]);
|
||||
// }
|
||||
//
|
||||
// @Inject(method = "getChunk(II)Lnet/minecraft/world/level/chunk/ChunkAccess;", at = @At("HEAD"), cancellable = true)
|
||||
// public void getChunk(int chunkX, int chunkZ, CallbackInfoReturnable<ChunkAccess> cir) {
|
||||
// int x = chunkX - this.gensouHacks$minChunkX;
|
||||
// int z = chunkZ - this.gensouHacks$minChunkZ;
|
||||
// int w = this.size;
|
||||
//
|
||||
// if (x >= 0 && z >= 0 && x < w && z < w) {
|
||||
// cir.setReturnValue(this.gensouHacks$chunksArr[x + z * w]);
|
||||
// cir.cancel();
|
||||
// } else {
|
||||
// throw new NullPointerException("No chunk exists at " + new ChunkPos(chunkX, chunkZ));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Inject(method = "getBlockState", at = @At("HEAD"), cancellable = true)
|
||||
// public void getBlockState(BlockPos pos, CallbackInfoReturnable<BlockState> cir) {
|
||||
// int x = (Pos.ChunkCoord.fromBlockCoord(pos.getX())) - this.gensouHacks$minChunkX;
|
||||
// int z = (Pos.ChunkCoord.fromBlockCoord(pos.getZ())) - this.gensouHacks$minChunkZ;
|
||||
// int w = this.size;
|
||||
//
|
||||
// if (x >= 0 && z >= 0 && x < w && z < w) {
|
||||
// cir.setReturnValue(this.gensouHacks$chunksArr[x + z * w].getBlockState(pos));
|
||||
// cir.cancel();
|
||||
// } else {
|
||||
// throw new NullPointerException("No chunk exists at " + new ChunkPos(pos));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -14,40 +14,40 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
package net.gensokyoreimagined.nitori.mixin.alloc.chunk_ticking;
|
||||
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.CallbackInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@Mixin(ServerChunkCache.class)
|
||||
public class ServerChunkManagerMixin {
|
||||
private final ArrayList<ChunkHolder> cachedChunkList = new ArrayList<>();
|
||||
|
||||
@Redirect(
|
||||
method = "tickChunks()V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lcom/google/common/collect/Lists;newArrayListWithCapacity(I)Ljava/util/ArrayList;",
|
||||
remap = false
|
||||
)
|
||||
)
|
||||
private ArrayList<ChunkHolder> redirectChunksListClone(int initialArraySize) {
|
||||
ArrayList<ChunkHolder> list = this.cachedChunkList;
|
||||
list.clear(); // Ensure the list is empty before re-using it
|
||||
list.ensureCapacity(initialArraySize);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Inject(method = "tick(Ljava/util/function/BooleanSupplier;Z)V", at = @At("HEAD"))
|
||||
private void preTick(BooleanSupplier shouldKeepTicking, boolean tickChunks, CallbackInfo ci) {
|
||||
// Ensure references aren't leaked through this list
|
||||
this.cachedChunkList.clear();
|
||||
}
|
||||
}
|
||||
//import net.minecraft.server.level.ChunkHolder;
|
||||
//import net.minecraft.server.level.ServerChunkCache;
|
||||
//import org.spongepowered.asm.mixin.Mixin;
|
||||
//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.CallbackInfo;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.function.BooleanSupplier;
|
||||
//
|
||||
//@Mixin(ServerChunkCache.class)
|
||||
//public class ServerChunkManagerMixin {
|
||||
// private final ArrayList<ChunkHolder> cachedChunkList = new ArrayList<>();
|
||||
//
|
||||
// @Redirect(
|
||||
// method = "tickChunks",
|
||||
// at = @At(
|
||||
// value = "INVOKE",
|
||||
// target = "Lcom/google/common/collect/Lists;newArrayListWithCapacity(I)Ljava/util/ArrayList;",
|
||||
// remap = false
|
||||
// )
|
||||
// )
|
||||
// private ArrayList<ChunkHolder> redirectChunksListClone(int initialArraySize) {
|
||||
// ArrayList<ChunkHolder> list = this.cachedChunkList;
|
||||
// list.clear(); // Ensure the list is empty before re-using it
|
||||
// list.ensureCapacity(initialArraySize);
|
||||
//
|
||||
// return list;
|
||||
// }
|
||||
//
|
||||
// @Inject(method = "tick(Ljava/util/function/BooleanSupplier;Z)V", at = @At("HEAD"))
|
||||
// private void preTick(BooleanSupplier shouldKeepTicking, boolean tickChunks, CallbackInfo ci) {
|
||||
// // Ensure references aren't leaked through this list
|
||||
// this.cachedChunkList.clear();
|
||||
// }
|
||||
//}
|
||||
@@ -1,40 +1,40 @@
|
||||
package net.gensokyoreimagined.nitori.mixin.collections.attributes;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeMap;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attribute;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
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;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(AttributeMap.class)
|
||||
public class AttributeContainerMixin {
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private Map<Attribute, AttributeInstance> attributes;
|
||||
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private Set<AttributeInstance> dirtyAttributes;
|
||||
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void initCollections(AttributeSupplier defaultAttributes, CallbackInfo ci) {
|
||||
this.attributes = new Reference2ReferenceOpenHashMap<>(0);
|
||||
this.dirtyAttributes = new ReferenceOpenHashSet<>(0);
|
||||
}
|
||||
}
|
||||
//import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
||||
//import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
//import net.minecraft.world.entity.ai.attributes.AttributeMap;
|
||||
//import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
//import net.minecraft.world.entity.ai.attributes.Attribute;
|
||||
//import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
//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;
|
||||
//import java.util.Set;
|
||||
//
|
||||
//@Mixin(AttributeMap.class)
|
||||
//public class AttributeContainerMixin {
|
||||
// @Mutable
|
||||
// @Shadow
|
||||
// @Final
|
||||
// private Map<Attribute, AttributeInstance> attributes;
|
||||
//
|
||||
// @Mutable
|
||||
// @Shadow
|
||||
// @Final
|
||||
// private Set<AttributeInstance> attributesToSync;
|
||||
//
|
||||
// @Inject(
|
||||
// method = "<init>",
|
||||
// at = @At("RETURN")
|
||||
// )
|
||||
// private void initCollections(AttributeSupplier defaultAttributes, CallbackInfo ci) {
|
||||
// this.attributes = new Reference2ReferenceOpenHashMap<>(0);
|
||||
// this.attributesToSync = new ReferenceOpenHashSet<>(0);
|
||||
// }
|
||||
//}
|
||||
@@ -1,14 +1,14 @@
|
||||
package net.gensokyoreimagined.nitori.mixin.util.accessors;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
// Does not work on Paper...
|
||||
@Mixin(ServerLevel.class)
|
||||
public interface ServerWorldAccessor {
|
||||
@Accessor
|
||||
PersistentEntitySectionManager<Entity> getEntityManager();
|
||||
}
|
||||
//import net.minecraft.server.level.ServerLevel;
|
||||
//import net.minecraft.world.entity.Entity;
|
||||
//import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
||||
//import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
//import org.spongepowered.asm.mixin.Mixin;
|
||||
//
|
||||
//// Does not work on Paper...
|
||||
//@Mixin(ServerLevel.class)
|
||||
//public interface ServerWorldAccessor {
|
||||
// @Accessor
|
||||
// PersistentEntitySectionManager<Entity> getEntityManager();
|
||||
//}
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
package net.gensokyoreimagined.nitori.mixin.world.block_entity_ticking.sleeping.campfire;
|
||||
|
||||
import net.gensokyoreimagined.nitori.common.block.entity.SleepingBlockEntity;
|
||||
import net.gensokyoreimagined.nitori.mixin.world.block_entity_ticking.sleeping.WrappedBlockEntityTickInvokerAccessor;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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.world.level.block.entity.CampfireBlockEntity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.entity.TickingBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(CampfireBlockEntity.class)
|
||||
public class CampfireBlockEntityMixin extends BlockEntity implements SleepingBlockEntity {
|
||||
|
||||
private WrappedBlockEntityTickInvokerAccessor tickWrapper = null;
|
||||
private TickingBlockEntity sleepingTicker = null;
|
||||
|
||||
public CampfireBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedBlockEntityTickInvokerAccessor lithium$getTickWrapper() {
|
||||
return tickWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lithium$setTickWrapper(WrappedBlockEntityTickInvokerAccessor tickWrapper) {
|
||||
this.tickWrapper = tickWrapper;
|
||||
this.lithium$setSleepingTicker(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingBlockEntity lithium$getSleepingTicker() {
|
||||
return sleepingTicker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lithium$setSleepingTicker(TickingBlockEntity sleepingTicker) {
|
||||
this.sleepingTicker = sleepingTicker;
|
||||
}
|
||||
|
||||
|
||||
@Inject(
|
||||
method = "placeFood",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/core/NonNullList;set(ILjava/lang/Object;)Ljava/lang/Object;")
|
||||
)
|
||||
private void wakeUpOnAddItem(Entity user, ItemStack stack, int cookTime, CallbackInfoReturnable<Boolean> cir) {
|
||||
this.wakeUpNow();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "loadAdditional",
|
||||
at = @At(value = "RETURN")
|
||||
)
|
||||
private void wakeUpOnReadNbt(CompoundTag nbt, HolderLookup.Provider registryLookup, CallbackInfo ci) {
|
||||
this.wakeUpNow();
|
||||
}
|
||||
}
|
||||
//import net.gensokyoreimagined.nitori.common.block.entity.SleepingBlockEntity;
|
||||
//import net.gensokyoreimagined.nitori.mixin.world.block_entity_ticking.sleeping.WrappedBlockEntityTickInvokerAccessor;
|
||||
//import net.minecraft.world.entity.Entity;
|
||||
//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.world.level.block.entity.CampfireBlockEntity;
|
||||
//import net.minecraft.world.entity.LivingEntity;
|
||||
//import net.minecraft.world.item.ItemStack;
|
||||
//import net.minecraft.nbt.CompoundTag;
|
||||
//import net.minecraft.core.HolderLookup;
|
||||
//import net.minecraft.core.BlockPos;
|
||||
//import net.minecraft.world.level.block.entity.TickingBlockEntity;
|
||||
//import org.spongepowered.asm.mixin.Mixin;
|
||||
//import org.spongepowered.asm.mixin.injection.At;
|
||||
//import org.spongepowered.asm.mixin.injection.Inject;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
//
|
||||
//@Mixin(CampfireBlockEntity.class)
|
||||
//public class CampfireBlockEntityMixin extends BlockEntity implements SleepingBlockEntity {
|
||||
//
|
||||
// private WrappedBlockEntityTickInvokerAccessor tickWrapper = null;
|
||||
// private TickingBlockEntity sleepingTicker = null;
|
||||
//
|
||||
// public CampfireBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
// super(type, pos, state);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public WrappedBlockEntityTickInvokerAccessor lithium$getTickWrapper() {
|
||||
// return tickWrapper;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void lithium$setTickWrapper(WrappedBlockEntityTickInvokerAccessor tickWrapper) {
|
||||
// this.tickWrapper = tickWrapper;
|
||||
// this.lithium$setSleepingTicker(null);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public TickingBlockEntity lithium$getSleepingTicker() {
|
||||
// return sleepingTicker;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void lithium$setSleepingTicker(TickingBlockEntity sleepingTicker) {
|
||||
// this.sleepingTicker = sleepingTicker;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Inject(
|
||||
// method = "placeFood",
|
||||
// at = @At(value = "INVOKE", target = "Lnet/minecraft/core/NonNullList;set(ILjava/lang/Object;)Ljava/lang/Object;")
|
||||
// )
|
||||
// private void wakeUpOnAddItem(LivingEntity user, ItemStack stack, int cookTime, CallbackInfoReturnable<Boolean> cir) {
|
||||
// this.wakeUpNow();
|
||||
// }
|
||||
//
|
||||
// @Inject(
|
||||
// method = "loadAdditional",
|
||||
// at = @At(value = "RETURN")
|
||||
// )
|
||||
// private void wakeUpOnReadNbt(CompoundTag nbt, HolderLookup.Provider registryLookup, CallbackInfo ci) {
|
||||
// this.wakeUpNow();
|
||||
// }
|
||||
//}
|
||||
@@ -1,40 +1,40 @@
|
||||
package net.gensokyoreimagined.nitori.mixin.world.block_entity_ticking.sleeping.campfire.lit;
|
||||
|
||||
import net.gensokyoreimagined.nitori.common.block.entity.SleepingBlockEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.entity.CampfireBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.event.block.BlockCookEvent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(CampfireBlockEntity.class)
|
||||
public abstract class CampfireBlockEntityMixin extends BlockEntity implements SleepingBlockEntity {
|
||||
|
||||
public CampfireBlockEntityMixin(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.CAMPFIRE, pos, state);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "cookTick",
|
||||
at = @At("RETURN"),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD
|
||||
)
|
||||
private static void trySleepLit(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire, CallbackInfo ci, boolean flag) {
|
||||
if (!flag) {
|
||||
CampfireBlockEntityMixin self = (CampfireBlockEntityMixin) (Object) campfire;
|
||||
self.nitori$startSleeping();
|
||||
}
|
||||
}
|
||||
}
|
||||
//import net.gensokyoreimagined.nitori.common.block.entity.SleepingBlockEntity;
|
||||
//import net.minecraft.core.BlockPos;
|
||||
//import net.minecraft.world.SimpleContainer;
|
||||
//import net.minecraft.world.item.ItemStack;
|
||||
//import net.minecraft.world.level.Level;
|
||||
//import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
//import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
//import net.minecraft.world.level.block.entity.CampfireBlockEntity;
|
||||
//import net.minecraft.world.level.block.state.BlockState;
|
||||
//import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
//import org.bukkit.event.block.BlockCookEvent;
|
||||
//import org.spongepowered.asm.mixin.Mixin;
|
||||
//import org.spongepowered.asm.mixin.injection.At;
|
||||
//import org.spongepowered.asm.mixin.injection.Inject;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
//
|
||||
//import java.util.Optional;
|
||||
//
|
||||
//@Mixin(CampfireBlockEntity.class)
|
||||
//public abstract class CampfireBlockEntityMixin extends BlockEntity implements SleepingBlockEntity {
|
||||
//
|
||||
// public CampfireBlockEntityMixin(BlockPos pos, BlockState state) {
|
||||
// super(BlockEntityType.CAMPFIRE, pos, state);
|
||||
// }
|
||||
//
|
||||
// @Inject(
|
||||
// method = "cookTick",
|
||||
// at = @At("RETURN"),
|
||||
// locals = LocalCapture.CAPTURE_FAILHARD
|
||||
// )
|
||||
// private static void trySleepLit(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire, CallbackInfo ci, boolean flag) {
|
||||
// if (!flag) {
|
||||
// CampfireBlockEntityMixin self = (CampfireBlockEntityMixin) (Object) campfire;
|
||||
// self.nitori$startSleeping();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
package net.gensokyoreimagined.nitori.mixin.world.block_entity_ticking.sleeping.campfire.unlit;
|
||||
|
||||
import net.gensokyoreimagined.nitori.common.block.entity.SleepingBlockEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.entity.CampfireBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
@Mixin(CampfireBlockEntity.class)
|
||||
public abstract class CampfireBlockEntityMixin extends BlockEntity implements SleepingBlockEntity {
|
||||
|
||||
public CampfireBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "cooldownTick",
|
||||
at = @At("RETURN"),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD
|
||||
)
|
||||
private static void trySleepLit(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire, CallbackInfo ci, boolean flag) {
|
||||
if (!flag) {
|
||||
CampfireBlockEntityMixin self = (CampfireBlockEntityMixin) (Object) campfire;
|
||||
self.nitori$startSleeping();
|
||||
}
|
||||
}
|
||||
}
|
||||
//import net.gensokyoreimagined.nitori.common.block.entity.SleepingBlockEntity;
|
||||
//import net.minecraft.core.BlockPos;
|
||||
//import net.minecraft.world.level.Level;
|
||||
//import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
//import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
//import net.minecraft.world.level.block.entity.CampfireBlockEntity;
|
||||
//import net.minecraft.world.level.block.state.BlockState;
|
||||
//import org.spongepowered.asm.mixin.Mixin;
|
||||
//import org.spongepowered.asm.mixin.injection.At;
|
||||
//import org.spongepowered.asm.mixin.injection.Inject;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
//
|
||||
//@Mixin(CampfireBlockEntity.class)
|
||||
//public abstract class CampfireBlockEntityMixin extends BlockEntity implements SleepingBlockEntity {
|
||||
//
|
||||
// public CampfireBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
// super(type, pos, state);
|
||||
// }
|
||||
//
|
||||
// @Inject(
|
||||
// method = "cooldownTick",
|
||||
// at = @At("RETURN"),
|
||||
// locals = LocalCapture.CAPTURE_FAILHARD
|
||||
// )
|
||||
// private static void trySleepLit(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire, CallbackInfo ci, boolean flag) {
|
||||
// if (!flag) {
|
||||
// CampfireBlockEntityMixin self = (CampfireBlockEntityMixin) (Object) campfire;
|
||||
// self.nitori$startSleeping();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -18,147 +18,147 @@ package net.gensokyoreimagined.nitori.tracker;
|
||||
* Ported from Petal, derived from Airplane
|
||||
*/
|
||||
|
||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet; //io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices; //io.papermc.paper.world.ChunkEntitySlices;
|
||||
import net.gensokyoreimagined.nitori.access.IMixinChunkEntitySlicesAccess;
|
||||
import net.gensokyoreimagined.nitori.access.IMixinChunkMap_TrackedEntityAccess;
|
||||
import net.gensokyoreimagined.nitori.access.IMixinIteratorSafeOrderedReferenceSetAccess;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class MultithreadedTracker {
|
||||
|
||||
private enum TrackerStage {
|
||||
UPDATE_PLAYERS,
|
||||
SEND_CHANGES
|
||||
}
|
||||
|
||||
private static final int parallelism = Math.max(4, Runtime.getRuntime().availableProcessors());
|
||||
private static final Executor trackerExecutor = Executors.newFixedThreadPool(parallelism, new ThreadFactoryBuilder()
|
||||
.setNameFormat("mirai-tracker-%d")
|
||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||
.build());
|
||||
|
||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> entityTickingChunks;
|
||||
private final AtomicInteger taskIndex = new AtomicInteger();
|
||||
|
||||
private final ConcurrentLinkedQueue<Runnable> mainThreadTasks;
|
||||
private final AtomicInteger finishedTasks = new AtomicInteger();
|
||||
|
||||
public MultithreadedTracker(ReferenceList<ServerChunkCache.ChunkAndHolder> entityTickingChunks, ConcurrentLinkedQueue<Runnable> mainThreadTasks) {
|
||||
this.entityTickingChunks = entityTickingChunks;
|
||||
this.mainThreadTasks = mainThreadTasks;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
this.taskIndex.set(0);
|
||||
this.finishedTasks.set(0);
|
||||
|
||||
for (int i = 0; i < parallelism; i++) {
|
||||
trackerExecutor.execute(this::runUpdatePlayers);
|
||||
}
|
||||
|
||||
// start with updating players
|
||||
while (this.taskIndex.get() < this.entityTickingChunks.size()) {
|
||||
this.runMainThreadTasks();
|
||||
this.handleChunkUpdates(5); // assist
|
||||
}
|
||||
|
||||
// then send changes
|
||||
while (this.finishedTasks.get() != parallelism) {
|
||||
this.runMainThreadTasks();
|
||||
}
|
||||
|
||||
this.runMainThreadTasks(); // finish any remaining tasks
|
||||
|
||||
for (ServerChunkCache.ChunkAndHolder chunkAndHolder : this.entityTickingChunks) {
|
||||
LevelChunk chunk = chunkAndHolder.chunk();
|
||||
|
||||
if (chunk != null) {
|
||||
this.updateChunkEntities(chunk, TrackerStage.SEND_CHANGES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void runMainThreadTasks() {
|
||||
try {
|
||||
Runnable task;
|
||||
while ((task = this.mainThreadTasks.poll()) != null) {
|
||||
task.run();
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
MinecraftServer.LOGGER.warn("Tasks failed while ticking track queue", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private void runUpdatePlayers() {
|
||||
try {
|
||||
while (handleChunkUpdates(10));
|
||||
} finally {
|
||||
this.finishedTasks.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleChunkUpdates(int tasks) {
|
||||
int index;
|
||||
while ((index = this.taskIndex.getAndAdd(tasks)) < this.entityTickingChunks.size()) {
|
||||
for (int i = index; i < index + tasks && i < this.entityTickingChunks.size(); i++) {
|
||||
LevelChunk chunk = this.entityTickingChunks.getChecked(i).chunk();
|
||||
if (chunk != null) {
|
||||
try {
|
||||
this.updateChunkEntities(chunk, TrackerStage.UPDATE_PLAYERS);
|
||||
} catch (Throwable throwable) {
|
||||
MinecraftServer.LOGGER.warn("Ticking tracker failed", throwable);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateChunkEntities(LevelChunk chunk, TrackerStage trackerStage) {
|
||||
final ChunkEntitySlices entitySlices = chunk.level.moonrise$getEntityLookup().getChunk(chunk.locX, chunk.locZ);
|
||||
if (entitySlices == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Entity[] rawEntities = ((IMixinChunkEntitySlicesAccess) (Object) entitySlices).getEntities().getRawData();
|
||||
final ChunkMap chunkMap = chunk.level.chunkSource.chunkMap;
|
||||
|
||||
for (int i = 0; i < rawEntities.length; i++) {
|
||||
Entity entity = rawEntities[i];
|
||||
if (entity != null) {
|
||||
ChunkMap.TrackedEntity entityTracker = chunkMap.entityMap.get(entity.getId());
|
||||
if (entityTracker != null) {
|
||||
if (trackerStage == TrackerStage.SEND_CHANGES) {
|
||||
entityTracker.serverEntity.sendChanges();
|
||||
} else if (trackerStage == TrackerStage.UPDATE_PLAYERS) {
|
||||
ReferenceList<ServerPlayer> nearbyPlayers = chunkMap.level.moonrise$getNearbyPlayers().getChunk(entity.chunkPosition()).getPlayers(NearbyPlayers.NearbyMapType.VIEW_DISTANCE);
|
||||
List<ServerPlayer> nearbyPlayersList = new ArrayList<ServerPlayer>(nearbyPlayers.size()); // intentionally typed as List for requirement clarity
|
||||
nearbyPlayers.forEach(nearbyPlayersList::add);
|
||||
((IMixinChunkMap_TrackedEntityAccess) (Object) entityTracker).callUpdatePlayers(nearbyPlayersList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
//import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||
//import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
//import ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet; //io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet;
|
||||
//import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices; //io.papermc.paper.world.ChunkEntitySlices;
|
||||
//import net.gensokyoreimagined.nitori.access.IMixinChunkEntitySlicesAccess;
|
||||
//import net.gensokyoreimagined.nitori.access.IMixinChunkMap_TrackedEntityAccess;
|
||||
//import net.gensokyoreimagined.nitori.access.IMixinIteratorSafeOrderedReferenceSetAccess;
|
||||
//import net.minecraft.server.MinecraftServer;
|
||||
//import net.minecraft.server.level.ChunkMap;
|
||||
//import net.minecraft.server.level.ServerChunkCache;
|
||||
//import net.minecraft.server.level.ServerPlayer;
|
||||
//import net.minecraft.world.entity.Entity;
|
||||
//import net.minecraft.world.level.chunk.LevelChunk;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.List;
|
||||
//import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
//import java.util.concurrent.Executor;
|
||||
//import java.util.concurrent.Executors;
|
||||
//import java.util.concurrent.atomic.AtomicInteger;
|
||||
//
|
||||
//public class MultithreadedTracker {
|
||||
//
|
||||
// private enum TrackerStage {
|
||||
// UPDATE_PLAYERS,
|
||||
// SEND_CHANGES
|
||||
// }
|
||||
//
|
||||
// private static final int parallelism = Math.max(4, Runtime.getRuntime().availableProcessors());
|
||||
// private static final Executor trackerExecutor = Executors.newFixedThreadPool(parallelism, new ThreadFactoryBuilder()
|
||||
// .setNameFormat("mirai-tracker-%d")
|
||||
// .setPriority(Thread.NORM_PRIORITY - 2)
|
||||
// .build());
|
||||
//
|
||||
// private final ReferenceList<ServerChunkCache.ChunkAndHolder> entityTickingChunks;
|
||||
// private final AtomicInteger taskIndex = new AtomicInteger();
|
||||
//
|
||||
// private final ConcurrentLinkedQueue<Runnable> mainThreadTasks;
|
||||
// private final AtomicInteger finishedTasks = new AtomicInteger();
|
||||
//
|
||||
// public MultithreadedTracker(ReferenceList<ServerChunkCache.ChunkAndHolder> entityTickingChunks, ConcurrentLinkedQueue<Runnable> mainThreadTasks) {
|
||||
// this.entityTickingChunks = entityTickingChunks;
|
||||
// this.mainThreadTasks = mainThreadTasks;
|
||||
// }
|
||||
//
|
||||
// public void tick() {
|
||||
// this.taskIndex.set(0);
|
||||
// this.finishedTasks.set(0);
|
||||
//
|
||||
// for (int i = 0; i < parallelism; i++) {
|
||||
// trackerExecutor.execute(this::runUpdatePlayers);
|
||||
// }
|
||||
//
|
||||
// // start with updating players
|
||||
// while (this.taskIndex.get() < this.entityTickingChunks.size()) {
|
||||
// this.runMainThreadTasks();
|
||||
// this.handleChunkUpdates(5); // assist
|
||||
// }
|
||||
//
|
||||
// // then send changes
|
||||
// while (this.finishedTasks.get() != parallelism) {
|
||||
// this.runMainThreadTasks();
|
||||
// }
|
||||
//
|
||||
// this.runMainThreadTasks(); // finish any remaining tasks
|
||||
//
|
||||
// for (ServerChunkCache.ChunkAndHolder chunkAndHolder : this.entityTickingChunks) {
|
||||
// LevelChunk chunk = chunkAndHolder.chunk();
|
||||
//
|
||||
// if (chunk != null) {
|
||||
// this.updateChunkEntities(chunk, TrackerStage.SEND_CHANGES);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void runMainThreadTasks() {
|
||||
// try {
|
||||
// Runnable task;
|
||||
// while ((task = this.mainThreadTasks.poll()) != null) {
|
||||
// task.run();
|
||||
// }
|
||||
// } catch (Throwable throwable) {
|
||||
// MinecraftServer.LOGGER.warn("Tasks failed while ticking track queue", throwable);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void runUpdatePlayers() {
|
||||
// try {
|
||||
// while (handleChunkUpdates(10));
|
||||
// } finally {
|
||||
// this.finishedTasks.incrementAndGet();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private boolean handleChunkUpdates(int tasks) {
|
||||
// int index;
|
||||
// while ((index = this.taskIndex.getAndAdd(tasks)) < this.entityTickingChunks.size()) {
|
||||
// for (int i = index; i < index + tasks && i < this.entityTickingChunks.size(); i++) {
|
||||
// LevelChunk chunk = this.entityTickingChunks.getChecked(i).chunk();
|
||||
// if (chunk != null) {
|
||||
// try {
|
||||
// this.updateChunkEntities(chunk, TrackerStage.UPDATE_PLAYERS);
|
||||
// } catch (Throwable throwable) {
|
||||
// MinecraftServer.LOGGER.warn("Ticking tracker failed", throwable);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// private void updateChunkEntities(LevelChunk chunk, TrackerStage trackerStage) {
|
||||
// final ChunkEntitySlices entitySlices = chunk.level.moonrise$getEntityLookup().getChunk(chunk.locX, chunk.locZ);
|
||||
// if (entitySlices == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final Entity[] rawEntities = ((IMixinChunkEntitySlicesAccess) (Object) entitySlices).getEntities().getRawData();
|
||||
// final ChunkMap chunkMap = chunk.level.chunkSource.chunkMap;
|
||||
//
|
||||
// for (int i = 0; i < rawEntities.length; i++) {
|
||||
// Entity entity = rawEntities[i];
|
||||
// if (entity != null) {
|
||||
// ChunkMap.TrackedEntity entityTracker = chunkMap.entityMap.get(entity.getId());
|
||||
// if (entityTracker != null) {
|
||||
// if (trackerStage == TrackerStage.SEND_CHANGES) {
|
||||
// entityTracker.serverEntity.sendChanges();
|
||||
// } else if (trackerStage == TrackerStage.UPDATE_PLAYERS) {
|
||||
// ReferenceList<ServerPlayer> nearbyPlayers = chunkMap.level.moonrise$getNearbyPlayers().getChunk(entity.chunkPosition()).getPlayers(NearbyPlayers.NearbyMapType.VIEW_DISTANCE);
|
||||
// List<ServerPlayer> nearbyPlayersList = new ArrayList<ServerPlayer>(nearbyPlayers.size()); // intentionally typed as List for requirement clarity
|
||||
// nearbyPlayers.forEach(nearbyPlayersList::add);
|
||||
// ((IMixinChunkMap_TrackedEntityAccess) (Object) entityTracker).callUpdatePlayers(nearbyPlayersList);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "Nitori",
|
||||
"version": "1.4-SNAPSHOT",
|
||||
"version": "1.5-SNAPSHOT",
|
||||
"mixins": [
|
||||
"mixins.core.json"
|
||||
]
|
||||
|
||||
@@ -6,17 +6,16 @@
|
||||
"target": "@env(DEFAULT)",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"server": [
|
||||
"ChunkMapMixin",
|
||||
"ChunkMapMixin$TrackedEntity",
|
||||
"MixinBlock",
|
||||
"MixinBlockPos",
|
||||
"MixinChunkEntitySlices",
|
||||
"MixinCraftPlayer",
|
||||
"MixinEntity",
|
||||
"MixinEntitySectionStorage",
|
||||
"collections.gamerules.MixinGameRules",
|
||||
"MixinGameRules",
|
||||
"MixinIteratorSafeOrderedReferenceSet",
|
||||
"MixinLevelStorageAccess",
|
||||
"entity.micro_opts.MixinMob",
|
||||
"MixinMob",
|
||||
"MixinNoiseBasedChunkGenerator",
|
||||
"MixinPlayer",
|
||||
"MixinPlayerList",
|
||||
@@ -43,7 +42,6 @@
|
||||
"alloc.composter.ComposterMixin$ComposterBlockDummyInventoryMixin",
|
||||
"alloc.composter.ComposterMixin$ComposterBlockFullComposterInventoryMixin",
|
||||
"alloc.biome_temprature_leak.Biome_threadLocalMixin",
|
||||
"alloc.MixinIdentifier",
|
||||
"cached_hashcode.BlockNeighborGroupMixin",
|
||||
"collections.attributes.AttributeContainerMixin",
|
||||
"collections.block_entity_tickers.WorldChunkMixin",
|
||||
|
||||
Reference in New Issue
Block a user